-- @version 0.94
-- @author lbx
-- @changelog

--[[
   * ReaScript Name: LBX Stripper
   * Lua script for Cockos REAPER
   * Author: Leon Bradley (LBX)
   * Author URI:
   * Licence: GPL v3
  ]]

  --------------------------------------------
  --------------------------------------------
  DBG_mode = false

  local lvar = {}
  local xPnl = {}
  local cbi = {}

  lvar.offline_paramcnt = 3
  --wet and bypass offsets from last param
  lvar.pn_byp = 3
  lvar.pn_wet = 2
  lvar.pn_delta = 1
  
  lvar.scriptver = '0.94.0204' --Script Version

  lvar.screensize = {x = 1920, y = 1080}

  lvar.surfacefade_active = true
  lvar.surfacefadetime = 0.08
  
  lvar.sk2data_slots = nil
  lvar.sk2data_assign = nil
  
  lvar.sk2overlay = {listoffs = 0, slots = 64, slot = {}, assign = {{}}}
  lvar.sk2overlay_active = 0
  lvar.sk2overlay_globalassgrp = 1
  lvar.sk2overlay_solo = 0
  lvar.sk2overlay_hud = 1
  lvar.sk2overlay_hudt = 0
  
  lvar.anchor = {}
  lvar.anchor['bottom_centre'] = 1
  lvar.anchor['top_centre'] = 2
  
  lvar.paramhud = {}
  lvar.paramhud_idx = {}
  
  lvar.superfine = 1/4 --TEST - this will be implemented in control params
  
  lvar.show_slotnameoninactivesk2ctls = 0
  
  lvar.pastespecial_sel = 1
  lvar.pastespecial = {}
  lvar.pastespecial[1] = {'Paste All Attributes|','ctltype','knob_select','ctl_info','scale','w','wsc','hsc','show_paramname','show_paramval',
                          'textcol','textoff','textoffval','textoffx','textoffvalx','textsize','textsizev','textcolv','font','maxdp','horiz',
                          'scalemode','framemode','knobsens','bright','bypassbg_c','bypassbg_n','bypassbg_v','clickthrough','limittext',
                          'wwtext','textflags','animatetime','animateshape','adjust_active','adjust'}
  lvar.pastespecial[2] = {'Paste Colour Overlay','adjust_active','adjust'}
  lvar.pastespecial[3] = {'Paste Colour Overlay, Image|','adjust_active','adjust','knob_select','ctl_info','scale','w','wsc','hsc'}
  lvar.pastespecial[4] = {'Paste Font (All Attributes)','textcol','textoff','textoffval','textoffx','textoffvalx','textsize','textsizev','textcolv','font','limittext',
                          'wwtext','textflags'}
  lvar.pastespecial[5] = {'Paste Font Type','font'}
  lvar.pastespecial[6] = {'Paste Font (Type, Size, Colour)','textcol','textsize','textsizev','textcolv','font'}
  lvar.pastespecial[7] = {'Paste Font (Type, Size, Colour, Position Offsets)|','textcol','textoff','textoffval','textoffx','textoffvalx','textsize','textsizev','textcolv','font'}
  lvar.pastespecial[8] = {'Paste Label (Limits, Word Wrap, Justification)|','limittext','wwtext','textflags'}
  lvar.pastespecial[9] = {'Paste Image Scale|','scale'}
  lvar.pastespecial[10] = {'Paste Min/Max|','minov','maxov'}
                          
  local ctls_dirty = {idx = {}, update = {}}

  local tab_xtouch_color_menu = {'Black','Red','Green','Yellow','Blue','Magenta','Cyan','White','Invert Top Line','Invert Bottom Line'}
  local tab_xtouch_colors = {}
  tab_xtouch_colors[0] = {v = 0, c = '0 0 0', tc = '205 205 205', r = 20, g = 20, b = 20}
  tab_xtouch_colors[1] = {v = 1, c = '255 0 0', r = 255, g = 0, b = 0}
  tab_xtouch_colors[2] = {v = 2, c = '0 255 0', r = 0, g = 255, b = 0}
  tab_xtouch_colors[3] = {v = 3, c = '255 216 0', r = 255, g = 216, b = 0}
  tab_xtouch_colors[4] = {v = 4, c = '0 38 255', r = 0, g = 38, b = 255}
  tab_xtouch_colors[5] = {v = 5, c = '255 0 220', r = 255, g = 0, b = 220}
  tab_xtouch_colors[6] = {v = 6, c = '0 255 255', r = 0, g = 255, b = 255}
  tab_xtouch_colors[7] = {v = 7, c = '255 255 255', r = 255, g = 255, b = 255}
  
  lvar.sliderzoom = true
  lvar.extidentifiers = {}
  lvar.externalcontrol = true
  
  lvar.trackstrips = {}
  
  lvar.delayfunction = {}
  lvar.maxdim = 4096
  
  lvar.screenset = {}
  
  lvar.Mac_revcol = false
  lvar.sortcontrols = false
  
  lvar.mousewheel_div = 120 --default 120 - change to 30 or ? for weird Mac mice!

  lvar.mode0swipetime = 0.15

  lvar.savesettingstofile = true
  lvar.forcestrippluginguisclosed = true

  lvar.dm_fixtrack = nil
  lvar.dm_trackslocked = true
  lvar.dm_shiftstripoffset = true
  lvar.dm_autoupdatesnaps = true
  lvar.dm_autonamesnaps = true
  lvar.dm_checkdupsnaps = true
  
  lvar.dm_refreshtrack_active = false
  lvar.dm_refreshtrack = {}

  lvar.spos = {}
  lvar.mac_coord_hack = true
  
  lvar.dm_addstrip_autoswipe = true
  
  lvar.popout_autoarrange = false
  lvar.autoarrange_activefx = false
  lvar.popout_autoarrange_hideswitchers = false
  lvar.popout_autoarrange_xgap = 0
  lvar.popout_autoarrange_ygap = 0
  
  lvar.analyzer = {}
  lvar.analyzer.type = 1
  lvar.analyzer.active = false
  lvar.analyzer.title = {'- LBXAnalyzer -'}
  lvar.analyzer.titleplug = {'JS: gfxanalyzer-lbxmod','JS: gfxspectrograph','JS: gfxscope'}
  lvar.analyzer.titleplugdesc = {'Frequency','Spectrograph','Oscilloscope'}
  lvar.analyzer.mod = {'gfxanalyzer-lbxmod','gfxspectrograph','gfxscope'}
  --lvar.analyzer.mod2 = 'gfxanalyzer'
  lvar.analyzer.track = nil
  lvar.analyzer.trackguid = nil
  lvar.analyzer.anwinplug = {}
  lvar.analyzer.anwin = {}
  lvar.analyzer.pos = 0
  lvar.analyzer.showcontrols = true
  lvar.analyzer.controls = {}
  lvar.analyzer.controls[1] = {}
  lvar.analyzer.controls[1][1] = {param = 0, type = 1}
  lvar.analyzer.controls[1][2] = {param = 4, type = 1}
  lvar.analyzer.controls[1][3] = {param = 5, type = 1}
  lvar.analyzer.controls[1][4] = {param = 1, type = 1}
  lvar.analyzer.controls[1][5] = {param = 9, type = 1}
  lvar.analyzer.controls[1][6] = {param = 8, type = 1, sens = 500}
  lvar.analyzer.controls[1][7] = {param = 7, type = 1, sens = 500}
  lvar.analyzer.controls[1][8] = {param = 11, type = 1}
  lvar.analyzer.controls[1][9] = {param = 10, type = 2}
  lvar.analyzer.controls[1][10] = {param = 3, type = 1}
  lvar.analyzer.controls[1][11] = {param = 6, type = 1}
  lvar.analyzer.controls[1][12] = {param = 2, type = 2}
  lvar.analyzer.controls[1][13] = {param = 22, type = 1}
  lvar.analyzer.controls[1][14] = {param = 24, type = 1}
  --lvar.analyzer.controls[1][15] = {param = 25, type = 1}
  lvar.analyzer.controls[2] = {}
  lvar.analyzer.controls[2][1] = {param = 0, type = 2}
  lvar.analyzer.controls[2][2] = {param = 1, type = 1}
  lvar.analyzer.controls[2][3] = {param = 2, type = 1}
  lvar.analyzer.controls[2][4] = {param = 3, type = 1}
  lvar.analyzer.controls[2][5] = {param = 4, type = 1}
  lvar.analyzer.controls[2][6] = {param = 5, type = 1}
  lvar.analyzer.controls[3] = {}
  lvar.analyzer.controls[3][1] = {param = 0, type = 1}
  lvar.analyzer.controls[3][2] = {param = 1, type = 1, sens = 1000}
  lvar.analyzer.controls[3][3] = {param = 2, type = 1}
  lvar.analyzer.script = nil --'_RS0a99016f2b61ee8b6905f103a988d511e1e0cb19'

  lvar.trmix_panelsz = 500
  --lvar.trmix_panelsz2 = 500

  lvar.freq = {}
  lvar.freqcnt = 5
  lvar.freqsolo = nil
  lvar.freq[0] = {col = '255 255 0',
                  track = '',
                  active = false}
  lvar.freq[1] = {col = '255 0 255',
                  track = '',
                  active = false}
  lvar.freq[2] = {col = '128 128 255',
                  track = '',
                  active = false}
  lvar.freq[3] = {col = '255 0 0',
                  track = '',
                  active = false}
  lvar.freq[4] = {col = '0 255 0',
                  track = '',
                  active = false}
  lvar.freq[5] = {col = '0 255 255',
                  track = '',
                  active = false}

  lvar.highbox = {}
  lvar.btnflashtime = 0.3

  lvar.mmtouch = false

  lvar.bgcentred = true
  lvar.checkdatatables_active = true
  lvar.dm_autorefresh = true
  lvar.dm_fastmode = true
  lvar.dm_singlepopup = true
  lvar.dm_saveenabled = true
  lvar.dm_trackbtns = {}
  lvar.trbtns_autoidx = 99999
  lvar.dm_tbidx = lvar.trbtns_autoidx
  lvar.trbtns_size = 80
  lvar.trmixbtns_size = 80
  lvar.trbtns_show = true
  lvar.trbtns_offs = 0
  lvar.trbtns_meters = true
  lvar.trbtns_pkcolor = '0 128 255'
  lvar.trbtns_solocolor = '0 255 0'
  lvar.trbtns_mutecolor = '255 0 0'
  lvar.trbtns_freezecolor = '0 196 255'
  lvar.dm_padx = 50
  lvar.dm_pady = 20
  lvar.trmix_show = false
  lvar.trmix_h = 270
  lvar.trmix_minh = 270
  lvar.trmix_seth = 270
  lvar.trmix_vscale = 11
  lvar.trmix_sndpnl_show = 0
  lvar.trmix_sndpnl_offs = 0
  lvar.trmix_pnl_tbar = 10
  lvar.trmix_pnl_tbar_alpha = 0.05
  lvar.trmix_sndpnl_dirty = {}
  lvar.trmix_animateshow = true

  lvar.dm_showtrackname = true
  lvar.dm_btnpnlidx = 1
  lvar.dm_btnpnl2idx = 2
  lvar.dm_btnpnl = {}
  lvar.dm_btnpnl[lvar.dm_btnpnlidx] = {}
  lvar.dm_btnpnl_page = 0
  lvar.phtime = 1
  lvar.btnpnl_update = {}

  lvar.enablelargegui = true
  
  lvar.trackfxtype_input = 0x1000000
  lvar.tfx_type = 0
  
  lvar.dm_maxvistracks = 99
  lvar.dm_maxvissends = 8

  lvar.sb_folbtn_offs = 0
  lvar.sb_folbtn_show = true
  lvar.reloadsbimages = true

  lvar.dropenabled_timer = -1

  lvar.mm_fadepop = 0.2
  lvar.mm_fadepopamt = 0.2

  lvar.maxpage = 4

  lvar.shadowmax = 20
  lvar.shadowmax_p = 20
  lvar.enablegfxshadows = true
  lvar.shadow_alpha = 0.3
  lvar.shadow_offsx = 8
  lvar.shadow_offsy = 8
  lvar.shadow_feather = 0
  lvar.shadows = {}

  lvar.template_strips_offs = 0

  lvar.fxpos = {l = 0, t = 0, w = 1920, h = 1080}

  lvar.extswitch_format = {}

  lvar.TSM_active = true
  lvar.TSM_coord = {l = 0, t = 0, r = 400, b = 400}
  lvar.TSM_time = 0.3
  lvar.TSM_Timer = 0

  lvar.mmgap = 4
  lvar.mmpadgap = 20

  lvar.zoomv = 3
  --lvar.zoomtab = {0.25,0.5,0.75,1,1.25,1.5,1.75,2,2.25,2.5,2.75,3,3.5,4}
  lvar.zoomtab = {0.25,0.5,1,2,3,4}
  lvar.zoom = lvar.zoomtab[lvar.zoomv]
  lvar.mixmode_fastdraw = 1
  lvar.mixswids = {}

  lvar.bgmatchestrackcolour = 0

  lvar.hidecursordrag = false

  lvar.ctlupdate_rr = nil
  lvar.ctlupdate_pos = 1
  lvar.snapstages = 32
  lvar.swdropsz = 16
  lvar.deletestripwhentrackdeleted = true

  --local redraw_ctlbitmapmix
  --local redraw_ctlbitmap

  lvar.gfxpages = 0
  lvar.gfxpagesmax = 9

  lvar.showpop = true
  lvar.showpoponly = false

  lvar.anitime = 0.15
  lvar.stripctlbox = {}

  lvar.readpeaks = {}

  lvar.noteletters_tab = {'C','C#','D','D#','E','F','F#','G','G#','A','A#','B'}

  lvar.fxmulti_table = {'Wet On','Wet Off','Bypass','Offline'}
  lvar.submode_table = {'FX PARAMS','GRAPHICS','STRIPS'}
  lvar.submode_table2 = {'STRIP','FX','TRACK','GFX'}
  lvar.mode0_submode_table = {'LIVE MODE','FADERS','MODULATORS'}
  lvar.xxymode_table = {'SNAPSHOTS','PATHS'}
  lvar.ctltype_table = {'KNOB/SLIDER','BUTTON','BUTTON INV','CYCLE BUTTON','METER','MEM BUTTON','MOMENT BTN','MOMENT INV','FLASH BUTTON','FLASH INV','KNOB/SLIDER REV','MAGNETIC KNOB'}
  lvar.ctltype_buttons = {[2] = true,[3] = true}
  lvar.trctltype_table = {'Track Controls','Track Sends','Track Meters','Other Controls'}
  lvar.special_table = {}
  lvar.otherctl_table = {'Action Trigger','Macro Control','EQ Engine','Strip Switcher','ReaControlMidi Switch','Midi/OSC Control','Take Switcher','RS5K Control','Param Update Ctl','Param Value Ctl (Global)',
                         'Info Control','State Control (Numeric)','State Control (String)','Navigate Control','SK2 Control'}
  lvar.scalemode_preset_table = {'','NORMAL','REAPER VOL'}
  lvar.lfomode_table = {'NORMAL MODE','TAKESWITCH MODE','RS5K MODE'}
  lvar.scalemode_table = {1/8,1/7,1/6,1/5,1/4,1/3,1/2,1,2,3,4,5,6,7,8}
  lvar.scalemode_dtable = {'1/8','1/7','1/6','1/5','1/4','1/3','1/2','1','2','3','4','5','6','7','8'}
  lvar.macroscale_table = {'Linear','Slow','Fast','Smooth','Slow 2 (Cubic)','Fast 2 (Cubic)', 'Smooth 2 (Cubic)', 'Slow 3', 'Fast 3', 'Smooth 3', 'Instant'}
  lvar.macroscale_sm_table = {'Linear','Slow','Fast','Smooth','Slow2','Fast2', 'Smooth2', 'Slow3', 'Fast3', 'Smooth3','Instant'}
  lvar.eqcontrol_colours = {'160 0 0','0 160 0','0 0 160','160 160 0','0 160 160','160 0 160','255 165 0','160 160 160','196 80 80','80 196 80','80 80 196','196 196 80','196 80 196'
                       ,'255 64 64','64 0 255','80 160 0','102 0 51','255 255 255','255 255 255','255 255 255'}

  lvar.midimsgtype_table = {'80 - Note Off','90 - Note On','A0 - Key Pressure','B0 - Control Change','C0 - Program Change','D0 - Channel Pressure','E0 - Pitch Bend'}
  lvar.midimsgval_table = {'0x8','0x9','0xA','0xB','0xC','0xD','0xE'}

  lvar.sync_table = {"Off","1/64t","1/64","1/64d","1/32t","1/32","1/32d","1/16t","1/16","1/16d","1/8t","1/8","1/8d","1/4t","1/4","1/4d","1/2t","1/2","1/2d",
                "1","2","3","4","5","6","7","8","12","16","20","24","28","32","48","64","96","128"}
  lvar.sync_mult_table = {0,1/64*2/3,1/64,1/64*1.5,1/32*2/3,1/32,1/32*1.5,1/16*2/3,1/16,1/16*1.5,1/8*2/3,1/8,1/8*1.5,1/4*2/3,1/4,1/4*1.5,1/2*2/3,1/2,1/2*1.5,1,2,3,4,5,6,7,8,12,16,20,24,28,32,48,64,96,128}

  lvar.divmult_table = {1,2,3,4,5,6,7,8,16,32,64,128}

  lvar.focus_table = {'Off','Arrange','MIDI Editor','Custom Window'}
  lvar.ctlfile_type_table = {'Knob','Slider','Button','Meter','Misc','Slider2','Slider2H','Slider3'}
  lvar.undotypeflag_table = {delete = 1}
  lvar.framemode_table = {'NORMAL','CIRC'}
  lvar.snapsubsets_table = {'PAGE'}
  lvar.gaugetype_table = {'ARC','LINEAR VERT', 'LINEAR HORIZ'}
  lvar.gfxstretch_table = {'normal','fix edge'}

  lvar.linkgrp_table = {'Randomize X', 'Randomize X on', 'Randomize X off', 'Linked'}
  lvar.ctlbrowserbutt_table = {'ALL','KNOBS','SLIDERS','SLIDERS X','BUTTONS','METERS','MISC'}
  lvar.ctlbrowserbutt_transtable = {1,2,3,5,6,7,4}

  lvar.settingspages = {'General / Misc','Performance','Saving','Appearance','Advanced'}
  lvar.settingspage = 1
  lvar.settingsy = 60
  lvar.lbxutil_chunk = 'BYPASS 0 0 0\n<JS LBX_TrackUtility ""\n0.000000 0.000000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n>\nFLOATPOS 0 0 0 0\nFXID {800E025A-6418-48A4-B72E-71E93B970664}\nWAK 0'
  lvar.lbxinsfx_chunk = 'BYPASS 1 0 0\n<JS LBX/LBX-Insert.jsfx "INSERT"\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n>\nFLOATPOS 0 0 0 0\nFXID {E1940877-07BA-45CA-B2B4-21F039C6CD6B}\nWAK 0'
  lvar.lbxdummyfx_chunk = 'BYPASS 1 1 0\n<JS LBX/LBX-Dummy.jsfx "INSERT"\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n>\nFLOATPOS 0 0 0 0\nFXID {E1940877-07BA-45CA-B2B4-21F039C6CD6B}\nWAK 0'
  lvar.infoctl_table = {'Track Name','FX Slot'}
  lvar.gridalpha = 0.8
  lvar.gridcolor = '0 0 0'
  lvar.gridstyle = 1

  lvar.showtakeover = true
  lvar.disabletakeover_ctl = -1
  lvar.mousefadermode = 0
  lvar.gfxpreview = true
  lvar.ctlpreview = true

  lvar.striploadoverride = nil
  lvar.slotoffset = {}

  lvar.sliderxy = false

  lvar.scrollbar_hl = '192 192 0'
  lvar.ctlbrowserfav_select = 1
  lvar.ctlbrowserfavs = {}
  lvar.ctlbrowserfavs_max = 512
  lvar.ctlbrowser_offs = 0
  lvar.ctlfiles_idx = {}
  lvar.gfxfiles_idx = {}

  lvar.trctltypeidx_table = {tr_ctls = 1,
                        tr_sends = 2,
                        tr_rcvs = 3,
                        tr_hwouts = 4
                       }

  lvar.mutate_settings = {dir = 0,
                     range_min = 0,
                     range_max = 100,
                     mutate = true,
                     mutate_min = 0,
                     mutate_max = 5,
                    }

  --Floating Window Objects
  --160  = Snapshots
  --1100 = Mods
  --1120 = Mutate
  --1130 = Random Adv
  --1300 = Sample Manager
  --1350 = Strip Browser

  lvar.stripbrowser = {page = 0, favs = true, dockpos = 1, showlabel = true, type2 = false, fullscreen = false}
  lvar.sbmin = 80

  lvar.livemode = 0
  lvar.glivemode = 0

  lvar.mixmodedir = 0
  lvar.mixmodealign = 0
  lvar.mmov_vsize = 60
  lvar.mmov_show = true
  lvar.mmov_pad = 4
  lvar.mmov_pos = 0
  --lvar.mmov_offs = math.floor(lvar.mmov_vsize/2)
  lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)
  lvar.mmov_tint = 0.2
  lvar.mmov_bgimgon = false

  lvar.maxsamples = 2048
  lvar.followsample = true

  lvar.addstrip_keepseparateids = false

 --GMEM FADERBOX4
    
  lvar.gm_fb = {}
  
  lvar.gm_fb.fader_cnt = 9999 --;
  lvar.gm_fb.fader_val = 0 --;
  lvar.gm_fb.fader_val2 = 1024 --;
  lvar.gm_fb.fader_change = 2048 --;
  lvar.gm_fb.fader_relative = 3072 --;
  lvar.gm_fb.fader_input = 4096
  
  lvar.gm_fb.ftouch_in_cc = 200000 --; //16384
  lvar.gm_fb.ftouch_in_note = 216384 --; //16384
  lvar.gm_fb.ftouch_on = 233000 --; //1024
  lvar.gm_fb.ftouch_off = 235000 --; //1024
  lvar.gm_fb.fadertouch = 237000 --; //1024
  lvar.gm_fb.faderfb = 239000 --; //1024
  
  lvar.gm_fb.fset = 241000 --; //1024
  lvar.gm_fb.fset_trigger51 = 241025
  lvar.gm_fb.fbuttype = 243000 --; //1024
  lvar.gm_fb.fbutstates = 245000 --; //1024
  
  lvar.gm_fb.faderled_on = 255000 --; //1024
  lvar.gm_fb.bstate = 257000 --; //1024
  lvar.gm_fb.ignorebstate = 256999 --; //1
  
  lvar.gm_fb.fbutstates_array = 3000000 --; //32*1024 = 32768
  lvar.gm_fb.fbutstates_array_ext = 3040000 --; //32*1024 = 32768
  lvar.gm_fb.bsarraytransfer = 3080000 --32
  lvar.gm_fb.bsarraytransferext = 3080032 --32
  lvar.gm_fb.bsarraytransfersscolor = 3080064 --32
  
  lvar.butstates_mult = 32 
  
  lvar.gm_fb.fbuttype2 = 247000 --; //1024
  lvar.gm_fb.fencoderres = 249000 --; //1024
  
  lvar.gm_fb.directin_cc = 300000 --; //16384 
  lvar.gm_fb.directin_pitch = 316384 --; //16384 
  lvar.gm_fb.directin_note = 332768 --; //16384 
  
  lvar.gm_fb.faderstate = 10000 --; //1024
  lvar.gm_fb.fflash_cnt = 11024 --1
  lvar.gm_fb.fflash = 11025 --1024
  lvar.gm_fb.fflash_data = 13000 --   0=type 1=ontime 2=offtime 3=duration
  lvar.gm_fb.faderval_lock = 14000
  
  lvar.gm_cc = {}
  
  lvar.gm_cc.fdata_in_cc = 1000000 --; //size 16384
  lvar.gm_cc.fdata_in_note=1016384 --; //size 16384
  lvar.gm_cc.fdata_in_pitch=1032768 --; //size 128
  lvar.gm_cc.fdata_fader=1150000 --;
  lvar.gm_cc.fdata_fadermode=1152000 --; //1024
  lvar.gm_cc.fdata_14bit=1154000 --; //1024
  lvar.gm_cc.fdata_polarity=1156000 --; //1024
  lvar.gm_cc.fdata_bmode=1158000 --; //1024
  lvar.gm_cc.fdata_fine=1160000 --; //1024
  lvar.gm_cc.fdata_fineval=1162000 --; //1024
  
  --lvar.fineamt = 1024
  --lvar.fineamt_idx = 1163100;  
    
  lvar.gm_cc.fbutstate = 3040100 --; //1024
  --lvar.gm_cc.fencoderres = 249000 --; //1024 -- set up via faderbox
  
  lvar.man_send = 1998998
  lvar.man_val = 1998999
  lvar.man_send2 = 1998996
  lvar.man_val2 = 1998997
  lvar.man_msg = 1998995
  
  local contexts = {updatefreq = 0,
              lockw = 1,
              lockh = 2,
              gridslider = 3,
              dragsidebar = 4,
              sliderctl = 5,
              scaleslider = 6,
              offsetslider = 7,
              valoffsetslider = 8,
              defvalslider = 9,
              textsizeslider = 10,
              dragctl = 11,
              draglasso = 12,
              dragparam = 13,
              draggfx = 14,
              stretch_x = 15,
              stretch_y = 16,
              stretch_xy = 17,
              draggfx2 = 18,
              dragstrip = 19,
              cycleknob = 20,
              dragparamlrn = 21,
              minov = 22,
              maxov = 23,
              dragparam_tr = 24,
              dragparam_snd = 25,
              shadxslider = 26,
              shadyslider = 27,
              shadaslider = 28,
              movesnapwindow = 29,
              resizesnapwindow = 30,
              dragparam_spec = 31,
              sliderctl_h = 32,
              dragcycle = 33,
              addsnapctl = 34,
              resizefsnapwindow = 35,
              hold = 36,
              insertstrip = 37,
              addxyctl = 38,
              dragxy = 39,
              auto_delayslider = 40,
              xxy_dragsnap = 41,
              xxy_movesnap = 42,
              xxy_drag = 43,
              xxy_gravityslider = 44,
              xxypath_dragcontrolpt = 45,
              xxypath_dragpt = 46,
              xxypath_posslider = 47,
              knobsens_norm = 48,
              knobsens_fine = 49,
              knobsens_wheel = 50,
              knobsens_wheelfine = 51,
              eqc_pminslider = 52,
              eqc_pmaxslider = 53,
              eqc_drag = 54,
              eqc_gminslider = 55,
              eqc_gmaxslider = 56,
              eqc_dragfreq = 57,
              eqc_draggain = 58,
              eqc_dragq = 59,
              eqc_dragc1 = 60,
              eqc_dragc2 = 61,
              eqc_dragc3 = 62,
              eqc_dragc4 = 63,
              eqc_dragc5 = 64,
              macsliderA = 65,
              macsliderB = 66,
              macctl = 67,
              macctl_h = 68,
              macctl2 = 69,
              reassplugin = 70,
              dragcycle_h = 71,
              gauge_val = 80,
              gauge_arcrad = 82,
              gauge_arclen = 83,
              gauge_arcrot = 84,
              gauge_tksz = 85,
              gauge_tkoffs = 86,
              gauge_xoffs = 87,
              gauge_yoffs = 88,
              gauge_fs = 89,
              gauge_valfreq = 90,
              gauge_nudge = 91,
              tfxo_shift = 92,
              midiout_chan = 93,
              midiout_msg = 94,
              snap_move = 95,
              snapshot_rand = 96,
              dragparam_other = 97,
              dd = 98,
              textsizevslider = 99,
              gfxopt_bright = 100,
              gfxopt_contr = 101,
              gfxopt_r = 102,
              gfxopt_g = 103,
              gfxopt_b = 104,
              gfxopt_a = 105,
              gfxopt_edge = 106,
              morph_time = 107,
              dragfader = 108,
              sa_dragstrip = 109,
              sa_dragstrip2 = 110,
              mod_draw = 111,
              dragmod = 112,
              modoffset_slider = 113,
              modmin_slider = 114,
              modmax_slider = 115,
              modwin_resize = 116,
              modwin_move = 117,
              morph_puw_slider = 118,
              move_eb = 119,
              move_ctlopts = 120,
              move_gaugeed = 121,
              move_gfxopts = 122,
              move_paramlrn = 123,
              settingswin_dragoff = 124,
              move_mutatewin = 125,
              mutate_amt = 126,
              dragsep_strip = 127,
              dragsep_gfx = 128,
              dragsep_fx = 129,
              modwin_resize2 = 130,
              sbpanszslider = 131,
              panszslider = 132,
              panfontszslider = 133,
              sbfontszslider = 134,
              lstfontszslider = 135,
              move_randomwin = 136,
              lg_probability = 137,
              lg_min = 138,
              lg_max = 139,
              lg_bias = 140,
              lg_X = 141,
              lg_range = 142,
              lg_wild = 143,
              scrollmatrix = 144,
              move_fxorder = 145,
              scrollsamples = 146,
              move_smwin = 147,
              scrollkeyb = 148,
              resize_smwin = 149,
              resize_smwinv = 150,
              move_sbwin = 151,
              resize_sbwin = 152,
              resize_sbwinv = 153,
              resize_sbwinh = 154,
              sb_dragstrip = 155,
              sb_dragstrip2 = 156,
              lv_dragstrip = 157,
              sb_movefav = 158,
              draggfx2_timer = 159,
              dragctl_timer = 160,
              scrollsswin = 161,
              scrollfxparams = 162,
              scrollgfxfiles = 163,
              scrollstripfiles = 164,
              scrollstripfols = 165,
              scrollfx = 166,
              scrollgfxfols = 167,
              sliderctlxy = 168,
              macctlxy = 169,
              dragcyclexy = 170,
              snapslider = 171,
              snapparamdrag = 172,
              sliderctl_t2 = 173,
              sliderctl_h_t2 = 174,
              macsliderctl_t2 = 175,
              macsliderctl_h_t2 = 176,
              infoctl_click = 177,
              swdrop = 178,
              switchdrag_ext = 179,
              switchdrag_ext2 = 180,
              mmov_dragh = 181,
              mmov_dragv = 192,
              shadsz_slider = 193,
              shadalpha_slider = 194,
              shadfeather_slider = 195,
              wwdrag = 196,
              resize_ctlbrowser = 197,
              mixer_vol = 198,
              resize_mixer = 199,
              mixer_pan = 200,
              sndpnl_vol = 201,
              sndpnl_pan = 202,
              mixer_vol2 = 203,
              sndpnl_drag = 204,
              analyzerctl = 205,
              mixer_drag = 206,
              dm_selecttracks = 207,
              dmtrprm_swipe = 208,
              mod_nudge = 209,
              adjust_bright = 210,
              adjust_contrast = 211,
              adjust_r = 212,
              adjust_g = 213,
              adjust_b = 214,
              sk2_dragassign = 215,
              stretch_x2 = 216,
              stretch_y2 = 217,
              stretch_xy2 = 218,
              stretch_xy3 = 219,
              stretch_xy4 = 220,
              xpnl_move = 5000,
              xpnl_resize = 5001,
              xpnl_resizew = 5002,
              xpnl_resizeh = 5003,
              xpnl_resizeh_t = 5004,
              xp_sk2_assignbtn = 5100,
              dummy = 999
              }

  local ctlcats = {fxparam = 0,
                   trackparam = 1,
                   tracksend = 2,
                   trackrecv = 3,
                   trackhwout = 4,
                   action = 5,
                   snapshot = 6,
                   pkmeter = 7,
                   xy = 8,
                   fxoffline = 9,
                   macro = 10,
                   eqcontrol = 11,
                   switcher = 12,
                   snapshotrand = 13,
                   fxgui = 14,
                   rcm_switch = 15,
                   midictl = 16,
                   oscctl = 17,
                   takeswitcher = 18,
                   rs5k = 19,
                   midieditor_pageswitch = 20,
                   switcher_pagesel = 21,
                   fxmulti = 22,
                   macro_updateparam = 23,
                   paramvalue_glob = 24,
                   threshold = 25,
                   paramvalue_strip = 26,
                   infoctl = 27,
                   statectl = 28,
                   statectl_str = 29,
                   navictl = 30,
                   gr_meter = 31,
                   sk2ctl = 32,
                   dummyctl = 33,
                   fxname = 34,
                   }

  lvar.ctlcats_nm = {'fxparam',
                     'trackparam',
                     'tracksend',
                     'trackrecv',
                     'trackhwout',
                     'action',
                     'snapshot',
                     'pkmeter',
                     'xy',
                     'fxoffline',
                     'macro',
                     'eqcontrol',
                     'switcher',
                     'snapshotrand',
                     'fxgui',
                     'rcm_switch',
                     'midictl',
                     'oscctl',
                     'takeswitcher',
                     'rs5k',
                     'midi editor - page switcher',
                     'switcher_pagesel',
                     'fxmulti',
                     'macro_updateparam',
                     'paramvalue_glob',
                     'threshold',
                     'paramvalue_strip',
                     'infoctl',
                     'statectl',
                     'statectl_str',
                     'navigation',
                     'gr meter',
                     'sk2ctl',
                     'dummyctl',
                     'fxname',}


  lvar.gfxtype = {img = 0,
                  txt = 1
                 }

  lvar.CP4Funcs = {}

  local paths = {}

  local pi = 3.14159265359

  local midiouts, midioutsidx

  lvar.SCRIPT = 'LBX_STRIPPER'
  lvar.VERSION = 0.96
  lvar.STRIPSET = 'STRIP SET 1'

  lvar.LBX_FB_CNT = 32

  local OS = reaper.GetOS()
  local gmode = 0

  local fact = {}

  --911 - 990 = control browser images - can be reused if redrawn *** unused now
  --920 - 950 = reserved for gfx pages

  --825 - 910 = Skin images + others
  --960 - ?? = Skin images

  local image_max = 824
  local strip_image = 920
  local bg_image = 930
  local ctlbitmap_image = 940

  local tmpctl = 846
  
  local guibitmap = 964
  lvar.showguibitmap = true

  local ctl_browser_image = 910
  local maximg_browse = 79
  local b_sz = 250
  local lockx = false
  local locky = false
  local lockw, olockw = 400, 400
  local lockh, olockh = 400, 400
  local auto_delay = 0
  local xxypath_indexcnt = 50

  local nebscanboot_file = nil
  local defskin_select = "LBXDEF/"
  local skin_select = defskin_select

  local mouse = {}
  local butt_h
  local mode
  local mode0_submode
  local submode
  local fxmode

  local strips
  local switchers
  local snapshots
  local xxy
  local xxy_gravity
  local modulators
  local modbaridx
  local modbaredit
  local page
  local gpage
  local navigate

  local track_select
  local trackedit_select
  local macro_lrn_mode
  local macro_edit_mode

  --INIT Initialized
  local lastprojdirty
  local last_proj_change_count
  local projnamechange
  local lastprojname

  local surface_offset
  local mod_select
  local plist_w

  local time_nextupdate
  local time_nextupdate_pkmeter
  local time_checksend
  local time_sendupdate

  lvar.ctlbrowser_docked = true
  lvar.ctlbrowser_docked_w = 220
  lvar.ctlbrowser_btnh = 24
  local show_ctlbrowser
  local show_ctloptions
  local show_lbloptions

  local show_gfxoptions
  local show_editbar
  local show_settings
  local show_cycleoptions
  local show_paramlearn
  local show_snapshots
  local show_fsnapshots
  local show_actionchooser
  local show_xxy
  local show_gaugeedit
  local show_trackfxorder
  local show_midiout
  local show_bitmap
  local show_dd
  local show_lfoedit
  local show_eqcontrol
  local show_pinmatrix

  local show_paramname
  local show_paramval

  local eq_edit

  local ctl_page

  local EB_Open
  local EB_Enter

  local MS_Open
  local MB_Enter

  local lupd = {}

  local ctl_select
  local gfx4_select
  local gfx3_select
  local gfx2_select

  local undo = {}
  --undo.active = true
  undo.max = 999
  local undo_pos = 0
  local undo_types = {ctl = 1, gfx = 2}

  --[[local update_gfx
  local update_surface
  local update_ctls
  local update_sidebar
  local update_topbar
  local update_ctlopts
  local update_actcho
  local update_xxy
  local force_gfx_update]]

  local settings_localfaders = false
  lvar.bgloaded = -1
  lvar.bgstretch = false
  lvar.bgbright = 0
  lvar.livebg = true
  lvar.mm_disablenonpoppedctls = false

  lvar.limitmw = false

  -------------------------------------------------
  
  -------------------------------------------------------------
    
  local function GetTrackGUID(track)
    if reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER') == -1 then
      return '{00000000-0000-0000-0000-000000000000}'
    else
      return reaper.GetTrackGUID(track)
    end
  end
  
   local function F_limit(val,min,max)
     if val == nil or min == nil or max == nil then return end
     local val_out = val
     if val < min then val_out = min end
     if val > max then val_out = max end
     return val_out
   end
  
   ------------------------------------------------------------
  
   local function MOUSE_sliderHBar(b)
     if mouse.mx > b.x-200 and mouse.mx < b.x+b.w+200
        and mouse.LB then
       local mx = mouse.mx - (b.x)
      return (mx) / (b.w)
     end
   end
  
   local function MOUSE_slider(b,yoff)
     if mouse.LB and not lvar.sliderzoom then
       yoff = yoff or 0
       local my = mouse.my - (b.y-200) + yoff
      return (my) / (b.h+400)
     elseif mouse.LB then
       yoff = yoff or 0
       local my = mouse.my - (b.y-(200*lvar.zoom)) + yoff
      return (my) / (b.h+(400*lvar.zoom))
     end
   end
  
   local function MOUSE_slider_S(b,yoff)
     if mouse.LB and not lvar.sliderzoom then
       yoff = yoff or 0
       local my = mouse.smy - (b.y-200) + yoff
      return (my) / (b.h+400)
     elseif mouse.LB then
       yoff = yoff or 0
       local my = mouse.smy - (b.y-(200*lvar.zoom)) + yoff
      return (my) / (b.h+(400*lvar.zoom))
     end
   end
  
   local function MOUSE_slider_alt(b,yoff,xoff)
     if mouse.LB and not lvar.sliderzoom then
       yoff = yoff or 0
       xoff = xoff or 0
       local my = mouse.my - (b.y-200) + yoff
       local mx = mouse.mx - (b.x-200) + xoff
      return (my / (b.h+400)) + (-mx / (b.w+400))
     elseif mouse.LB then
       yoff = yoff or 0
       xoff = xoff or 0
       local my = mouse.my - (b.y-(200*lvar.zoom)) + yoff
       local mx = mouse.mx - (b.x-(200*lvar.zoom)) + xoff
      return (my / (b.h+(400*lvar.zoom))) + (-mx / (b.w+(400*lvar.zoom)))
     end
   end
  
   local function MOUSE_slider_S_alt(b,yoff,xoff)
     if mouse.LB and not lvar.sliderzoom then
       yoff = yoff or 0
       xoff = xoff or 0
       local my = mouse.smy - (b.y-200) + yoff
       local mx = mouse.smx - (b.x-200) + xoff
      return (my / (b.h+400)) + (-mx / (b.w+400))
     elseif mouse.LB then
       yoff = yoff or 0
       xoff = xoff or 0
       local my = mouse.smy - (b.y-(200*lvar.zoom)) + yoff
       local mx = mouse.smx - (b.x-(200*lvar.zoom)) + xoff
      return (my / (b.h+(400*lvar.zoom))) + (-mx / (b.w+(400*lvar.zoom)))
     end
   end
  
   local function MOUSE_sliderX(b,yoff)
     if mouse.LB then
       yoff = yoff or 0
       local my = mouse.my - b.y + yoff
      return (my+200) / (400)
     end
   end
  
   local function MOUSE_slider_horiz(b,xoff)
     if mouse.LB then
       xoff = xoff or 0
       local mx = mouse.mx - (b.x-200) + xoff
      return (mx) / (b.w+400)
     end
   end
  
   local function MOUSE_slider_S_horiz(b,xoff)
     if mouse.LB and not lvar.sliderzoom then
       xoff = xoff or 0
       local mx = mouse.smx - (b.x-200) + xoff
      return (mx) / (b.w+400)
     elseif mouse.LB then
       xoff = xoff or 0
       local mx = mouse.smx - (b.x-(200*lvar.zoom)) + xoff
      return (mx) / (b.w+(400*lvar.zoom))
     end
   end
  
   local function MOUSE_slider_horiz2(b, xoff)
     if mouse.LB then
       xoff = xoff or 0
       local mx = mouse.mx - xoff
      return (mx) / (b.w)
     end
   end
  
   local function MOUSE_sliderRB(b)
     if mouse.RB then
       local my = mouse.my - (b.y-200)
      return (my) / (b.h+400)
     end
   end
  
   local function MOUSE_surfaceX(b)
     if mouse.LB then
       local mx = mmx - mouse.mx
      return (mx)
     end
   end
  
   local function MOUSE_surfaceX2(b)
     if mouse.LB then
       local mx = mmx - mouse.mx
      return (mx)
     end
   end
  
   local function MOUSE_surfaceY(b)
     if mouse.LB then
       local my = mmy - mouse.my
      return (my)
     end
   end
  
   local function MOUSE_click(b)
     if b and mouse.mx > b.x and mouse.mx < b.x+b.w
       and mouse.my > b.y and mouse.my < b.y+b.h
       and mouse.LB
       and not mouse.last_LB then
      return true
     end
     --return nil
   end
  
   local function MC()
     if (mouse.LB and not mouse.last_LB) or
        (mouse.RB and not mouse.last_RB) then
      return true
     end
     --return nil
   end
  
   local function MOUSE_click2(b, mx, my)
     if mx == nil then mx = mouse.mx end
     if my == nil then my = mouse.my end
  
     if mx > b.x and mx < b.x+b.w
       and my > b.y and my < b.y+b.h
       and mouse.LB
       and not mouse.last_LB then
      return true
     end
   end
  
   local function MOUSE_click2_RB(b, mx, my)
     if mx == nil then mx = mouse.mx end
     if my == nil then my = mouse.my end
     if mx > b.x and mx < b.x+b.w
       and my > b.y and my < b.y+b.h
       and mouse.RB
       and not mouse.last_RB then
      return true
     end
   end
  
   local function MOUSE_LB()
     if mouse.LB
       and not mouse.last_LB then
      return true
     end
     --return nil
   end
  
   local function MOUSE_RB()
     if mouse.RB
       and not mouse.last_RB then
      return true
     end
     --return nil
   end
  
   local function MOUSE_clickXY(b,xoff,yoff)
     if mouse.mx > b.x+xoff and mouse.mx < b.x+xoff+b.w
       and mouse.my > b.y+yoff and mouse.my < b.y+yoff+b.h
       and mouse.LB
       and not mouse.last_LB then
      return true
     end
   end
  
   local function MOUSE_click_RB(b)
     if mouse.mx > b.x and mouse.mx < b.x+b.w
       and mouse.my > b.y and mouse.my < b.y+b.h
       and mouse.RB
       and not mouse.last_RB then
      return true
     end
   end
  
   local function MOUSE_over(b, mx, my)
     if mx == nil then mx = mouse.mx end
     if my == nil then my = mouse.my end
  
     if mx > b.x and mx < b.x+b.w
       and my > b.y and my < b.y+b.h then
      return true
     end
     --return nil
   end
  
  local function mousewheel_val()
  
    if lvar.limitmw then
      
      local v = math.ceil(gfx.mouse_wheel/lvar.mousewheel_div)
      if v < 0 then
        return math.max(v,-1)
      else
        return math.min(v,1)
      end
      
    else
      return math.ceil(gfx.mouse_wheel/lvar.mousewheel_div)
    end
  
  end
  
  local function RedrawGUIBitmap(t)
  --DBG('T')
    if t then
      lvar.redrawguibitmap_timer = reaper.time_precise() + t
    else
      if mouse.context == nil then
        lvar.redrawguibitmap = true
      else
        lvar.redrawguibitmap_nocontext = true      
      end
      if lvar.livemode >= 1 then
        if lvar.popout_autoarrange then
          --DBG('a')
          PopOut_AutoArrange()
        else
          PopOut_GetBounds()
        end
      end
    end
  end
  
  local function Img_SetDim(img, w, h, noclear, clearmethod2, bcol)
    --DBG(img .. '  '..tostring(noclear))
    if lvar.largeimages then
      w = math.min(w, lvar.maxdim)
      h = math.min(h, lvar.maxdim)
      if not noclear then
        gfx.setimgdim(img,-1,-1)
      end
      if w ~= -1 and h ~= -1 then
        gfx.setimgdim(img,w,h)     
      end
      if bcol then
        local od = gfx.dest          
        gfx.dest = img
        f_Get_SSV(bcol) 
        gfx.rect(0,0,w,h,1)
        gfx.dest = od
      end  
    elseif (w <= 2048 and h <= 2048) or lvar.missingTI then
      w = math.min(w, 2048)
      h = math.min(h, 2048)
      if not noclear then
        if clearmethod2 then
          local od = gfx.dest          
          gfx.dest = img
          gfx.muladdrect(0,0,w,h,0,0,0,0)
          gfx.dest = od
        else
          gfx.setimgdim(img,-1,-1)
        end
      end
      if w ~= -1 and h ~= -1 then
        gfx.setimgdim(img,w,h)     
      end
    else    
      local od = gfx.dest          
      gfx.dest = img
      local w2, h2 = gfx.getimgdim(img)
      --DBG(w2..'  '..h2)
      if w2 < lvar.maxdim or h2 < lvar.maxdim then
        gfx.loadimg(img,lvar.tranimg)
        
        --lupd.update_gfx = true
      elseif not noclear then
        gfx.muladdrect(0,0,w,h,0,0,0,0)
      end
  
      if bcol then
        f_Get_SSV(bcol) 
        gfx.rect(0,0,w,h,1)
      end  
      gfx.dest = od
    end
  end
  
  ------------------------------------------------------------
  
  local function GetWWData(txt, w, firstline)
  
    txt = string.gsub(txt, '[_]', ' ')
    local tw, th = gfx.measurestr(txt)
  
    local tab = {}
    tab.txt = txt
  
    local stab = split2(txt," ")
    local ln = 1
    if firstline then
      if not tab[ln] then
        tab[ln] = {w=0}
      end
      local sw, sh = gfx.measurestr(firstline)
      tab[ln].w = sw
      tab[ln].t = firstline
      ln = 2
    end
    for i = 1, #stab do
      if not tab[ln] then
        tab[ln] = {w=0}
      end
      local pfx = ''
      if i > 1 then
        pfx = ' '
      end
      local sw, sh = gfx.measurestr(pfx..stab[i])
      if sw > w then
        --too big for line
        if i == 1 then
          --display on current line
          tab[ln].w = tab[ln].w + sw
          tab[ln].t = (tab[ln].t or '') .. pfx..stab[i]
          ln = ln + 1
          tab[ln] = {w=0}
        else
          --display on next line
          ln = ln + 1
          tab[ln] = {}
          tab[ln].w = sw
          tab[ln].t = stab[i]
        end
      elseif sw + tab[ln].w > w then
        --display on next line
          ln = ln + 1
          tab[ln] = {}
          tab[ln].w = sw
          tab[ln].t = stab[i]
      else
        --display on current line
        tab[ln].w = tab[ln].w + sw
        tab[ln].t = (tab[ln].t or '').. pfx..stab[i]
      end
  
    end
  
    return tab, th
  
  end

  local function GetHUDIdx(ctl)
    local idxx = ctl.c_id
    if ctl.ctlcat == ctlcats.fxparam then
      idxx = ctl.fxguid..'|'..ctl.param
    end
    return idxx
  end
  
  local function SetHUD(ctl)
    local idx = lvar.paramhud_idx[GetHUDIdx(ctl)]
    if not idx then
      idx = #lvar.paramhud + 1
      lvar.paramhud[idx] = {}
      local idxx = GetHUDIdx(ctl)
      lvar.paramhud_idx[idxx] = idx
    end
    local ph = lvar.paramhud[idx]
    ph.ctl = ctl
    if (ctl.ctlname_override or '') ~= '' then
      ph.name = ctl.ctlname_override
    else
      ph.name = ctl.param_info.paramname
    end
    ph.timeout = reaper.time_precise() + 2
    ph.alpha = nil
    xPnl.HUD.updategui = true
  end
  
  -------------------------------------------------
  -- XPANELS
  -------------------------------------------------
  
  xPnl.SK2 = {name = 'SK2', x = 0, y = 400, ow = 660, oh = 200, minw = 660, minh = 200, iidx = 827, resize = true}
  xPnl.HUD = {name = 'HUD', x = 0, y = 0, ow = 200, oh = 100, minw = 150, minh = 100, iidx = 828, resize = false, clickthrough = 1}
  
  local xPnlIdx = {}
  lvar.xPnlOffset = 1000000
  lvar.xPnlCnt = 0
  
  function xPnl.HUD:init()
    self.title = 'PARAMETER HUD'
    local idx = #xPnlIdx + 1
    self.guiobj = {}
    self.updategui = true
    local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
    self.minh = thh
    self.w = math.max(math.ceil(self.ow * pnl_scale),self.minw)
    self.h = math.max(math.ceil(self.oh * pnl_scale),self.minh)
    self.internalh = self.h - thh
    --self.anchor = lvar.anchor['bottom_centre']
    self.obj = {}
    self.obj[1] = {x = 10, y = thh+10, w = self.w-20, h = self.h-thh-20}
    
    gfx.setimgdim(self.iidx,-1,-1)
    gfx.setimgdim(self.iidx,self.w,self.h)
    
    return self
  end
  
  function xPnl.HUD:draw()
    gfx.dest = self.iidx
    local alpha = 0.25
    local tbalpha = 0.25
    local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
    local rh = 20
    local h = 0
    local cnt = #lvar.paramhud
    if cnt > 0 then
      h = cnt*rh            
    end
    self.h = thh+h+20
    self.w = 260
    
    gfx.setimgdim(self.iidx,-1,-1)
    gfx.setimgdim(self.iidx,self.w,self.h)

    GUI_DrawPanel(self, nil, self.title, nil, alpha, tbalpha)
  
    local xywh1 = {x = 10, y = thh+10, w = self.w-20, h = rh}
    local c = gui.color.white
    local cv = gui.color.yellow
    for i = 1, cnt do
      local ctl = lvar.paramhud[i].ctl
      if ctl then
        local name = lvar.paramhud[i].name
        local val = ctl.dval
        GUI_Str(gui, xywh1, name, 4, c, -4 + gui.fontsz.lst + lst_fontscale, lvar.paramhud[i].alpha or 1, '0 0 0', gui.fontnm.lst, gui.fontflag.lst)
        GUI_Str(gui, xywh1, (val or ''), 6, cv, -4 + gui.fontsz.lst + lst_fontscale, lvar.paramhud[i].alpha or 1, '0 0 0', gui.fontnm.lst, gui.fontflag.lst)
        xywh1.y = xywh1.y+rh
      end
    end
    
  end
  
  function xPnl.HUD:onclick(x,y)
  
    local LB, RB = mouse.LB, mouse.RB
    
    lvar.xPnlSel = self
    if LB then
      mouse.context = contexts.xpnl_move
      lvar.movexPnl = {xoff = x, yoff = y}
    end
  end
  
  function xPnl.SK2:init()
    --self.visible = true
    self.title = 'SK2'
    local idx = #xPnlIdx + 1
    self.guiobj = {}
    self.updategui = true
    local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
    self.minh = thh
    self.w = math.max(math.ceil(self.ow * pnl_scale),self.minw)
    self.h = math.max(math.ceil(self.oh * pnl_scale),self.minh)
    self.internalh = self.h - thh
    self.anchor = lvar.anchor['bottom_centre']
    self.obj = {}
    
    self.cols = 8
    self.bsz = ((self.w-10) / self.cols)
    self.rows = math.min(math.floor((self.internalh-10) / self.bsz),8)
 
    self.obj[1] = {x = 10, y = thh+10, w = self.w-20, h = self.rows*self.bsz}
    self.obj[2] = {x = 10, y = 3, w = self.bsz, h = thh-6}
    self.obj[3] = {x = self.obj[2].x+self.obj[2].w+10, y = 3, w = self.bsz, h = thh-6}
    self.obj[4] = {x = self.obj[3].x+self.obj[3].w+10, y = 3, w = 40, h = thh-6}
    self.obj[5] = {x = self.obj[4].x+self.obj[4].w+10, y = 3, w = 40, h = thh-6}
    
    self.h = math.max(math.floor(self.obj[1].y+self.obj[1].h),self.minh)
    --self.oh = math.floor(self.h/pnl_scale)
    
    gfx.setimgdim(self.iidx,-1,-1)
    gfx.setimgdim(self.iidx,self.w,self.h)
    
    self.bsz = math.floor(self.bsz - 10)
    
    return self
  end
  
  function xPnl.SK2:draw()
    gfx.dest = self.iidx
    local alpha = 0.75
    local talpha = 1
    GUI_DrawPanel(self, nil, self.title, nil, alpha, talpha)
    local o1 = self.obj[1]
    --gfx.rect(o1.x,o1.y,o1.w,o1.h,0)
    local max = (lvar.sk2overlay.slots / self.cols) - self.rows
    lvar.sk2overlay.listoffs = F_limit(lvar.sk2overlay.listoffs,0,max)
    
    for c = 0, self.cols-1 do
      for r = 0, self.rows-1 do
        xywh = {x = o1.x + c*(self.bsz+10), y = o1.y + r*(self.bsz+10), w = self.bsz, h = self.bsz}
        local idx = ((r+lvar.sk2overlay.listoffs)*self.cols + c + 1)
        
        local txt = string.format('%i',idx)
        local cc = gui.color.black
        local ccc
        if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp] and lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][idx] then
          txt = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][idx].paramname
          local cidx = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][idx].sscolor
          if tab_xtouch_colors[cidx] then
            local xt = tab_xtouch_colors[cidx]
            ccc = xt.r + (xt.g << 8) + (xt.b << 16)
            cc = xt.tc or xt.c
          end
        elseif lvar.sk2overlay.slot[idx] then
          txt = --[['['..lvar.sk2overlay.slot[idx].dev..'] '..]]lvar.sk2overlay.slot[idx].name
          cc = '64 64 64'
        end
        
        GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
        local tab, th = GetWWData(txt, self.bsz-10)
        if not tab[#tab].t then
          tab[#tab] = nil
        end
        GUI_DrawButtonWW(gui, tab, th, 4, xywh, -1, cc, true, nil, nil, 0, nil, nil, nil, nil, nil, ccc, cc)

      end
    end
    
    local c = -1
    if lvar.sk2overlay_active == 1 then
      c = -8   
    end
    GUI_DrawButton(gui, 'ENABLE', self.obj[2], c, gui.color.white, true, '', false, gui.fontsz.butt)
    GUI_DrawButton(gui, 'GLOB GRP '..string.format('%i',lvar.sk2overlay_globalassgrp), self.obj[3], c, gui.color.white, true, '', false, gui.fontsz.butt)
    
    local c = -1
    if lvar.sk2overlay_solo == 1 then
      c = -8   
    end
    GUI_DrawButton(gui, 'SOLO', self.obj[4], c, gui.color.white, true, '', false, gui.fontsz.butt)
    local c = -1
    if lvar.sk2overlay_hud > 0 then
      c = -8   
    end
    GUI_DrawButton(gui, 'HUD', self.obj[5], c, gui.color.white, true, '', false, gui.fontsz.butt)
    
    self.updategui = false
  end

  function xPnl.SK2:onclick(x,y)
  
    local LB, RB = mouse.LB, mouse.RB
    
    lvar.xPnlSel = self
    if LB then
      if MOUSE_over(self.obj[2],x,y) then
        lvar.sk2overlay_active = 1-lvar.sk2overlay_active
        self.updategui = true
        SendSK2Data_Enable(lvar.sk2overlay_active)
      elseif MOUSE_over(self.obj[3],x,y) then
        lvar.sk2overlay_globalassgrp = math.min(lvar.sk2overlay_globalassgrp+1,32)
        if lvar.sk2overlay_active == 1 then
          SendSK2Data()
        end
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
      elseif MOUSE_over(self.obj[4],x,y) then
        lvar.sk2overlay_solo = 1-lvar.sk2overlay_solo
        if lvar.sk2overlay_active == 1 then
          SendSK2Data()
        end
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
        SK2SaveSlots()
        
      elseif MOUSE_over(self.obj[5],x,y) then
        lvar.sk2overlay_hud = 1-lvar.sk2overlay_hud
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
        SK2SaveSlots()
        
      elseif y < 10 then
        if mouse.lastLBclicktime and (reaper.time_precise()-mouse.lastLBclicktime) < 0.2 then
          if self.rows <= 0 then
            self.oh = self.ohh or 200
            self:init()
          else
            local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
            self.ohh = self.oh
            self.oh = thh
            self:init()
          end
          RedrawGUIBitmap()
        else
          mouse.context = contexts.xpnl_resizeh_t
          lvar.resizexPnl = {xoff = x, yoff = y, xy = self.y, ow = self.ow, oh = self.oh, w = self.w, h = self.h, wdiff = 0, hdiff = 0}
        end
      elseif y < gui.winsz.pnltit*pnl_scale then
        if mouse.lastLBclicktime and (reaper.time_precise()-mouse.lastLBclicktime) < 0.2 then
          if self.rows <= 0 then
            self.oh = self.ohh or 200
            self:init()
          else
            local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
            self.ohh = self.oh
            self.oh = thh
            self:init()
          end
          RedrawGUIBitmap()
        else
          if self.anchor == lvar.anchor['bottom_centre'] then
            mouse.context = contexts.xpnl_resizeh_t
            lvar.resizexPnl = {xoff = x, yoff = y, xy = self.y, ow = self.ow, oh = self.oh, w = self.w, h = self.h, wdiff = 0, hdiff = 0}
          else
            mouse.context = contexts.xpnl_move
            lvar.movexPnl = {xoff = x, yoff = y}
          end
        end
      elseif self.resize and x > self.w-10 and y > self.h-10 then
        mouse.context = contexts.xpnl_resize
        lvar.resizexPnl = {xoff = x, yoff = y, ow = self.ow, oh = self.oh, w = self.w, h = self.h, wdiff = 0, hdiff = 0}
      elseif self.resize and x > self.w-10 then
        mouse.context = contexts.xpnl_resizew
        lvar.resizexPnl = {xoff = x, yoff = y, ow = self.ow, oh = self.oh, w = self.w, h = self.h, wdiff = 0, hdiff = 0}
      elseif self.resize and y > self.h-10 then
        mouse.context = contexts.xpnl_resizeh
        lvar.resizexPnl = {xoff = x, yoff = y, ow = self.ow, oh = self.oh, w = self.w, h = self.h, wdiff = 0, hdiff = 0}
      elseif MOUSE_over(self.obj[1],x,y) then
      
        local c = math.floor((x-self.obj[1].x) / (self.bsz+10))
        local r = math.floor((y-self.obj[1].y) / (self.bsz+10))
        local btn = (r+lvar.sk2overlay.listoffs)*self.cols + c + 1
      
        if mouse.alt then
          lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn] = nil
          
          local xpnl = lvar.xPnlSel
          xpnl.updategui = true
          
          SendSK2Data()
        elseif mouse.shift then
          if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn] then
            lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor + 1
            if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor > #tab_xtouch_colors then
              lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor = 0
            end
            SendSK2Data()
            --tab_xtouch_colors
          end
        else
          mouse.context = contexts.xp_sk2_assignbtn
          lvar.xp_sk2_assign = {x = mouse.mx, y = mouse.my, btn = btn}
        end
      end
    elseif RB then
      if MOUSE_over(self.obj[3],x,y) then
        lvar.sk2overlay_globalassgrp = math.max(lvar.sk2overlay_globalassgrp-1,1)
        if lvar.sk2overlay_active == 1 then
          SendSK2Data()
        end
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
      elseif MOUSE_over(self.obj[5],x,y) then
        lvar.sk2overlay_hudt = lvar.sk2overlay_hudt+1
        if lvar.sk2overlay_hudt > 2 then
          lvar.sk2overlay_hudt = 0
        end
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
        SK2SaveSlots()
      elseif y < gui.winsz.pnltit*pnl_scale then
        HideXPnl(self.name)
      elseif MOUSE_over(self.obj[1],x,y) then
        local c = math.floor((x-self.obj[1].x) / (self.bsz+10))
        local r = math.floor((y-self.obj[1].y) / (self.bsz+10))
        local btn = (r+lvar.sk2overlay.listoffs)*self.cols + c + 1
      
        if mouse.shift then
          if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn] then
            lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor - 1
            if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor < 0 then
              lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor = #tab_xtouch_colors
            end
            SendSK2Data()
            --tab_xtouch_colors
          end
        else
        
          SK2DropDown(btn)
        end
      end
    end
    if not mouse.context then
      --prevent mouse click activating anything else
      mouse.context = contexts.dummy
    end
  end
  
  function xPnl.SK2:onwheel(x,y)
    lvar.xPnlSel = self
    local v = mousewheel_val()
    
    if MOUSE_over(self.obj[1],x,y) then
    
      local noffs = lvar.sk2overlay.listoffs - v
      local max = (lvar.sk2overlay.slots / lvar.xPnlSel.cols) - lvar.xPnlSel.rows
      lvar.sk2overlay.listoffs = F_limit(noffs,0,max)
      lvar.xPnlSel.updategui = true
    end
    
    gfx.mouse_wheel = 0
  end
  
  function ShowXPnl(name)
    if xPnl[name] and not xPnlIdx[name] then
      xPnl[name].visible = true
      lvar.xPnlCnt = lvar.xPnlCnt + 1
      xPnlIdx[lvar.xPnlCnt], xPnlIdx[name] = xPnl[name]:init(), lvar.xPnlCnt
      RedrawGUIBitmap()
    end
  end
  
  function HideXPnl(name)
    if xPnl[name] and xPnlIdx[name] then
      xPnl[name].visible = false
      local ntab = {}
      local cnt = 0
      for i = 1, lvar.xPnlCnt do
        if i ~= xPnlIdx[name] then
          cnt = cnt + 1
          ntab[cnt] = xPnlIdx[i]
          ntab[xPnlIdx[i].name] = cnt
        end
      end
      xPnlIdx = ntab
      lvar.xPnlCnt = cnt
      RedrawGUIBitmap()
    end
  end
  
  function InitXPnls(noload)
    
    if not noload then
      XpnlLoadInfo()
    end
    
    for a, pnl in pairs(xPnl) do
      pnl:init()
    end
  end
  
  function XpnlSaveInfo()
    local str = ''
    for a, pnl in pairs(xPnl) do
      str = str..'['..a..'|visible]'..tostring(pnl.visible)..'\n'
      str = str..'['..a..'|x]'..pnl.x..'\n'
      str = str..'['..a..'|y]'..pnl.y..'\n'
      str = str..'['..a..'|ow]'..pnl.ow..'\n'
      str = str..'['..a..'|oh]'..pnl.oh..'\n'
    end
    local fn = paths.resource_path..'xpnlinfo.lbx'
    file=io.open(fn,"w")
    file:write(str)
    file:close()
  end
  
  function XpnlLoadInfo()
  
    local fn = paths.resource_path..'xpnlinfo.lbx'
    if reaper.file_exists(fn) then
      
      local match = string.match
      local data = {}
      local flines = io.lines
      for line in flines(fn) do
        local pnlname, key, val = match(line,'%[(.-)|(.-)%](.*)')
        if pnlname then
          if xPnl[pnlname] then
            if tonumber(val) then
              xPnl[pnlname][key] = tonumber(val)
            elseif val == 'true' or val == 'false' then
              xPnl[pnlname][key] = tobool(val)
            else
              xPnl[pnlname][key] = val
            end
          end
        end
      end
      
      for a, b in pairs(xPnl) do
        if b.visible then
          ShowXPnl(b.name)
        end
      end
    end
  end
  
  function DrawXPnls()
  
    if mode ~= 0 then return end
    
    if resize_display == true then
      InitXPnls(true)
    end
    
    for i = 1, #xPnlIdx do
    
      local xpnl = xPnlIdx[i]
      if xpnl and xpnl.draw then
        if xpnl.updategui then
          gfx.setimgdim(xpnl.iidx,-1,-1)
          gfx.setimgdim(xpnl.iidx,xpnl.w,xpnl.h)
          xpnl:draw()
        end
        if xpnl.visible then
          gfx.dest = -1
          gfx.a = 1
          if xpnl.anchor then
            local o10 = obj.sections[10]
            if xpnl.anchor == lvar.anchor['bottom_centre'] then
              xpnl.x = o10.x + math.floor(o10.w/2 - xpnl.w/2)
              xpnl.y = o10.y + o10.h - xpnl.h
            elseif xpnl.anchor == lvar.anchor['bottom_centre'] then
              xpnl.x = o10.x + math.floor(o10.w/2 - xpnl.w/2)
              xpnl.y = o10.y
            end
          end
          local x,y = xpnl.x, xpnl.y
          gfx.blit(xpnl.iidx, 1, 0, 0, 0, xpnl.w, xpnl.h, xpnl.x, xpnl.y)
        end
      end
    end
  
    gfx.dest = -1
    
    local xpnl = lvar.xPnlSel
    if lvar.xp_sk2_assign then
      f_Get_SSV('0 0 0')
      gfx.a = 0.5
      local y = lvar.xp_sk2_assign.y-80
      gfx.rect(lvar.xp_sk2_assign.x-50,y,100,100,1)
      local c
      local txt = ''
      if lvar.xp_sk2_assign.assignctl == -1 then
        f_Get_SSV('255 0 0')
        c = '255 0 0'
      elseif lvar.xp_sk2_assign.assignctl then
        c = '0 255 0'
        local ctl = lvar.xp_sk2_assign.assignctl
        if (ctl.ctlname_override or '') ~= '' then
          txt = ctl.ctlname_override
        else
          txt = ctl.param_info.paramname
        end
      else
        c = '255 255 255'
      end
      gfx.a = 1
      local xywh = {x = lvar.xp_sk2_assign.x-50, y = y, w = 100, h = 100}
      local txt2 = 'SK2 Assign: '..txt
      GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
      local tab, th = GetWWData(txt2, 100)
      if not tab[#tab].t then
        tab[#tab] = nil
      end
      gfx.a = 0.5
      GUI_DrawButtonWW(gui, tab, th, 4, xywh, -5, c, true, nil, nil, 0)
      f_Get_SSV(c)
      gfx.rect(lvar.xp_sk2_assign.x-50,y,100,100,0)
  
      --GUI_textC(gui,xywh,txt2,c,-2 +((lvar.zoom-1)*8))
    end
  
  end
  
  function A_Run_XPnlContext()
  
    mouse.xpnlcontext = mouse.context
    if mouse.context < 5100 then
      if mouse.context == contexts.xpnl_move then
        local xpnl = lvar.xPnlSel
        if xpnl then
          if mouse.mx ~= xpnl.x + lvar.movexPnl.xoff or mouse.my ~= xpnl.y + lvar.movexPnl.yoff then
            xpnl.x = F_limit(mouse.mx - lvar.movexPnl.xoff,0,gfx1.main_w-xpnl.w)
            xpnl.y = F_limit(mouse.my - lvar.movexPnl.yoff,0,gfx1.main_h-xpnl.h)
          end
        end
      elseif mouse.context == contexts.xpnl_resize then
        local xpnl = lvar.xPnlSel
        if xpnl then
          local wdiff = (mouse.mx - (xpnl.x + lvar.resizexPnl.xoff))
          local hdiff = (mouse.my - (xpnl.y + lvar.resizexPnl.yoff))
          if wdiff ~= lvar.resizexPnl.wdiff or hdiff ~= lvar.resizexPnl.hdiff then
            lvar.resizexPnl.wdiff = wdiff
            lvar.resizexPnl.hdiff = hdiff
            xpnl.ow = math.floor((lvar.resizexPnl.w + wdiff)/pnl_scale)
            xpnl.oh = math.floor((lvar.resizexPnl.h + hdiff)/pnl_scale)
            xpnl:init()
          end
        end
      elseif mouse.context == contexts.xpnl_resizew then
        local xpnl = lvar.xPnlSel
        if xpnl then
          local wdiff = (mouse.mx - (xpnl.x + lvar.resizexPnl.xoff))
          if wdiff ~= lvar.resizexPnl.wdiff then
            lvar.resizexPnl.wdiff = wdiff
            lvar.resizexPnl.hdiff = hdiff
            xpnl.ow = math.floor((lvar.resizexPnl.w + wdiff)/pnl_scale)
            xpnl:init()
          end
        end
      elseif mouse.context == contexts.xpnl_resizeh then
        local xpnl = lvar.xPnlSel
        if xpnl then
          local hdiff = (mouse.my - (xpnl.y + lvar.resizexPnl.yoff))
          if hdiff ~= lvar.resizexPnl.hdiff then
            lvar.resizexPnl.wdiff = wdiff
            lvar.resizexPnl.hdiff = hdiff
            xpnl.oh = math.floor((lvar.resizexPnl.h + hdiff)/pnl_scale)
            xpnl:init()
          end
        end
      elseif mouse.context == contexts.xpnl_resizeh_t then
        local xpnl = lvar.xPnlSel
        if xpnl then
          local hdiff = (lvar.resizexPnl.xy + lvar.resizexPnl.yoff)-mouse.my
          if hdiff ~= lvar.resizexPnl.hdiff then
            lvar.resizexPnl.wdiff = wdiff
            lvar.resizexPnl.hdiff = hdiff
            local ob = xpnl.y+xpnl.h
            xpnl.oh = math.floor((lvar.resizexPnl.h + hdiff)/pnl_scale)
            xpnl:init()
            xpnl.y = ob-xpnl.h            
          end
        end
      end
      
    elseif mouse.context < 5120 then
      if mouse.context == contexts.xp_sk2_assignbtn then
        lvar.xp_sk2_assign.x = mouse.mx
        lvar.xp_sk2_assign.y = mouse.my
        lvar.xp_sk2_assign.assignctl = nil
        if CheckOver10_gui() then
          local strip = tracks[track_select].strip
          local c = GetControlAtXY(strip, page, mouse.mx, mouse.my, true)
          if c then
            local ctl = strips[strip][page].controls[c]
            if ctl and ctl.ctlcat == ctlcats.fxparam then
              lvar.xp_sk2_assign.assignctl = ctl
              lvar.xp_sk2_assign.assignctl_c = c
            else
              lvar.xp_sk2_assign.assignctl = -1
            end
          end
        end
      end
    end
    
  end
  
  function A_Run_XPnlContext_End()
  
    if mouse.xpnlcontext == contexts.xpnl_move or 
       mouse.xpnlcontext == contexts.xpnl_resize or 
       mouse.xpnlcontext == contexts.xpnl_resizew or 
       mouse.xpnlcontext == contexts.xpnl_resizeh or 
       mouse.xpnlcontext == contexts.xpnl_resizeh_t then
      RedrawGUIBitmap()
    elseif mouse.xpnlcontext == contexts.xp_sk2_assignbtn then
      if lvar.xp_sk2_assign.assignctl and lvar.xp_sk2_assign.assignctl ~= -1 then
        local btn = lvar.xp_sk2_assign.btn
        local ctl = lvar.xp_sk2_assign.assignctl
        if not lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp] then
          lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp] = {}
        end
        if not lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn] then
          lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn] = {}
        end
        local tguid, m
        if lvar.livemode == 2 then
          tguid = lvar.dynamicmode_guid
          m = 2
        else
          m = 0
          tguid = GetTrackGUID(GetTrack(tracks[track_select].tracknum))
        end
        
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].mode = m
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].tguid = tguid
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].cid = ctl.c_id
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].c = lvar.xp_sk2_assign.assignctl_c
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].fxguid = ctl.fxguid
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].fxparam = ctl.param_info.paramnum
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].paramname = ctl.param_info.paramname
        lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][btn].sscolor or 7
        
        local xpnl = lvar.xPnlSel
        xpnl.updategui = true
        
        SendSK2Data()
      end
      lvar.xp_sk2_assign = nil
    end
  
    mouse.xpnlcontext = nil
  end
  
  -------------------------------------------------------
  function CheckAllCids()
  
    local ccnt = 0
    
    local cidlist = {}
    cidlist.trguids = {}
    for t = -1, reaper.CountTracks(0)-1 do
      local track = GetTrack(t)
      cidlist.trguids[GetTrackGUID(track)] = t
    end
    
    for s = 1, #strips do
      --DBG('tguid = '..strips[s].track.guid..'='..tostring(cidlist.trguids[strips[s].track.guid])..'='..strips[s].track.tracknum)
      for p = 1, lvar.maxpage do
        local ctls = strips[s][p].controls
        for c = 1, #ctls do
          if cidlist[ctls[c].c_id] then
            --cidlist[ctls[c].c_id] = cidlist[ctls[c].c_id] + 1
            --DBG('DUP FOUND '..c)
          else
            ccnt = ccnt + 1
            cidlist[ctls[c].c_id] = {type = 0, 
                                     ctl = ctls[c], 
                                     ctls = ctls, 
                                     striptab = strips[s][p], 
                                     trackguid = strips[s].track.guid,
                                     snaptab = snapshots[s][p]}
          end
          
        end
      end
    end
    for a,b in pairs(lvar.stripstore) do
      if b then
        --DBG('*tguid = '..a..'='..tostring(cidlist.trguids[a]))
        local ctls = b.controls
        for c = 1, #ctls do
          if cidlist[ctls[c].c_id] and a ~= cidlist[ctls[c].c_id].trackguid then
            --cidlist[ctls[c].c_id] = ctls[c]
            --DBG('DM DUP FOUND '..c..' '..a..'='..tostring(cidlist.trguids[a])..'  '..cidlist[ctls[c].c_id].trackguid..'='..tostring(cidlist.trguids[cidlist[ctls[c].c_id].trackguid]))
          elseif cidlist[ctls[c].c_id] then
          
          else
            ccnt = ccnt + 1
            cidlist[ctls[c].c_id] = {type = 1, 
                                     ctl = ctls[c], 
                                     ctls = ctls, 
                                     striptab = b,
                                     trackguid = a,
                                     snaptab = lvar.snapstore[a]}
          end
        end
      end
    end
    

    --DBG('SCANNED CIDS: '..ccnt)
    
    return cidlist 
    
  end
  
  
  --[[function MonitorSK2Links()
    local gmem_rd = reaper.gmem_read
    reaper.gmem_attach('LBX_SK2_SharedMem')
    for a, b in pairs(lvar.sk2overlay.assign) do
      if b then
      
        for btn, tab in pairs(b) do
          local map = lvar.sk2overlay.slot[btn].map
          local sk2slot = lvar.sk2data_slotsidx[map]
          local val = gmem_rd(lvar.gm_fb.fader_val + sk2slot) / 16383
          local ctl = lvar.cids[tab.cid]
          
          A_SetParam()
        end
      end
    end
  end]]
  
  function SaveSK2Assign(file)
    --lvar.sk2overlay_assigntab = {'fxguid','fxparam','paramname','sscolor'}
    if file then
      for a, b in pairs(lvar.sk2overlay.assign) do
        if b then
        
          for btn, tab in pairs(b) do
            local str = '[SK2OL_'..a..'_'..btn..']'
            for i = 1, #lvar.sk2overlay_assigntab do
              if i > 1 then
                str = str..'|'
              end
              str = str..(tab[lvar.sk2overlay_assigntab[i]] or '')
            end
            file:write(str..'\n')
          end
        end
      end
    end
  end
  
  function LoadSK2Assign(data)
    --lvar.sk2overlay_assigntab = {'mode','cid','c','tguid','fxguid','fxparam','paramname','sscolor'}
    lvar.sk2overlay_assigntab = {'fxguid','fxparam','paramname','sscolor'}
    local atab = lvar.sk2overlay_assigntab
    local loadmatchstr = '(.-)'
    for i = 2, #atab do
      if i == #atab then
        loadmatchstr = loadmatchstr .. '|(.*)'
      else
        loadmatchstr = loadmatchstr .. '|(.-)'
      end
    end
    for g = 1, 32 do
      for a = 1, 64 do
        local key = 'SK2OL_'..g..'_'..a
        if data[key] then
          local loadtab = {string.match(data[key],loadmatchstr)}
          if loadtab and loadtab[1] then
            if not lvar.sk2overlay.assign[g] then
              lvar.sk2overlay.assign[g] = {}
            end
            
            lvar.sk2overlay.assign[g][a] = {}
            for i = 1, #loadtab do
              if tonumber(loadtab[i]) then
                lvar.sk2overlay.assign[g][a][atab[i]] = tonumber(loadtab[i])
              else
                lvar.sk2overlay.assign[g][a][atab[i]] = loadtab[i]
              end
            end
          end
        end
      end
    end
  
  end
  
  function SK2SaveSlots()
    local str = ''
    str = '[SOLO]'..string.format('%i',lvar.sk2overlay_solo)..'\n'
    str = str..'[HUD]'..string.format('%i',lvar.sk2overlay_hud)..'\n'
    str = str..'[HUDTYPE]'..string.format('%i',lvar.sk2overlay_hudt)..'\n'
    for s = 1, lvar.sk2overlay.slots do
      if lvar.sk2overlay.slot[s] then
        for a, b in pairs(lvar.sk2overlay.slot[s]) do
          local key = '['..s..'_'..a..']'..b..'\n'
          str = str..key
        end
      end
    end
    local fn = paths.resource_path..'sk2slotdata.lbx'
    file=io.open(fn,"w")
    file:write(str)
    file:close()
    
  end

  function SK2LoadSlots()

    local fn = paths.resource_path..'sk2slotdata.lbx'
    if reaper.file_exists(fn) then
      
      local match = string.match
      local data = {}
      local flines = io.lines
      for line in flines(fn) do
        local idx, key, val = match(line,'%[(%d+)_(.-)%](.*)')
        --DBG(tostring(idx)..'  '..tostring(key)..'  '..tostring(val))
        idx = tonumber(idx)
        if idx then
          if not lvar.sk2overlay.slot[idx] then
            lvar.sk2overlay.slot[idx] = {}
          end
          if tonumber(val) then
            lvar.sk2overlay.slot[idx][key] = tonumber(val)
          else
            lvar.sk2overlay.slot[idx][key] = val
          end
        else
          local key, val = match(line,'%[(.-)%](.*)')
          if key == 'SOLO' then
            lvar.sk2overlay_solo = tonumber(val)
          elseif key == 'HUD' then
            lvar.sk2overlay_hud = tonumber(val)
          elseif key == 'HUDTYPE' then
            lvar.sk2overlay_hudt = tonumber(val)
          end
        end
      end
    end
  end
  
  function SendSK2Data()
  
    local sendstr = ''
    sendstr = sendstr..'[SOLO]'..string.format('%i',lvar.sk2overlay_solo)..'\n'
    for s = 1, lvar.sk2overlay.slots do
    
      if lvar.sk2overlay.slot[s] then
        
        local assstring = ''
        local slotstr = lvar.sk2overlay.slot[s].dev..'|'..lvar.sk2overlay.slot[s].name
        if lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp] and lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][s] then
          assstring = lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][s].fxguid..'|'
                      ..lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][s].fxparam..'|'..lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][s].paramname
                      ..'|'..lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp][s].sscolor
        end
        sendstr = sendstr .. '['..slotstr..']'..assstring..'\n'
        
      end
    
    end
    reaper.SetExtState(REMSCRIPT, 'REMOTE_DATA', sendstr, false)
    reaper.SetExtState(REMSCRIPT, 'REMOTE_CTL', 'SK2_SET_STRIPPER_LAYER', false)
    lvar.sk2overlay_active = 1
    
    local xpnl = xPnl.SK2
    xpnl.updategui = true
    
  end

  function SendSK2Data_Enable(enable)
    if enable == 1 then
      SendSK2Data()
      --lvar.cids = CheckAllCids()
      --DBG(strips[tracks[track_select].strip][1].controls[1].c_id)
      --[[for a, b in pairs(lvar.cids) do
        DBG(a)
      end
      DBG('************')]]
    else
      reaper.SetExtState(REMSCRIPT, 'REMOTE_DATA', enable, false)
      reaper.SetExtState(REMSCRIPT, 'REMOTE_CTL', 'SK2_ENABLE_STRIPPER_LAYER', false)
    end
  end
  
  function SK2DropDown(btn)
  
    local ddtab = {btn = btn, bottom = true, hcentre = true, x = mouse.mx, y = mouse.my, w = 200, h = 100, items = {}, itemcol = {}, itemdisabled = {}, indcol = {}, data = {}, wpad = 40, scroll = -1}
          
    local usedidx = {}
    for s = 1, lvar.sk2overlay.slots do
      if lvar.sk2overlay.slot[s] then
        local idx = lvar.sk2overlay.slot[s].map
        if idx then
          usedidx[idx] = 1
        end
      end
    end
    
    for s = 1, #lvar.sk2data_slots do
      local tick = ''
      local idx = lvar.sk2data_slots[s-1].map..'|'..lvar.sk2data_slots[s-1].name
      if lvar.sk2overlay.slot[ddtab.btn] and lvar.sk2overlay.slot[ddtab.btn].map == idx then
        tick = '!'
      end
      ddtab.items[s] = tostring((lvar.sk2data_slots[s-1].map..' | '..lvar.sk2data_slots[s-1].name) or '')
      if usedidx[idx] == 1 then
        ddtab.itemdisabled[s] = true
      end
    
    end
    
    OpenDropDown(11, ddtab, true, true)
  end
  
  
  -------------------------------------------------------



  function Store_ScreenSet(idx)
  
    local ss = lvar.screenset
    ss[idx] = {}
    --sidebar
    ss[idx].plist_w = plist_w
    ss[idx].oplist_w = oplist_w
    ss[idx].show_editbar = show_editbar
    
    --topbar
    ss[idx].hide_topbar = hide_topbar
    ss[idx].topbarheight = topbarheight

    --stripbrowser
    ss[idx].settings_sbdock = settings_sbdock
    ss[idx].sbdockpos = lvar.stripbrowser.dockpos
    ss[idx].sbwin = table.copy(sbwin)
    ss[idx].show_stripbrowser = show_stripbrowser
    ss[idx].sbminw = lvar.stripbrowser.minw
    ss[idx].sbminh = lvar.stripbrowser.minh
    ss[idx].sbshowlabel = lvar.stripbrowser.showlabel
    
    --snapshots
    ss[idx].show_snapshots = show_snapshots
    ss[idx].settings_ssdock = settings_ssdock
    ss[idx].snapshot_win_pos = table.copy(snapshot_win_pos)
    ss[idx].snaph = snaph
    
    --modwin
    ss[idx].settings_moddock = settings_moddock
    ss[idx].modwinsz = table.copy(modwinsz)
    ss[idx].show_lfoedit = show_lfoedit

    --trbtns
    ss[idx].trbtns_size = lvar.trbtns_size
    ss[idx].trmixbtns_size = lvar.trmixbtns_size
    ss[idx].trmix_seth = lvar.trmix_seth
    ss[idx].trmix_h = lvar.trmix_h
    ss[idx].trmix_show = lvar.trmix_show
    ss[idx].trbtns_show = lvar.trbtns_show
    
    --dm/mix mode
    ss[idx].mmov_show = lvar.mmov_show
    ss[idx].mixmodedir = lvar.mixmodedir
    ss[idx].mixmodealign = lvar.mixmodealign
    ss[idx].mmov_vsize = lvar.mmov_vsize

    SaveScreenSets()
  end

  function SaveScreenSets()
    local fn = paths.resource_path..'screensets.lbx'
    local pickdata = pickle(lvar.screenset)
    file=io.open(fn,"w")
    file:write(pickdata)
    file:close()
  end

  function LoadScreenSets()
    local fn = paths.resource_path..'screensets.lbx'
    if reaper.file_exists(fn) then
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      lvar.screenset = unpickle(content)    
    end
  end
  
  function Recall_ScreenSet(idx)
  
    local ss = lvar.screenset

    if ss[idx] then
      --sidebar
      local stripoffx = 0
      if lvar.dm_shiftstripoffset then
        if plist_w ~= ss[idx].plist_w then
          stripoffx = plist_w - ss[idx].plist_w
          if lvar.mixmodedir == 1 then
            surface_offset.mixx = (surface_offset.mixx or 0) - stripoffx
          end
        end
      end
      plist_w = ss[idx].plist_w
      oplist_w = ss[idx].oplist_w
      show_editbar = ss[idx].show_editbar
      
      --topbar
      hide_topbar = ss[idx].hide_topbar
      topbarheight = ss[idx].topbarheight
  
      --stripbrowser
      settings_sbdock = ss[idx].settings_sbdock
      lvar.stripbrowser.dockpos = ss[idx].sbdockpos
      sbwin = table.copy(ss[idx].sbwin)
      show_stripbrowser = ss[idx].show_stripbrowser
      lvar.stripbrowser.minw = ss[idx].sbminw or lvar.stripbrowser.minw
      lvar.stripbrowser.minh = ss[idx].sbminh or lvar.stripbrowser.minh
      lvar.stripbrowser.showlabel = nz(ss[idx].sbshowlabel, lvar.stripbrowser.showlabel)
      obj.sections[1350].x = sbwin.x
      obj.sections[1350].y = sbwin.y
      
      --snapshots
      show_snapshots = ss[idx].show_snapshots
      settings_ssdock = ss[idx].settings_ssdock
      snapshot_win_pos = table.copy(ss[idx].snapshot_win_pos)
      snaph = ss[idx].snaph
      
      --modwin
      settings_moddock = ss[idx].settings_moddock
      modwinsz = table.copy(ss[idx].modwinsz)
      show_lfoedit = ss[idx].show_lfoedit
  
      --trbtns
      lvar.trbtns_size = ss[idx].trbtns_size
      lvar.trmixbtns_size = ss[idx].trmixbtns_size
      lvar.trmix_seth = ss[idx].trmix_seth
      lvar.trmix_h = ss[idx].trmix_h
      lvar.trmix_show = ss[idx].trmix_show
      lvar.trbtns_show = ss[idx].trbtns_show
    
      --dm/mix mode
      lvar.mmov_show = nz(ss[idx].mmov_show, lvar.mmov_show)
      lvar.mixmodedir = ss[idx].mixmodedir or lvar.mixmodedir
      lvar.mixmodealign = ss[idx].mixmodealign or lvar.mixmodealign
      lvar.mmov_vsize = ss[idx].mmov_vsize or lvar.mmov_vsize
      
      obj = GetObjects(obj)
      lvar.reloadsbimages = true
      --GUI_DrawSB_Strips(obj, gui)
      resize_display = true
      lupd.update_gfx = true
      force_resize = true
    
    end
  end

  function LoadBGImage(file_bgimage)

    if file_bgimage then
      if reaper.file_exists(file_bgimage) then

        lvar.bgloaded = gfx.loadimg(978, file_bgimage)

      else
        lvar.bgloaded = -1
      end
    else
      lvar.bgloaded = -1
    end
    if lvar.bgloaded == -1 then
      gfx.setimgdim(978,-1,-1)
      gfx.setimgdim(979,-1,-1)
    else
      local w, h = gfx.getimgdim(978)
      --[[gfx.setimgdim(979,-1,-1)
      gfx.setimgdim(979,lvar.maxdim,lvar.maxdim)]]
      Img_SetDim(979,lvar.maxdim,lvar.maxdim)
      
      gfx.dest = 979
      gfx.a = 1
      f_Get_SSV('0 0 0')
      gfx.rect(0,0,lvar.maxdim,lvar.maxdim,1)
      if lvar.bgstretch then
        gfx.blit(978,1,0,0,0,w,h,0,0,lvar.maxdim,lvar.maxdim)
      else
        for y = 0, math.max(math.ceil(lvar.maxdim/h)-1,1) do
          for x = 0, math.max(math.ceil(lvar.maxdim/w)-1,1) do
            gfx.blit(978,1,0,0,0,w,h,x*w,y*h)
          end
        end
      end
      if lvar.bgbright ~= 0 then
        local m = ((lvar.bgbright+100)/100)
        gfx.dest = 979
        gfx.muladdrect(0,0,lvar.maxdim,lvar.maxdim,m,m,m,1)
        --gfx.rect(0,0,2048,2048,1)
        gfx.a = 1
      end
      lvar.bgloaded = 979
      gfx.dest = 1
    end

  end

  local function TouchFX(track, trguid, fxn, fxguid)
    --[[local pcnt = reaper.TrackFX_GetNumParams(track, fxn)
    local v = reaper.TrackFX_GetParamNormalized(track, fxn, pcnt-1)
    reaper.TrackFX_SetParamNormalized(track, fxn, pcnt-1, v)]]
    if lvar.active_switcher and (lvar.active_switcher.fxguid ~= fxguid or lvar.active_switcher.trguid ~= trguid) then
      lvar.active_switcher.fxguid = fxguid
      lvar.active_switcher.trguid = trguid
      local trnum = reaper.GetMediaTrackInfo_Value(track,'IP_TRACKNUMBER')
      reaper.gmem_attach('LBX_SK2_SharedMem')
      
      reaper.SetExtState('LBX_TOUCHED_FX','TRNUM',trnum,false)
      reaper.SetExtState('LBX_TOUCHED_FX','FXNUM',fxn,false)
      
      reaper.SetExtState('LBX_TOUCHED_FX','FXGUID',fxguid,false)
      reaper.SetExtState('LBX_TOUCHED_FX','TRGUID',trguid,false)
    end
  end

  local function TouchFX_Switcher(switchid)
    if switchers[switchid].fxguids then
      local fxguid = switchers[switchid].fxguids[1]
      if fxguid then
        local track = GetTrack(lvar.dynamicmode_trn)
        if track then
          local trguid = GetTrackGUID(track)
          local fxn = GetFXNFromGUID(track,fxguid)
          if fxn then
            lvar.active_switcher = {switchid = switchid}
            TouchFX(track, trguid, fxn, fxguid)
          end
        end
      end
    end
  end
  

  local function normalize(min, max, val)
    if min and max and val then
      return (val - min)/(max - min)
    else
      return 0
    end
  end

  --nv*(max - min) + min = val
  local function DenormalizeValue(min, max, val)
    if min and max and val then
      return val*(max - min) + min
    else
      return 0
    end
  end

  local function CropToRect(x,y,w,h,l,t,r,b)

    local rr = math.min(x+w, r)
    local bb = math.min(y+h, b)
    x = math.max(x, l)
    y = math.max(y, t)

    w = rr - x
    h = bb - y

    return x, y, w, h

  end

  local function CropToRect2(x,y,w,h,l,t,r,b,px,py,z)

    local rr = math.min(x+w*z, r)
    local bb = math.min(y+h*z, b)
    local xx = math.max(x, l)
    local yy = math.max(y, t)

    local ww = math.max((rr - xx)/z,0)
    local hh = math.max((bb - yy)/z,0)

    local px = px + (xx - x)/z
    local py = py + (yy - y)/z

    return xx, yy, ww, hh, px, py

  end

  function GetTrackFXInfo(stripid, tracknum, swtgt)

    local tfxi = {}
    local tr = GetTrack(tracknum or track_select)
    if tr then
      local fxcnt = reaper.TrackFX_GetCount(tr)
      --[[local ts = track_select
      if lvar.livemode == 2 then
        ts = tracknum
      end]]
      local stripctls = {}

      local strip = tracks[track_select].strip
      if strips[strip] then
        for p = 1, lvar.maxpage do
          ctls = strips[strip][p].controls
          for c = 1, #ctls do
            --DBG(tostring(stripid)..'  '..tostring(ctls[c].switcher))
            if stripid and ctls[c].id
               and ((tracknum == track_select and ctls[c].fxnum) or (ctls[c].tracknum == tracknum and ctls[c].fxnum))
               and ctls[c].id == stripid then
              if lvar.show_addstripdialog == true and lvar.livemode == 2 and ctls[c].switcher then
                local dynplaceholder
                switchid = Switcher_GetTopLevelSwitcher(ctls[c].switcher)
                if switchid then
                  local stripfn = string.match(switchers[switchid].grpids[1].stripfn, '.+[\\/](.*).strip')
                  if stripfn == 'dynamic_placeholder' then
                    dynplaceholder = true
                  end
                end
                if dynplaceholder ~= true then
                  stripctls[ctls[c].fxnum] = 1
                end
              else
                stripctls[ctls[c].fxnum] = 1
              end
            elseif ctls[c].id
               and ((tracknum == track_select and ctls[c].fxnum) or (ctls[c].tracknum == tracknum and ctls[c].fxnum)) then
              if lvar.show_addstripdialog == true and lvar.livemode == 2 and ctls[c].switcher then
                local dynplaceholder
                switchid = Switcher_GetTopLevelSwitcher(ctls[c].switcher)
                if switchid then
                  local stripfn = string.match(switchers[switchid].grpids[1].stripfn or '', '.+[\\/](.*).strip')
                  if stripfn == 'dynamic_placeholder' then
                    dynplaceholder = true
                  end
                end
                if dynplaceholder ~= true and (not swtgt or swtgt ~= switchid) then
                  stripctls[ctls[c].fxnum] = 2
                end
              else
                stripctls[ctls[c].fxnum] = 2
              end
            end
          end
        end
      end

      for i = 0, fxcnt-1 do
        tfxi[i] = {}
        local _, nm = reaper.TrackFX_GetFXName(tr,i,'')
        local _, nm2 = reaper.BR_TrackFX_GetFXModuleName(tr,i,'',64) --bug with video processor
--DBG(i..'  '..nm2)
        tfxi[i].fxname = nm
        tfxi[i].fxfn = nm2
        tfxi[i].fxguid = reaper.TrackFX_GetFXGUID(tr,i)
        tfxi[i].stripinfo = stripctls[i]
      end
    end
    return tfxi
  end

  function GetStripFXInfo(fn, loaddata)
    local tfxi = {}

    if loaddata then
      for i = 1, #loaddata.fx do
        tfxi[i] = {}

        tfxi[i].fxname = GetPlugNameFromChunk2(loaddata.fx[i].fxchunk)
        tfxi[i].fxfn = GetPlugIdentifierFromChunk(loaddata.fx[i].fxchunk)
        tfxi[i].fxguid = '{'..loaddata.fx[i].fxguid..'}'

        --DBG(i..'  '..tostring(tfxi[i].fxname)..'  '..tfxi[i].fxfn)

      end
    end
    return tfxi
  end

  function PopReadPeaks()
    local readpeaks = {}
    lvar.readpeaks_sel = nil
    if tracks[track_select].strip and strips[tracks[track_select].strip] then
      local ctls = strips[tracks[track_select].strip][page].controls
      local cnt = 1
      local rpidx = {}
      for c = 1, #ctls do
        local ctl = ctls[c]
        if ctl.ctlcat == ctlcats.pkmeter then
          local trn = ctl.tracknum or track_select
          if trn == -3 then
            lvar.readpeaks_sel = 1
          elseif trn and rpidx[trn] ~= 1 then
            readpeaks[cnt] = trn
            rpidx[trn] = 1
            cnt = cnt + 1
          end
        end
      end
      readpeaks.idx = rpidx
    end
    return readpeaks
  end

  ---------------------------------------------------------------------------

  function Progress(txt, bar)

    --[[gfx.dest = 1
    local w, h = 200, 50
    local xywh = {x = math.floor(gfx1.main_w/2 - w/2),
                  y = gfx1.main_h - h -20,
                  w = w,
                  h = h}
    f_Get_SSV('64 64 64')
    gfx.rect(xywh.x, xywh.y, xywh.w, xywh.h, 1)
    GUI_Str(gui, xywh, txt, 5, gui.color.white, 0, 1, '0 0 0', gui.fontnm.butt, gui.fontflag.butt)
    f_Get_SSV('200 50 100')
    gfx.rect(xywh.x+10, xywh.y+xywh.h-8, (xywh.w-20)*bar, 2, 1)

    gfx.dest = -1
    gfx.a = 1
    gfx.blit(1, 1, 0,
      0,0, gfx1.main_w,gfx1.main_h,
      0,0, gfx1.main_w,gfx1.main_h, 0,0)
    --gfx.update()]]
    --DBG(bar)

    if reaper.JS_Window_Find then
      local w, h = 200, 50
      local xywh = {x = math.floor(gfx1.main_w/2 - w/2),
                        y = gfx1.main_h - h -20,
                        w = w,
                        h = h}

      local wid = reaper.JS_Window_Find('- LBX Stripper -',true)
      local wdc = reaper.JS_GDI_GetClientDC(wid)

      local col = reaper.JS_GDI_CreateFillBrush(8289919)
      local col2 = reaper.JS_GDI_CreateFillBrush(0)
      local pen0 = reaper.JS_GDI_CreatePen(1, 0)
      local pen = reaper.JS_GDI_CreatePen(2, 0xFF8000)
      local fnt = reaper.JS_GDI_CreateFont(20, 1, 0, false, false, false, 'Calibri')
      reaper.JS_GDI_SelectObject(wdc, fnt)
      reaper.JS_GDI_SetTextBkMode(wdc, 0)
      reaper.JS_GDI_SetTextColor(wdc, 0)

      reaper.JS_GDI_SelectObject(wdc, pen0)
      reaper.JS_GDI_SelectObject(wdc, col)
      reaper.JS_GDI_FillRoundRect(wdc, xywh.x, xywh.y, xywh.x+xywh.w, xywh.y+xywh.h, 20, 20)
      reaper.JS_GDI_SelectObject(wdc, col2)
      if bar > 0 then
        reaper.JS_GDI_SelectObject(wdc, pen)
        reaper.JS_GDI_FillRect(wdc, xywh.x+10, xywh.y+xywh.h-10, math.floor(xywh.x+((xywh.w-20)*bar)),xywh.y+xywh.h-8)
      end
      reaper.JS_GDI_DrawText(wdc, txt, string.len(txt), xywh.x, xywh.y+10, xywh.x+xywh.w, xywh.y+xywh.h, 'VCENTER HCENTER')

      reaper.JS_GDI_DeleteObject(col)
      reaper.JS_GDI_DeleteObject(col2)
      reaper.JS_GDI_DeleteObject(pen)
      reaper.JS_GDI_DeleteObject(fnt)
      reaper.JS_GDI_ReleaseDC(wid, wdc)

      gfx.update()

    end

  end

  function SetFaderBoxVal(i, v)

    if LBX_CTL_TRACK then
      local track = GetTrack(LBX_CTL_TRACK)
      if track then
        local fxnum = 0
        reaper.TrackFX_SetParamNormalized(track, fxnum, i-1, v)
      end
    end

  end

  function Undo_Set(keytab, infostr, undotypeflag)

    --local t = reaper.time_precise()
    if undo.max > 0 then
      local upos = undo_pos+1
      undo.latch = true
      if ctl_select and #ctl_select > 0 then

        if undotypeflag == lvar.undotypeflag_table.delete then
          ctl_select = table_slowsort_gen(ctl_select,'ctl')
        end

        for i = 1, #ctl_select do
          local c = ctl_select[i].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          upos = Undo_Store(upos, undo_types.ctl, tracks[track_select].strip, page, c, ctl.c_id, ctl, keytab, infostr, undotypeflag)
        end
      end
      if gfx4_select and #gfx4_select > 0 then

        if undotypeflag == lvar.undotypeflag_table.delete then
          table.sort(gfx4_select)
        end

        for i = 1, #gfx4_select do
          local c = gfx4_select[i]
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          upos = Undo_Store(upos, undo_types.gfx, tracks[track_select].strip, page, c, ctl.g_id, ctl, keytab, infostr, undotypeflag)
        end
      end
      if gfx3_select and #gfx3_select > 0 then

        if undotypeflag == lvar.undotypeflag_table.delete then
          gfx3_select = table_slowsort_gen(gfx3_select,'ctl')
        end

        for i = 1, #gfx3_select do
          local c = gfx3_select[i].ctl
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          upos = Undo_Store(upos, undo_types.gfx, tracks[track_select].strip, page, c, ctl.g_id, ctl, keytab, infostr, undotypeflag)
        end
      end
      undo_pos = upos
    end
    --DBG(reaper.time_precise()-t)
  end

  function Undo_Store(idx, utype, strip, page, ctl, cid, data, keytab, infostr, undotypeflag)

    local ucnt = #undo
    for i = idx+1, ucnt do
      undo[i] = nil
    end

    if idx > undo.max then
      local tbl = {}
      for i = 2, undo.max do
        table.insert(tbl, undo[i])
      end
      local max = undo.max
      undo = tbl
      undo.max = max
      idx = undo.max
    end

    if not undo[idx] or undo.latch == true then
      undo[idx] = {}
      undo.latch = nil
    end
    undo[idx].infostr = infostr
    undo[idx].utypeflag = undotypeflag

    if not undotypeflag then
      if keytab == nil then
        undo[idx][#undo[idx]+1] = {utype = utype,
                                  strip = strip,
                                  page = page,
                                  ctl = ctl,
                                  cid = cid,
                                  data = table.deepcopy(data)}
      else
        local dtbl = {}
        undo[idx][#undo[idx]+1] = {utype = utype,
                                  strip = strip,
                                  page = page,
                                  ctl = ctl,
                                  cid = cid,
                                  keytab = keytab,
                                  data = dtbl}
        for i = 1, #keytab do
          local key = keytab[i]
          if (type(data[key]) == "table") then
            dtbl[i] = table.deepcopy(data[key])
          else
            dtbl[i] = data[key]
          end
        end
      end
    else
      if undotypeflag == lvar.undotypeflag_table.delete then
        undo[idx][#undo[idx]+1] = {utype = utype,
                                  strip = strip,
                                  page = page,
                                  ctl = ctl,
                                  cid = cid,
                                  data = table.deepcopy(data)}
      end
    end
    lupd.update_cbox = true

    return idx
  end

  function Undo_Recall(idx)

    if idx and idx > 0 then

      local ctype, gtype

      local utf = undo[idx].utypeflag

      for u = 1, #undo[idx] do

        local utype = undo[idx][u].utype
        if utype == undo_types.ctl then

          ctype = true
          local strip = undo[idx][u].strip
          local p = undo[idx][u].page
          local c = undo[idx][u].ctl
          local cid = undo[idx][u].cid
          local data = undo[idx][u].data
          local keytab = undo[idx][u].keytab

          if utf == nil then
            if strips[strip] then
              local ctls = strips[strip][p].controls
              if (ctls[c] and ctls[c].c_id ~= cid) or ctls[c] == nil then
                c = -1
                for i = 1, #ctls do

                  if ctls[i].c_id == cid then
                    c = i
                    undo[idx][u].ctl = i
                    break
                  end

                end
              end

              if c ~= -1 then
                lupd.update_gfx = true
                lupd.update_ctlopts = true

                if keytab == nil then
                  undo[idx][u].redodata = table.deepcopy(ctls[c])
                  ctls[c] = table.deepcopy(data)
                else
                  local dtbl = {}
                  for i = 1, #keytab do
                    local key = keytab[i]
                    if (type(ctls[c][key]) == "table") then
                      dtbl[i] = table.deepcopy(ctls[c][key])
                      ctls[c][key] = table.deepcopy(data[i])
                    else
                      dtbl[i] = ctls[c][key]
                      ctls[c][key] = data[i]
                    end
                  end
                  undo[idx][u].redodata = dtbl
                end
              end

            end
          elseif utf == lvar.undotypeflag_table.delete then
            if strips[strip] then
              local ctls = strips[strip][p].controls
              table.insert(ctls, c, data)
              lupd.update_gfx = true
            end
          end

        elseif utype == undo_types.gfx then

          gtype = true
          local strip = undo[idx][u].strip
          local p = undo[idx][u].page
          local c = undo[idx][u].ctl
          local cid = undo[idx][u].cid
          local data = undo[idx][u].data
          local keytab = undo[idx][u].keytab

          if utf == nil then
            if strips[strip] then
              local ctls = strips[strip][p].graphics
              if (ctls[c] and ctls[c].g_id ~= cid) or ctls[c] == nil then
                c = -1
                for i = 1, #ctls do

                  if ctls[i].g_id == cid then
                    c = i
                    undo[idx][u].ctl = i
                    break
                  end

                end
              end

              if c ~= -1 then
                lupd.update_gfx = true
                lupd.update_bg = true

                if keytab == nil then
                  undo[idx][u].redodata = table.deepcopy(ctls[c])
                  ctls[c] = table.deepcopy(data)
                else
                  local dtbl = {}
                  for i = 1, #keytab do
                    local key = keytab[i]
                    if (type(ctls[c][key]) == "table") then
                      dtbl[i] = table.deepcopy(ctls[c][key])
                      ctls[c][key] = table.deepcopy(data[i])
                    else
                      dtbl[i] = ctls[c][key]
                      ctls[c][key] = data[i]
                    end
                  end
                  undo[idx][u].redodata = dtbl
                end
              end

            end
          elseif utf == lvar.undotypeflag_table.delete then
            if strips[strip] then
              local ctls = strips[strip][p].graphics
              table.insert(ctls, c, data)
              lupd.update_gfx = true
            end
          end

        end
      end

      if utf == lvar.undotypeflag_table.delete then
        CheckDataTables(true)
        ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      end
      movefrom_sc = nil
      SetCtlBitmapRedraw()
      if gtype then
        glob_gfxselrect = CalcGFX4SelRect()
        if show_gfxoptions and gfx4_select then
          SetGfx4SelectVals2()
        elseif show_lbloptions then
          SetGfx4SelectVals()
        end
      end
      if ctype then
        if show_ctloptions and ctl_select ~= nil then
          SetCtlSelectVals()
        end
      end
      return idx - 1
    end
  end

  function Undo_Redo(idx)

    if idx and idx > 0 then

      local ctype, gtype
      local utf = undo[idx].utypeflag
      local deltab = {}
      local deltabidx = {}
      local ccnt, gcnt

      for u = 1, #undo[idx] do

        local utype = undo[idx][u].utype
        if utype == undo_types.ctl then

          ctype = true
          local strip = undo[idx][u].strip
          local p = undo[idx][u].page
          local c = undo[idx][u].ctl
          local cid = undo[idx][u].cid
          local data = undo[idx][u].redodata
          local keytab = undo[idx][u].keytab

          if utf == nil then

            if strips[strip] and data then

              local ctls = strips[strip][p].controls
              if (ctls[c] and ctls[c].c_id ~= cid) or ctls[c] == nil then
                c = -1
                for i = 1, #ctls do

                  if ctls[i].c_id == cid then
                    c = i
                    undo[idx][u].ctl = i
                    break
                  end

                end
              end

              if c ~= -1 then
                lupd.update_gfx = true
                lupd.update_ctlopts = true
                if keytab == nil then
                  ctls[c] = table.deepcopy(data)
                else
                  for i = 1, #keytab do
                    local key = keytab[i]
                    if (type(ctls[c][key]) == "table") then
                      ctls[c][key] = table.deepcopy(data[i])
                    else
                      ctls[c][key] = data[i]
                    end
                  end
                end
              end
            end

          elseif utf == lvar.undotypeflag_table.delete then

            local ctls = strips[strip][p].controls
            local key = 's'..strip..'p'..p
            if not deltabidx[key] then
              deltabidx[key] = #deltab+1
              deltab[#deltab+1] = {strip = strip, page = p, ccnt = #ctls}
            elseif not deltab[deltabidx[key]].ccnt then
              deltab[deltabidx[key]].ccnt = #ctls
            end
            ctls[c] = nil
            lupd.update_gfx = true
          end

        elseif utype == undo_types.gfx then

          gtype = true
          local strip = undo[idx][u].strip
          local p = undo[idx][u].page
          local c = undo[idx][u].ctl
          local cid = undo[idx][u].cid
          local data = undo[idx][u].redodata
          local keytab = undo[idx][u].keytab

          if utf == nil then
            if strips[strip] and data then

              local ctls = strips[strip][p].graphics
              if (ctls[c] and ctls[c].g_id ~= cid) or ctls[c] == nil then
                c = -1
                for i = 1, #ctls do

                  if ctls[i].g_id == cid then
                    c = i
                    undo[idx][u].ctl = i
                    break
                  end

                end
              end

              if c ~= -1 then
                lupd.update_gfx = true
                lupd.update_bg = true
                if keytab == nil then
                  ctls[c] = table.deepcopy(data)
                else
                  for i = 1, #keytab do
                    local key = keytab[i]
                    if (type(ctls[c][key]) == "table") then
                      ctls[c][key] = table.deepcopy(data[i])
                    else
                      ctls[c][key] = data[i]
                    end
                  end
                end
              end

            end

          elseif utf == lvar.undotypeflag_table.delete then
            local ctls = strips[strip][p].graphics
            local key = 's'..strip..'p'..p
            if not deltabidx[key] then
              deltabidx[key] = #deltab+1
              deltab[#deltab+1] = {strip = strip, page = p, gcnt = #ctls}
            elseif not deltab[deltabidx[key]].gcnt then
              deltab[deltabidx[key]].gcnt = #ctls
            end
            ctls[c] = nil
            lupd.update_gfx = true

          end

        end
      end

      if utf == lvar.undotypeflag_table.delete then
        ctl_select = nil
        gfx4_select = nil
        gfx3_select = nil
        for i = 1, #deltab do
          local strip = deltab[i].strip
          local page = deltab[i].page
          local ccnt = deltab[i].ccnt
          local gcnt = deltab[i].gcnt
          if ccnt then
            strips[strip][page].controls = Table_RemoveNils(strips[strip][page].controls,ccnt)
          end
          if gcnt then
            strips[strip][page].graphics = Table_RemoveNils(strips[strip][page].graphics,gcnt)
            lupd.update_bg = true
          end
        end
        ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      end

      movefrom_sc = nil
      SetCtlBitmapRedraw()
      if gtype then

        glob_gfxselrect = CalcGFX4SelRect()
        if show_gfxoptions then
          SetGfx4SelectVals2()
        elseif show_lbloptions then
          SetGfx4SelectVals()
        end
      end
      if ctype then
        if show_ctloptions and ctl_select ~= nil then
          SetCtlSelectVals()
        end
      end

      return idx
    end
  end

  function CheckUpdater()

    local up, git, clone
    if reaper.file_exists(paths.update_path..'lbx_updater.lua') == true then
      up = true
    end
    if reaper.file_exists(paths.update_path..'git_upload.lua') == true then
      git = true
    end
    if reaper.file_exists(paths.update_path..'git_clone.lua') == true then
      clone = true
    end
    return up, git, clone

  end

  function GetFileName(url)
    return url:match("^.+/(.+)$")
  end

  function GetFileExtension(url)
    return url:match("^.+(%..+)$")
  end

  function UploadToGit()

    if lvar.git == true then
      if reaper.MB('Upload LBX Stripper to GitHub?','GitUpload',1) == 1 then
        os.execute(string.sub(paths.update_path,1,2)..'&cd "'..paths.update_path..'"&lua.exe "'..paths.update_path..'git_upload.lua"')
      end
    end

  end

  function GitClone()

    if lvar.gitclone == true then
      if reaper.MB('Clone LBX Stripper to E:\\GIT_LBX?','GitClone',1) == 1 then
        os.execute(string.sub(paths.update_path,1,2)..'&cd "'..paths.update_path..'"&lua.exe "'..paths.update_path..'git_clone.lua"')
      end
    end

  end

  function RollbackMenu(mx, my)

    local mstr = '>Rollback <LBX Stripper.lua> to a previous version'
    local dir = paths.resource_path..'updater/oldversions/'
    local f = 0
    local fn = reaper.EnumerateFiles(dir, f)
    local rbfiles = {}
    local skip = 0
    if fn then
      local ffcnt = 0
      while fn do
        if string.match(fn,'LBX Stripper_%x_%x%x_%x%x%x%x.lua') then
          ffcnt = ffcnt + 1
        end
        f = f + 1
        fn = reaper.EnumerateFiles(dir, f)
      end
      if ffcnt > 0 then
        f = f - 1
        local fcnt = f
        fn = reaper.EnumerateFiles(dir, f)

        while fn do

          if string.match(fn,'LBX Stripper_%x_%x%x_%x%x%x%x.lua') then
            rbfiles[#rbfiles+1] = fn
            mstr = mstr .. '|' .. fn
            skip = skip + 1
          end
          f = f - 1
          fn = reaper.EnumerateFiles(dir, f)

        end
        mstr = string.gsub(mstr,'(.+)(%|)(.*)','%1|<%3')

      else
        mstr = mstr .. '|<#Empty'
        skip = 1
      end
    else
      mstr = mstr .. '|<#Empty'
      skip = 1
    end
    if lvar.git then
      mstr = mstr .. '||Upload to GitHub'
    end
    if lvar.gitclone then
      mstr = mstr .. '||Clone from GitHub'
    end
    gfx.x, gfx.y = mx, my
    local res = gfx.showmenu(mstr)
    if res ~= 0 then
      if res <= skip then
        --DBG(rbfiles[res])
        RollbackUpdate(rbfiles[res])
      elseif res == 1+skip then
        UploadToGit()
      elseif res == 2+skip then
        GitClone()
      end
    end
  end


  function RollbackUpdate(ffn)

    if reaper.MB('Rollback LBX Stripper to version: '..ffn..'?','Rollback',1) == 1 then

      local err = 0
      local f = 0
      local dir = paths.resource_path..'updater/oldversions/'
      local path = reaper.GetResourcePath().."/Scripts/LBX/"

      if reaper.file_exists(dir..ffn) then

        -- rollback version
        local file = io.open(dir..ffn, 'rb')
        local body
        if file then
          body = file:read('*a')
          file:close()
        else
          err = 4
        end

        local fn = 'LBX Stripper.lua'
        -- current version
        local file = io.open(path..fn, 'rb')
        local curr
        if file then
          curr = file:read('*a')
          file:close()
        else
          err = 3
        end

        if curr and curr ~= body then
          --backup current
          local bfn = fn
          if lvar.scriptver then

            local ver = string.gsub(lvar.scriptver,'%.','_')
            if ver then
              local bfn = 'LBX Stripper_'..ver..'.lua'
              if not reaper.file_exists(dir..bfn) then
                file = io.open(dir..bfn, 'wb')
                if file then
                  file:write(curr)
                  file:close()
                end
              end
            end
          end
        end

        file = io.open(path..fn, 'wb')
        if file then
          file:write(body)
          file:close()
        else
          err = 3
        end

      else
        err = 2
      end

      if err == 0 then
        OpenMsgBox(1, 'Please restart the script.', 1)
      elseif err == 1 then
        OpenMsgBox(1, 'Backup version is the same as installed version.', 1)
      elseif err == 2 then
        OpenMsgBox(1, 'File not found.', 1)
      elseif err == 3 then
        OpenMsgBox(1, 'Unable to open destination file.', 1)
      elseif err == 4 then
        OpenMsgBox(1, 'Unable to open source file.', 1)
      end

    end

  end

  function RunUpdater()

    if lvar.updateravailable == true then

      if reaper.MB('Update LBX Stripper to latest version?','Update',1) == 1 then

        --os.execute('"'..paths.update_path..'Run_Updater.bat"')
        --os.execute('start "'..paths.update_path..'lua.exe" "'..paths.update_path..'lbx_updater.lua"')
        os.execute(string.sub(paths.update_path,1,2)..'&cd "'..paths.update_path..'"&lua.exe "'..paths.update_path..'lbx_updater.lua"')

        OpenMsgBox(1,'Assuming that all went well - please reopen the script :)',1)
      end
    end

  end

  function InsertTrackUtil(trn, trguid)

    local track = GetTrack(trn)
    local fnd = false

    if track then
      if trguid ~= GetTrackGUID(track) then
        for i = -1, reaper.CountTracks(0) do
          track = GetTrack(i)
          if track then
            if trguid == GetTrackGUID(track) then
              trn = i
              fnd = true
              break
            end
          end
        end
      else
        fnd = true
      end
    else
      for i = -1, reaper.CountTracks(0) do
        track = GetTrack(i)
        if track then
          if trguid == GetTrackGUID(track) then
            trn = i
            fnd = true
            break
          end
        end
      end
    end

    if track and fnd == true then
      local fxcnt = reaper.TrackFX_GetCount(track)

      local fnd = -1
      for i = 0, fxcnt do
        local _,n = reaper.TrackFX_GetFXName(track,i,'')
        if n == 'JS: LBX Track Utility' or n == 'JS: LBX_TrackUtility' then
          fnd = i
          break
        end
      end

      if fnd == -1 then
        local chunk = GetTrackChunk(track,true)
        local insfxchunk = lvar.lbxutil_chunk
        local nchunk, nguid = Chunk_InsertFXChunkAtEndOfFXChain(trn,chunk,insfxchunk)
        fxcnt = fxcnt + 1

        --Move to top

        if fxcnt > 1 then
          nchunk = MoveFXChunk2(nchunk, trn, fxcnt, 1, fxcnt)
        end

        if nchunk then
          SetTrackChunk(track, nchunk, false)
        end
        return 0,nguid,trn
      else
        local guid = reaper.TrackFX_GetFXGUID(track,fnd)
        return fnd, guid, trn
      end
    else
      DBG('Track not found!')
    end

  end

  -----------------------------------
  --Thanks Eugen for this fix
  function GetTrackChunk(track, usefix)
    if not track then return end
    local track_chunk


    if usefix == true and reaper.APIExists('SNM_CreateFastString') == true then

      local fast_str = reaper.SNM_CreateFastString("")
      if reaper.SNM_GetSetObjectState(track, fast_str, false, false) then
        track_chunk = reaper.SNM_GetFastString(fast_str)
      end
      reaper.SNM_DeleteFastString(fast_str)
    else
      _, track_chunk = reaper.GetTrackStateChunk(track,'',false)
    end
    return track_chunk
  end

  function SetTrackChunk(track, track_chunk, usefix)
    usefix = false --force as fix isn't needed
    if not (track and track_chunk) then return end
    local ret

    if usefix == true then
      track_chunk2 = string.gsub(track_chunk,"<PROGRAMENV.->\n","")
      if track_chunk2 ~= track_chunk then
        local fast_str = reaper.SNM_CreateFastString("")
        if reaper.SNM_SetFastString(fast_str, track_chunk2) then
          ret = reaper.SNM_GetSetObjectState(track, fast_str, true, false)
        end
        reaper.SNM_DeleteFastString(fast_str)
      end

      local fast_str = reaper.SNM_CreateFastString("")
      if reaper.SNM_SetFastString(fast_str, track_chunk) then
        ret = reaper.SNM_GetSetObjectState(track, fast_str, true, false)
      end
      reaper.SNM_DeleteFastString(fast_str)
    else
      track_chunk2 = string.gsub(track_chunk,"<PROGRAMENV.->\n","")
      if track_chunk2 ~= track_chunk then
        ret = reaper.SetTrackStateChunk(track,track_chunk2,false)
      end
      ret = reaper.SetTrackStateChunk(track,track_chunk,false)
    end
    return ret
  end

  -----------------------------------

  function cfact(n) if n == 0 then return 1 else return n * cfact(n-1) end end

 -- mpl draw Bézier curve

  function draw_curve(x_table, y_table, pt, last)
    order = #x_table
    ----------------------------
    ----------------------------
    function bezier_eq(n, tab_xy, dt)
      local B = 0
      for i = 0, n-1 do
        B = B +
          ( fact[n] / ( fact[i] * fact[n-i] ) )
          *  (1-dt)^(n-i)
          * dt ^ i
          * tab_xy[i+1]
      end
      return B
    end
    ----------------------------
    function draw_points(x,y, pt, last)
      local point_side = 5
      gfx.set(0,0.8,0,0.4)
      local xx = {}
      local yy = {}
      for i = 1, #x do
        xx[i] = (x[i]*obj.sections[220].w)
        yy[i] = (y[i]*obj.sections[220].h)
      end

      for i = 1, #x do
        if i == 1 or i == 4 then
          if pt == 1 and i == 1 then
            f_Get_SSV('0 255 0')
          elseif pt == last and i == 4 then
            f_Get_SSV(gui.color.red)
          else
            f_Get_SSV(gui.color.yellow)
          end
          gfx.a=1
          gfx.circle(xx[i] ,yy[i] ,point_side,1, 1)
        else
          gfx.a = 0.2
          if i == 2 then
            f_Get_SSV(gui.color.blue)
            gfx.line(xx[1],yy[1],xx[2],yy[2],1)
          else
            f_Get_SSV(gui.color.blue)
            gfx.line(xx[4],yy[4],xx[3],yy[3],1)
          end
          gfx.a = 1
          f_Get_SSV('255 0 255')
          gfx.rect(xx[i] -point_side/2 ,yy[i] -point_side/2,point_side,point_side,1, 1)
        end
      end
    end
    ----------------------------
    local ox,oy = nil, nil
    if xxymode == 0 then
      f_Get_SSV('0 32 0')
    else
      f_Get_SSV('0 128 0')
    end
    for t = 0, 1, 0.01 do
      x_point = bezier_eq(order, x_table, t)+ t^order*x_table[order]
      y_point = bezier_eq(order, y_table, t)+ t^order*y_table[order]
      x = (x_point*obj.sections[220].w)
      y = (y_point*obj.sections[220].h)
      if ox and oy then
        gfx.a = 1
        --gfx.setpixel(1,1,1)
        gfx.line(ox,oy,x,y,1)
      end
      ox,oy = x,y
    end
    if xxymode == 1 and xxypath_edit then
      draw_points(x_table, y_table, pt, last)
    end
  end

  function curve_getxy(x_table, y_table, t)
    order = #x_table
    ----------------------------
    function bezier_eq(n, tab_xy, dt)
      local B = 0
      for i = 0, n-1 do
        B = B +
          ( fact[n] / ( fact[i] * fact[n-i] ) )
          *  (1-dt)^(n-i)
          * dt ^ i
          * tab_xy[i+1]
      end
      return B
    end
    ----------------------------
    x_point = bezier_eq(order, x_table, t)+ t^order*x_table[order]
    y_point = bezier_eq(order, y_table, t)+ t^order*y_table[order]
    return x_point, y_point
  end

  -----------------------------------
  -----------------------------------

  local log10 = function(x) return math.log(x, 10) end

  function get_peak_info(trn)
--DBG(trn)
    local tr
    if trn == -1 then
      tr = reaper.GetMasterTrack(0)
    else
      tr = reaper.GetTrack(0, trn)
    end
    if tr then
      local nchan = reaper.GetMediaTrackInfo_Value(tr, 'I_NCHAN')
      peak_info[trn] = {}
      local pk, peak_info_ch, peak_info_dB = 0
      for i = 0, nchan-1 do
        local peak_info_ch = reaper.Track_GetPeakInfo(tr, i)
        local peak_info_dB = 20*log10(peak_info_ch)
        local pk = 0
        if peak_info_dB > 0 then
          pk = 1
        end
        peak_info[trn][i] = {ch = normalize(-60,0,F_limit(peak_info_dB,-60,0)),
                             pk = pk,
                             ch_d = peak_info_dB}
      end
    end
  end

  function copyfile(src, dest)
    local file = io.open(src, 'rb')
    if file then
      local content = file:read('*a')
      file:close()
      local file = io.open(dest, 'wb')
      file:write(content)
      file:close()
    end
  end

  function readbinaryfile(src)
    local file = io.open(src, 'rb')
    local content = file:read('*a')
    file:close()
    return content
  end

  function writebinaryfile(dest, content)
    local file = io.open(dest, 'wb')
    file:write(content)
    file:close()
  end

  function MoveGFXFileToFolder(file, folder)

    if graphics_files[graphics_folder_files[file]] then
      local srcfol = ''
      if graphics_files[graphics_folder_files[file]].fol ~= 'GENERAL' then
        srcfol = graphics_files[graphics_folder_files[file]].fol..'/'
      end
      local chkdfol = graphics_folders[folder]

      local srcfn = paths.graphics_path..srcfol..graphics_files[graphics_folder_files[file]].fn
      --do nothing if file not exists or src and dest folders match
      if chkdfol ~= graphics_files[graphics_folder_files[file]].fol and reaper.file_exists(srcfn) then
        local dstfol = ''
        local dfol = ''
        if folder ~= 0 then
          dstfol = graphics_folders[folder]..'/'
          dfol = graphics_folders[folder]
        end

        local dstfn = paths.graphics_path..dstfol..graphics_files[graphics_folder_files[file]].fn
        copyfile(srcfn, dstfn)
        os.remove(srcfn)

        if folder == 0 then
          graphics_files[graphics_folder_files[file]].fol = 'GENERAL'
        else
          graphics_files[graphics_folder_files[file]].fol = dfol
        end
        PopGfxFolder(gfxfol_select)
        lupd.update_gfx = true
      else
        --DBG('file not found')
      end

    end

  end

  function StripData_ReadSnapContent(sdata)

    local snapdata = {}
    if sdata.version >= 4 and sdata.snapcontent then
      local snapcontent = sdata.snapcontent
      local data = {}
      local cnt = 0
      local lines = splitln(snapcontent)
      if lines and #lines > 0 then
        for ln = 1, #lines do
          local idx, val = string.match(lines[ln],'%[(.-)%](.*)')
          if idx then
            data[idx] = val
          end
        end
      end
      snapdata = LoadSnapDataX(nil,data)
    end
    return snapdata

  end

  function StripShare_Export(fol, fn, dfol)

    savefn = fn

    local stripdata, stripfilecontent = LoadStripFN(fol..fn, nil, true)
    if stripdata.version and stripdata.version >= 4 then
      if stripdata.snapcontent then
        local snapd = StripData_ReadSnapContent(stripdata)
        if snapd then
          stripdata.snapshots = snapd
        end
      end
    else
      OpenMsgBox(1,'Please open and resave the strip file in the new strip format',1, 'before creating a stripshare file.')
      return
    end

    local gfxchk = {}
    local ctlchk = {}
    local gfxf = {}
    local ctlf = {}

    if stripdata.strip.graphics then
      local gfxidx = PopulateGFXIdx()
      for g = 1, #stripdata.strip.graphics do
        local gx = stripdata.strip.graphics[g]
        local idx = gfxidx[gx.fn]
        if idx then
          local gfn
          if graphics_files[idx].fol == 'GENERAL' then
            gfn = graphics_files[idx].fn
          else
            gfn = graphics_files[idx].fol..'/'..graphics_files[idx].fn
          end
          if gx.gfxtype == lvar.gfxtype.img and reaper.file_exists(paths.graphics_path..gfn) then
            if gfxchk[gx.fn] == nil then
              gfxchk[gx.fn] = true
              local imgbin = readbinaryfile(paths.graphics_path..gfn)
              gfxf[#gfxf+1] = {fn = gx.fn, bindata = imgbin}
            end
          end
        end
      end
    end
    if stripdata.strip.controls then
      for c = 1, #stripdata.strip.controls do
        local cx = stripdata.strip.controls[c]
        if nz(cx.ctl_info.fn,'') ~= '' and reaper.file_exists(paths.controls_path..cx.ctl_info.fn) then
          local knbfn = string.match(cx.ctl_info.fn, '(.+)%.') ..'.knb'

          if reaper.file_exists(paths.controls_path..knbfn) then
            if ctlchk[cx.ctl_info.fn] == nil then
              ctlchk[cx.ctl_info.fn] = true
              local imgbin = readbinaryfile(paths.controls_path..cx.ctl_info.fn)
              local knbbin = readbinaryfile(paths.controls_path..knbfn)
              ctlf[#ctlf+1] = {fn = cx.ctl_info.fn, bindata = imgbin, knbdata = knbbin}
            end
          end
        end
      end
    end

    --browser image
    local sbfn = fol..string.match(fn,'(.+)%..*')..'.png'
    local sbdata
    if reaper.file_exists(paths.strips_path..sbfn) then
      local imgbin = readbinaryfile(paths.strips_path..sbfn)
      sbdata = {bindata = imgbin}
    end
    stripdata.sharedata = {stripfn = fn, ctls = ctlf, gfx = gfxf, sbdata = sbdata}

    local save_path=paths.share_path..'/'..(dfol or '')..'/'
    reaper.RecursiveCreateDirectory(save_path,1)
    
    local fn=save_path..string.match(savefn,'(.+)%.')..".sharestrip"

    local DELETE=true
    local file

    if reaper.file_exists(fn) then

    end

    if DELETE then

      local pickledsharedata=pickle(stripdata.sharedata)
      file=io.open(fn,"w")

      file:write('[SHARESTRIPFILE_VERSION]2\n')
      file:write('[SHAREDATA]\n'..pickledsharedata..'\n[\\SHAREDATA]\n')
      file:write('[SHARESTRIPDATA]\n')
      file:write(stripfilecontent)
      file:write('[\\SHARESTRIPDATA]\n')

      --local pickled_table=pickle(stripdata)
      --file:write(pickled_table)

      file:close()
    end


    OpenMsgBox(1,'Strip share file saved.',1)

  end

  function CompareStringToFile(str, fn)

    local fil = readbinaryfile(fn)
    local ret = false
    if fil == str then
      ret = true
    end
    return ret

  end

  function TestStuff()

    local gfxv = 1
    local fn = 'testttt.sharestrip'
    local tt = string.match(fn,'(.+)_v%d%d%d%d')
    local sfx = string.match(fn,'.+(%..*)')
    if tt == nil then
      tt = fn
    else
      tt = tt .. sfx
    end
    --tt = tt .. '_v'.. string.format('%04d',gfxv) .. string.match(fn,'.+(%..*)')
    DBG(tt)

  end

  function BatchImportShareStrips()
  
    local retval, fol = reaper.JS_Dialog_BrowseForFolder('Import Share Strips - Select folder', '')
    if retval == 1 then
    
      local fol1 = string.match(fol,".+[\\/](.*)")
      local f = 0
      local c = 0
      local sfn = reaper.EnumerateFiles(fol, f)
      while sfn do
    
        if string.match(sfn,'.+%.(.*)$') == 'sharestrip' then
          DBG('Importing: '..sfn)
          StripShare_Import(fol..'/'..sfn, fol1, true)          
          c=c+1
        end
    
        f=f+1
        sfn = reaper.EnumerateFiles(fol, f)
      end
      
      PopulateStripFolders(lvar.sortcontrols)
      PopulateStrips(lvar.sortcontrols)
      lupd.update_gfx = true
      
      DBG(string.format('%i',c)..' strip files imported')
    end
  
  end

  function StripShare_Import(fn, fol, verbose)

    local savefn
    local loadfn, path
    DBGOut('IMPORT SHARESTRIP - Get Filename')
    local retval = true
    
    if (fn or '') == '' then
      retval, fn = reaper.GetUserFileNameForRead(paths.share_path..'*', 'Load Strip Share File', '.sharestrip')
    end
    if retval then

      DBGOut('IMPORT SHARESTRIP - Retval True')

      if reaper.file_exists(fn) then
        DBGOut('IMPORT SHARESTRIP - File found')

        loadfn = string.match(fn, ".+[\\/](.*)")
        path = string.match(fn, "(.+[\\/]).*")
        DBGOut('IMPORT SHARESTRIP - Loadfn = ' .. tostring(loadfn))

      end
    end

    if loadfn then

      DBGOut('IMPORT SHARESTRIP - Calling LoadStripShareFN')

      local stripdata, stripfiledata = LoadStripShareFN(nil,loadfn,path)
      local continue = false
      if stripdata then
        if stripdata.fx then

          if not verbose then
            DBGOut('IMPORT SHARESTRIP - Plugins required')
  
            local fxstring = 'The following plugins are required by this strip layout:\n\n'
            local fxns = {}
            for f = 1, #stripdata.fx do
  
              local fxn = nil
              if stripdata.fx[f].fxname then
                fxn = stripdata.fx[f].fxname
              else
                local fxc = string.match(stripdata.fx[f].fxchunk,'.-<(.-)\n')
                fxn = GetPlugNameFromChunk(fxc)
                if fxn and fxns[fxn] == nil then
                  fxns[fxn] = true
                else
                  fxn = nil
                end
              end
              if fxn then
                fxstring = fxstring .. fxn .. '\n'
              end
            end
            fxstring = fxstring .. '\nContinue with import?'
            local retval = reaper.MB(fxstring, 'Import Strip File', 4)
            if retval == 6 then
              continue = true
            end
          else
            continue = true          
          end
        end

        DBGOut('IMPORT SHARESTRIP - Continue value:' .. tostring(continue))

        if continue == true then
          GUI_DrawStateWin(obj,gui,'Importing shared strip data... ',true)
          GUI_DrawStateWin(obj,gui,'')

          GUI_DrawStateWin(obj,gui,'Importing graphics data... ')
          GUI_DrawStateWin(obj,gui,'')

          for g = 1, #stripdata.sharedata.gfx do
            local gfxv = 0
            local base = string.match(stripdata.sharedata.gfx[g].fn,'(.+)_v%d%d%d%d')
            local suffx = string.match(stripdata.sharedata.gfx[g].fn,'.+(%..*)')
            if base == nil then
              base = string.match(stripdata.sharedata.gfx[g].fn,'(.+)%..*')
            end
            gfxfn = base .. suffx
            local fndg = false
            local gfn
            for gf = 0, #graphics_folders do
              local gfol = ''
              if graphics_folders[gf] ~= 'GENERAL' then
                gfol = graphics_folders[gf]..'/'
              end
              gfn = paths.graphics_path..gfol..gfxfn
              if reaper.file_exists(gfn) then
                fndg = true
                break
              end
            end

            local copy = 0 --1 = overwrite, 2 = rename (? not implemented yet), 3 = don't copy - but update fn as might be diff
            if fndg == true then
              --compare saved file verses imported - ask to overwrite if not same
              if CompareStringToFile(stripdata.sharedata.gfx[g].bindata, gfn) == false then

                --different file
                while copy == 0 do
                  gfxv = gfxv + 1
                  gfxfn = base .. '_v' .. string.format('%04d',gfxv) .. suffx

                  fndg = false
                  for gf = 0, #graphics_folders do
                    local gfol = ''
                    if graphics_folders[gf] ~= 'GENERAL' then
                      gfol = graphics_folders[gf]..'/'
                    end
                    gfn = paths.graphics_path..gfol..gfxfn
                    if reaper.file_exists(gfn) then
                      fndg = true
                      break
                    end
                  end

                  if fndg == true then
                    if reaper.file_exists(gfn) then
                      if CompareStringToFile(stripdata.sharedata.gfx[g].bindata, gfn) == true then
                        --same file - rename
                        copy = 3
                      end
                    end
                  else
                    --not found - copy and rename
                    copy = 1
                  end
                end

              else
                --same file - rename
                copy = 3
              end
            else
              --not found - copy and rename
              copy = 1
            end

            if copy == 1 then
              GUI_DrawStateWin(obj,gui,'Importing graphic: '..stripdata.sharedata.gfx[g].fn..'   ('..gfxfn..')')

              gfn = paths.graphics_path..gfxfn
              writebinaryfile(gfn, stripdata.sharedata.gfx[g].bindata)
            else
              GUI_DrawStateWin(obj,gui,'Already in graphics library: '..stripdata.sharedata.gfx[g].fn..'   ('..gfxfn..')')

            end
            if copy > 0 then
              local src = stripdata.sharedata.gfx[g].fn
              --update gfx fn in stripdata
              for i = 1, #stripdata.sharedata.gfx do
                if stripdata.sharedata.gfx[i].fn == src then
                  stripdata.sharedata.gfx[i].fn = gfxfn
                  stripdata.sharedata.gfx[i].imageidx = -1
                end
              end
              for i = 1, #stripdata.strip.graphics do
                if stripdata.strip.graphics[i].fn == src then
                  stripdata.strip.graphics[i].fn = gfxfn
                  stripdata.strip.graphics[i].imageidx = -1
                end
              end
            end
          end

          GUI_DrawStateWin(obj,gui,'')
          GUI_DrawStateWin(obj,gui,'Importing controls data... ')
          GUI_DrawStateWin(obj,gui,'')

          for c = 1, #stripdata.sharedata.ctls do

            --local cfn = paths.controls_path..stripdata.sharedata.ctls[c].fn

            local cfxv = 0
            local base = string.match(stripdata.sharedata.ctls[c].fn,'(.+)_v%d%d%d%d')
            local suffx = string.match(stripdata.sharedata.ctls[c].fn,'.+(%..*)')
            if base == nil then
              base = string.match(stripdata.sharedata.ctls[c].fn,'(.+)%..*')
            end
            cfxfn = base .. suffx
            local cfn = paths.controls_path..cfxfn
            local copy = 0
            if reaper.file_exists(cfn) then
              if CompareStringToFile(stripdata.sharedata.ctls[c].bindata, cfn) == false then
                --different file
                while copy == 0 do
                  cfxv = cfxv + 1
                  cfxfn = base .. '_v' .. string.format('%04d',cfxv) .. suffx
                  cfn = paths.controls_path..cfxfn
                  if reaper.file_exists(cfn) then
                    if CompareStringToFile(stripdata.sharedata.ctls[c].bindata, cfn) == true then
                      copy = 3
                    end
                  else
                    copy = 1
                  end
                end
              end
            else
              copy = 1
            end
            if copy == 1 then
              GUI_DrawStateWin(obj,gui,'Importing control: '..stripdata.sharedata.ctls[c].fn..'   ('..cfxfn..')')

              writebinaryfile(cfn, stripdata.sharedata.ctls[c].bindata)
              local knbfn = string.match(cfn, '(.+)%.') ..'.knb'
              writebinaryfile(knbfn, stripdata.sharedata.ctls[c].knbdata)

              setknbfn(knbfn,cfxfn)
            else
              GUI_DrawStateWin(obj,gui,'Already in controls library: '..stripdata.sharedata.ctls[c].fn..'   ('..cfxfn..')')

            end

            local src = stripdata.sharedata.ctls[c].fn
            if cfxfn ~= src then

              --update ctl fn in stripdata
              for i = 1, #stripdata.sharedata.ctls do
                if stripdata.sharedata.ctls[i].fn == src then
                  stripdata.sharedata.ctls[i].fn = cfxfn
                  stripdata.sharedata.ctls[i].imageidx = -1
                end
              end
              for i = 1, #stripdata.strip.controls do
                if stripdata.strip.controls[i].ctl_info.fn == src then
                  stripdata.strip.controls[i].ctl_info.fn = cfxfn
                  stripdata.strip.controls[i].ctl_info.imageidx = -1
                  --stripdata.strip.controls[i].knob_select = nil
                end
              end
            end
          end

          RCM_Neb_UpdateProgIDs(stripdata.strip.controls)
          ActionCommandID_RepairCtls(stripdata.strip.controls)

          GUI_DrawStateWin(obj,gui,'')
          GUI_DrawStateWin(obj,gui,'Importing strip data... ')
          GUI_DrawStateWin(obj,gui,'')

          savefn = stripdata.sharedata.stripfn
          local save_path
          if fol then
            save_path=paths.strips_path..fol..'/'
            reaper.RecursiveCreateDirectory(save_path,1)
          else
            save_path=paths.strips_path..strip_folders[stripfol_select].fn..'/'
          end
          local fn=save_path..savefn--..".strip"
          local copy = 0
          if not verbose and reaper.file_exists(fn) then
            local str = 'The strip file already exists:\n\n'..savefn..'\n\nOverwrite?'
            local retval = reaper.MB(str, 'Import Strip', 4)
            if retval == 6 then
              copy = 1
            end
          else
            copy = 1
          end
          if copy == 1 then
            --stripdata.sharedata = nil

            local DELETE=true
            local file

            if DELETE then

              file=io.open(fn,"w")

              if stripdata.version == 3 then
                local pickled_table=pickle(stripdata)
                file:write(pickled_table)
              else
                local fxdata
                --if string.match(stripfiledata, '%[STRIPFILE_VERSION%].-%[\\FXDATA%]') then
                  fxdata = string.match(stripfiledata, '%[STRIPFILE_VERSION%].-%[\\FXDATA%]')..'\n'
                --[[else
                  fxdata = string.match(stripfiledata, '%[FXDATA%].-%[\\FXDATA%]')..'\n'
                  if fxdata then
                    fxdata = '[STRIPFILE_VERSION]5\n'..fxdata
                  end
                end]]
                file:write(fxdata)
                file:write('[STRIPDATA]\n')
                GenStripSaveData2(stripdata.strip,nil,file)
                file:write('[\\STRIPDATA]\n')

                if stripdata.snapshots then
                  file:write('[SNAPSHOTDATA]\n')
                  SaveSnapshotDataX(stripdata.snapshots,nil,file)
                  file:write('[\\SNAPSHOTDATA]\n')
                end

                --file:write(stripfiledata)
              end
              --local pickled_table=pickle(stripdata)

              file:close()

              if stripdata.sharedata.sbdata then

                GUI_DrawStateWin(obj,gui,'')
                GUI_DrawStateWin(obj,gui,'Importing strip browser image... ')
                GUI_DrawStateWin(obj,gui,'')

                local sbfn = string.match(fn,'(.+)%..*')..'.png'
                writebinaryfile(sbfn, stripdata.sharedata.sbdata.bindata)

              end
            end

            OpenMsgBox(1,'Strip share file imported.',1)
          end

          RepopulateGFX(lvar.sortcontrols)
          RepopulateControls(lvar.sortcontrols)
          PopulateStrips(lvar.sortcontrols)

        else
          GUI_DrawStateWin(obj,gui,'')
          GUI_DrawStateWin(obj,gui,'Import aborted.')

        end
      end
    end
    return savefn
  end

  function setknbfn(kfn, cfn)

    if reaper.file_exists(kfn) then
      local file

      file=io.open(kfn,"r")
      local content=file:read("*a")
      file:close()

      local knbdat = unpickle(content)
      knbdat.fn = cfn

      --save knb file
      file=io.open(kfn,"w")
      local pickled_table=pickle(knbdat)
      file:write(pickled_table)
      file:close()
    end

  end

  ------------------------------------------- --
  -- Pickle.lua
  -- A table serialization utility for lua
  -- Steve Dekorte, http://www.dekorte.com, Apr 2000
  -- (updated for Lua 5.3 by me)
  -- Freeware
  ----------------------------------------------

  function pickle(t)
  return Pickle:clone():pickle_(t)
  end

  Pickle = {
  clone = function (t) local nt={}; for i, v in pairs(t) do nt[i]=v end return nt end
  }

  function Pickle:pickle_(root)
  if type(root) ~= "table" then
  error("can only pickle tables, not ".. type(root).."s")
  end
  self._tableToRef = {}
  self._refToTable = {}
  local savecount = 0
  self:ref_(root)
  local s = ""

  while #self._refToTable > savecount do
  savecount = savecount + 1
  local t = self._refToTable[savecount]
  s = s.."{\n"

  for i, v in pairs(t) do
  s = string.format("%s[%s]=%s,\n", s, self:value_(i), self:value_(v))
  end
  s = s.."},\n"

  end
  return string.format("{%s}", s)
  end

  function Pickle:value_(v)
  local vtype = type(v)
  if vtype == "string" then return string.format("%q", v)
  elseif vtype == "number" then return v
  elseif vtype == "boolean" then return tostring(v)
  elseif vtype == "table" then return "{"..self:ref_(v).."}"
  else error("pickle a "..type(v).." is not supported")
  end
  end

  function Pickle:ref_(t)
  local ref = self._tableToRef[t]
  if not ref then
  if t == self then error("can't pickle the pickle class") end
  table.insert(self._refToTable, t)
  ref = #self._refToTable
  self._tableToRef[t] = ref
  end
  return ref
  end

  ----------------------------------------------
  -- unpickle
  ----------------------------------------------

  function unpickle(s)
  if s == nil or s == '' then return end
  if type(s) ~= "string" then
  error("can't unpickle a "..type(s)..", only strings")
  end
  local gentables = load("return "..s)
  if gentables then
    local tables = gentables()

    if tables then
      for tnum = 1, #tables do
      local t = tables[tnum]
      local tcopy = {}; for i, v in pairs(t) do tcopy[i] = v end
      for i, v in pairs(tcopy) do
      local ni, nv
      if type(i) == "table" then ni = tables[i[1]] else ni = i end
      if type(v) == "table" then nv = tables[v[1]] else nv = v end
      t[i] = nil
      t[ni] = nv
      end
      end
      return tables[1]
    end
  else
    --error
  end
  end

  ------------------------------------------------------------

  function DBG(str)
  if str==nil then str="nil" end
  reaper.ShowConsoleMsg(tostring(str).."\n")
  end

  function DBGByte(s)
    DBG(s..' len '..string.len(s))
    for i = 1, string.len(s) do
      --DBG(string.sub(s,i,i+1))
      reaper.ShowConsoleMsg(tostring(string.byte(string.sub(s,i,i+1)))..' ')
    end
  end

  ------------------------------------------------------------

  function tobool(b)

    local ret = false
    if tostring(b) == 'true' then
      ret = true
    end
    return ret

  end

  function convertguid(g)
    if g then
      return string.match(g,'{(.*)}')
    end
  end

  val_to_dB = function(val) return 20*math.log(val, 10) end
  dB_to_val = function(dB_val) return 10^(dB_val/20) end

  function PosEBCtls(obj)

    local sizex, sizey = obj.sections[8].w, obj.sections[8].h
    local bsizex, bsizey = math.floor(60*pnl_scale), math.floor(20*pnl_scale)

    --EDIT BOX - textbox
    obj.sections[5] = {x = math.floor(obj.sections[8].x + 25*pnl_scale),
                       y = math.floor(obj.sections[8].y + 10*pnl_scale),
                       w = math.floor(sizex-50*pnl_scale),
                       h = math.floor(20*pnl_scale)}

    --OK
    obj.sections[6] = {x = obj.sections[8].x + obj.sections[8].w*0.5 + 10*pnl_scale,
                             y = obj.sections[8].y + sizey - bsizey - 10*pnl_scale,
                             w = bsizex,
                             h = bsizey}
    --CANCEL
    obj.sections[7] = {x = obj.sections[8].x + obj.sections[8].w*0.5 - bsizex - 10*pnl_scale,
                             y = obj.sections[8].y + sizey - bsizey - 10*pnl_scale,
                             w = bsizex,
                             h = bsizey}
    --EB Text
    obj.sections[9] = {x = obj.sections[8].x + 25*pnl_scale,
                       y = obj.sections[8].y+obj.sections[8].h - 66*pnl_scale,
                       w = sizex-50*pnl_scale,
                       h = 26*pnl_scale}

    return obj
  end

  function GetObjects(o10)

      if pnl_scale == nil then pnl_scale = 1 end

      local ss160
      if obj and obj.sections and pnlscaleflag ~= true then
        ss160 = obj.sections[160]
      end
      local mm1120
      if obj and obj.sections then
        mm1120 = obj.sections[1120]
      end
      local mm1130
      if obj and obj.sections then
        mm1130 = obj.sections[1130]
      end
      local mm1300
      if obj and obj.sections then
        mm1300 = obj.sections[1300]
      end
      local mm1350
      if obj and obj.sections then
        mm1350 = obj.sections[1350]
      end

      if obj and not o10 then
        lvar.o10_x = obj.sections[10].x
        lvar.o10_y = obj.sections[10].y
      end

      local obj = {}

      obj.sections = {}

      --Middle Button Arrows
      obj.sections[2000] = {x = 0, y = 0,
                            w = 70, h = 87}
      obj.sections[2001] = {x = 0, y = 0,
                            w = 87, h = 70}

      local sizex, sizey = math.floor(350*pnl_scale), math.floor(100*pnl_scale)
      --EB BG
      obj.sections[8] = {x = gfx1.main_w/2 - sizex/2,
                         y = gfx1.main_h/2 - sizey/2,
                         w = sizex,
                         h = sizey}

      obj = PosEBCtls(obj)

      --surface
      --if tb_butt_h == nil then
      --  tb_butt_h = 20
      --end

      if hide_topbar then
        topbarheight = 0
      else
        topbarheight = tb_butt_h
      end
      --DBG('a')
      SetSurfaceSize2(obj)

      obj = DockableWindows(obj, ss160, mm1350)

      --mode
      obj.sections[11] = {x = 1,
                          y = 1,
                          w = plist_w-1,
                          h = tb_butt_h}

      --track title
      obj.sections[12] = {x = 126,
                          y = obj.sections[11].y,
                          w = math.max(gfx1.main_w - plist_w - 352,0),
                          h = topbarheight}

      --submode
      obj.sections[13] = {x = 1,
                          y = tb_butt_h+2+1,
                          w = plist_w-1,
                          h = tb_butt_h+1}
      --SB button
      obj.sections[15] = {x = 0,
                          y = (tb_butt_h+2) *2 + 2,
                          w = plist_w,
                          h = tb_butt_h}
      --pages
      obj.sections[14] = {x = gfx1.main_w - plist_w - 100,
                          y = obj.sections[11].y,
                          w = 101,
                          h = topbarheight}
      --G page
      obj.sections[1000] = {x = gfx1.main_w - plist_w - 150,
                          y = obj.sections[11].y,
                          w = 50,
                          h = topbarheight}

      --save
      obj.sections[17] = {x = gfx1.main_w - plist_w - 250,
                          y = obj.sections[11].y,
                          w = 74,
                          h = topbarheight}
      --show/hide sidebar
      obj.sections[18] = {x = 0,
                          y = obj.sections[11].y,
                          w = 25,
                          h = tb_butt_h}
      --SB resize
      obj.sections[19] = {x = gfx1.main_w - plist_w - 125,
                          y = obj.sections[11].y,
                          w = 25,
                          h = tb_butt_h}
      --XYUD
      obj.sections[20] = {x = obj.sections[18].x+obj.sections[18].w+1,
                          y = obj.sections[11].y,
                          w = 100,
                          h = topbarheight}
      if hide_topbar then
        --...
        obj.sections[21] = {x = obj.sections[10].x + obj.sections[10].w - 26 - plist_w, --gfx1.main_w - plist_w - 26,
                            y = obj.sections[11].y,
                            w = 26,
                            h = tb_butt_h}
        --[[if settings_ssdock == true then
          obj.sections[21].x = obj.sections[21].x - gui.winsz.snaps
        end
        if settings_sbdock == true then
          obj.sections[21].x = obj.sections[21].x - sbwin.w*pnl_scale
        end]]
      else
        obj.sections[21] = {x = gfx1.main_w - plist_w - 175,
                            y = obj.sections[11].y,
                            w = 26,
                            h = tb_butt_h}
      end

      --TOOLBOX
      local cbheight = math.max(tb_butt_h,32)
      local cbwidth = 800
      obj.sections[3000] = {x = plist_w,
                          y = gfx1.main_h-cbheight,
                          w = gfx1.main_w-plist_w,
                          h = cbheight}
      obj.sections[3001] = {x = 60,
                          y = 1,
                          w = 40,
                          h = cbheight-4}

      obj.sections[3007] = {x = 10,
                          y = 1,
                          w = 40,
                          h = cbheight-4}

      local cpscale = cbheight-4
      if cpscale > 24 then
        cpscale = math.floor(cpscale / 24)*24
      end
      local cpy = math.floor((cbheight-cpscale)/2)

      obj.sections[3100] = {x = obj.sections[3001].x+obj.sections[3001].w+10,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3110] = {x = obj.sections[3100].x+obj.sections[3100].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3113] = {x = obj.sections[3110].x+obj.sections[3110].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3101] = {x = obj.sections[3113].x+obj.sections[3113].w+16,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3111] = {x = obj.sections[3101].x+obj.sections[3101].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3112] = {x = obj.sections[3111].x+obj.sections[3111].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3102] = {x = obj.sections[3112].x+obj.sections[3112].w+16,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3103] = {x = obj.sections[3102].x+obj.sections[3102].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3106] = {x = obj.sections[3103].x+obj.sections[3103].w+16,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3107] = {x = obj.sections[3106].x+obj.sections[3106].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3104] = {x = obj.sections[3107].x+obj.sections[3107].w+16,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}
      obj.sections[3105] = {x = obj.sections[3104].x+obj.sections[3104].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3108] = {x = obj.sections[3105].x+obj.sections[3105].w+16,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3109] = {x = obj.sections[3108].x+obj.sections[3108].w+6,
                            y = cpy,
                            w = cpscale,
                            h = cpscale}

      obj.sections[3003] = {x = obj.sections[3109].x+obj.sections[3109].w+40,
                          y = 1,
                          w = 50,
                          h = cbheight-4}
      obj.sections[3004] = {x = obj.sections[3003].x+obj.sections[3003].w+30,
                          y = 1,
                          w = 50,
                          h = cbheight-4}
      obj.sections[3005] = {x = obj.sections[3004].x+obj.sections[3004].w+30,
                          y = 1,
                          w = 50,
                          h = cbheight-4}
      obj.sections[3006] = {x = obj.sections[3005].x+obj.sections[3005].w+30,
                          y = 1,
                          w = 50,
                          h = cbheight-4}
      obj.sections[3002] = {x = obj.sections[3006].x+obj.sections[3006].w+60,
                          y = 1,
                          w = 50,
                          h = cbheight-4}

      obj = PosTrBtns(obj)

      --TEMPLATES
      obj = PosTemplates(obj)

      --TRACKS
      obj.sections[43] = {x = 0,
                          y = 0, --butt_h+2,
                          w = plist_w,
                          h = gfx1.main_h}
      --edit chooser
      obj.sections[501] = {x = 0,
                           y = (tb_butt_h*2+2),
                           w = plist_w,
                           h = butt_h}
      --NEW TRACKS
      obj.sections[500] = {x = 0,
                          y = tb_butt_h*2+6,
                          w = plist_w,
                          h = gfx1.main_h-(tb_butt_h*2+6)}
      --NEW STRIPS
      sf_h = def_sf_h
      if (tb_butt_h+2)*3+sf_h+4+8 > gfx1.main_h then
        sf_h = math.max(gfx1.main_h - ((tb_butt_h+2)*3+4+8),tb_butt_h*2)
      end
      --Strip folder list
      obj.sections[510] = {x = 0,
                           y = (tb_butt_h+2)*3 + 2,
                           w = plist_w,
                           h = sf_h}
      --Scrollbar
      obj.sections[515] = {x = obj.sections[510].w -12,
                           y = obj.sections[510].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[510].h - tb_butt_h-1 +4}
      --save
      obj.sections[511] = {x = 0,
                           y = (tb_butt_h+2)*2 + 2,
                           w = plist_w,
                           h = tb_butt_h}

      --Strip list resize
      local rsz = math.min(math.max(((tb_butt_h - 20)),6),20)
      obj.sections[513] = {x = 0,
                           y = obj.sections[510].y+obj.sections[510].h+4,
                           w = plist_w,
                           h = rsz}

      --Strip list
      obj.sections[512] = {x = 0,
                           y = obj.sections[510].y+obj.sections[510].h+4 + 2 + rsz,
                           w = plist_w,
                           h = gfx1.main_h - (obj.sections[510].y+obj.sections[510].h+2) - 8}
      --Scrollbar
      obj.sections[514] = {x = obj.sections[512].w -12,
                           y = obj.sections[512].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[512].h - tb_butt_h-1}

      --NEW FX - plugins/track controls
      fx_h = def_fx_h
      if (tb_butt_h+2)*2+fx_h+2+8 > gfx1.main_h then
        fx_h = math.max(gfx1.main_h - ((tb_butt_h+2)*2+2+8),40)
      end

      --FX list
      obj.sections[520] = {x = 0,
                           y = (tb_butt_h+2)*2 + 2,
                           w = plist_w,
                           h = fx_h}
      --Scrollbar
      obj.sections[525] = {x = obj.sections[520].w -12,
                           y = obj.sections[520].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[520].h - tb_butt_h-1 +2}
      --FX list resize
      --local rsz = math.max((6 + (tb_butt_h - 20)),6)
      obj.sections[523] = {x = 0,
                           y = obj.sections[520].y+obj.sections[520].h+2,
                           w = plist_w,
                           h = rsz}
      --track select/lrn
      obj.sections[521] = {x = 0,
                           y = obj.sections[520].y+obj.sections[520].h+2 + 2 + rsz,
                           w = plist_w,
                           h = tb_butt_h}
      --FX list params
      obj.sections[522] = {x = 0,
                           y = obj.sections[521].y+obj.sections[521].h+2,
                           w = plist_w,
                           h = gfx1.main_h - (obj.sections[521].y+obj.sections[521].h+2)}
      --Scrollbar
      obj.sections[524] = {x = obj.sections[522].w -12,
                           y = obj.sections[522].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[522].h - tb_butt_h-1}

      --GRAPHICS
      gx_h = def_gx_h
      if (tb_butt_h+2)*2+gx_h+2+8 > gfx1.main_h then
        gx_h = math.max(gfx1.main_h - ((tb_butt_h+2)*2+2+8),40)
      end

      --Graphics folder list
      obj.sections[531] = {x = 0,
                           y = (tb_butt_h+2)*2 + 2,
                           w = plist_w,
                           h = gx_h}
      --Scrollbar
      obj.sections[535] = {x = obj.sections[531].w -12,
                           y = obj.sections[531].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[531].h - tb_butt_h-1 +2}

      --Graphics list resize
      --local rsz = math.max((6 + (tb_butt_h - 20)),6)
      obj.sections[533] = {x = 0,
                           y = obj.sections[531].y+obj.sections[531].h+2,
                           w = plist_w,
                           h = rsz}

      --Graphics files list
      obj.sections[530] = {x = 0,
                           y = obj.sections[531].y+obj.sections[531].h+2 + 2 + rsz,
                           w = plist_w,
                           h = gfx1.main_h - (obj.sections[531].y+obj.sections[531].h+2) - 8}
      --Scrollbar
      obj.sections[534] = {x = obj.sections[530].w -12,
                           y = obj.sections[530].y + tb_butt_h+1,
                           w = 12,
                           h = obj.sections[530].h - tb_butt_h-1}

      --CONTROL OPTIONS Panel
      local cow = math.floor(gui.winsz.ctlopts*pnl_scale)
      local coh = math.floor(470*pnl_scale) --(470-150)*pnl_scale+150
      local coff = math.floor(150*pnl_scale+(gui.winsz.pnltit*pnl_scale-gui.winsz.pnltit))

      --[[obj.sections[45] = {x = obj.sections[10000].x+obj.sections[10].w-cow,
                          y = math.max(obj.sections[10000].y, obj.sections[10000].y),
                          w = cow,
                          h = coh}]]
      local cbdw = 0
      if lvar.ctlbrowser_docked then
        cbdw = lvar.ctlbrowser_docked_w
      end
      obj.sections[45] = {x = math.max(gfx1.main_w - cow - cbdw, obj.sections[10000].x),
                          y = math.max(obj.sections[10000].y --[[+ obj.sections[10].h - coh]], obj.sections[10000].y),
                          w = cow,
                          h = coh}

      --GFX / LABEL OPTS Panel
      obj.sections[49] = {x = gfx1.main_w - cow,
                          y = obj.sections[10000].y, --math.floor(obj.sections[10000].y+obj.sections[10000].h -1 - 320*pnl_scale),
                          w = cow,
                          h = math.floor(330*pnl_scale)}
      obj = PosGfxOptCtls(obj)


      --GAUGE EDIT
      local gaw, gah = math.floor(320*pnl_scale), math.floor(500*pnl_scale)
      local gsw = math.floor(90*pnl_scale)
      local gofs = math.floor(270*pnl_scale)
      obj.sections[800] = {x = math.max(gfx1.main_w/2 -gaw/2,obj.sections[43].w),
                          y = math.max(gfx1.main_h/2 - gah/2, obj.sections[10000].y),
                          w = gaw,
                          h = gah}
      obj = PosGaugeEdCtls(obj)

      local gaw,gah = 420, math.max(200, gfx1.main_h-obj.sections[10].y-40) --obj.sections[10].h-40)

      --Track FX ORDER panel
      obj.sections[900] = {x = math.max(gfx1.main_w/2 -gaw/2,obj.sections[43].w),
                          y = math.max(gfx1.main_h/2 - gah/2, obj.sections[10000].y+20),
                          w = gaw,
                          h = gah}

      --local sf_h = 140

      obj.sections[853] = {x = obj.sections[45].w - 74,
                           y = gui.winsz.pnltit*pnl_scale/2 - 5,
                           w = 74,
                           h = 14}

      --scale
      obj.sections[50] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+8)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
      --apply
      obj.sections[51] = {x = math.floor(20*pnl_scale),
                          y = coff,
                          w = math.floor(80*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Gauge button
      obj.sections[99] = {x = obj.sections[51].x+obj.sections[51].w+math.floor(2*pnl_scale),
                          y = coff,
                          w = math.floor(54*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}
      --SHOW NAME Tick
      obj.sections[52] = {x = math.floor(60*pnl_scale), --math.floor(obj.sections[45].w-(104+butt_h/2)*pnl_scale+4*pnl_scale),
                          y = math.floor(coff + (butt_h+10 + (butt_h/2+4 + 10)+24)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}
      --SHOW VALUE Tick
      obj.sections[53] = {x = math.floor(60*pnl_scale), --math.floor(obj.sections[45].w-(104+butt_h/2)*pnl_scale+4*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 2+20)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --COLOR BOX NAME
      obj.sections[54] = {x = math.floor((60+(butt_h/2+4)+6)*pnl_scale), --math.floor(obj.sections[45].w-(84+butt_h/2)*pnl_scale+4*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10)+24)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --COLOR BOX VALUE
      obj.sections[850] = {x = math.floor((60+(butt_h/2+4)+6)*pnl_scale), --math.floor(obj.sections[45].w-(84+butt_h/2)*pnl_scale+4*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 2+20)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Text size slider
      obj.sections[58] = {x = math.floor(obj.sections[52].x+obj.sections[52].w+26*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10)+24)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(obj.sections[52].x+obj.sections[52].w+36*pnl_scale)),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Text size slider
      obj.sections[851] = {x = math.floor(obj.sections[52].x+obj.sections[52].w+26*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 2+20)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(obj.sections[52].x+obj.sections[52].w+36*pnl_scale)),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Link button
      obj.sections[852] = {x = math.floor(obj.sections[851].x+obj.sections[851].w-22*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10)+24)*pnl_scale-butt_h*pnl_scale),
                          w = math.floor(26*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Ctl Type button
      obj.sections[55] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+7 + (butt_h/2+4 + 10) * 8 + 10)*pnl_scale),
                          w = math.floor(obj.sections[45].w-70*pnl_scale),
                          h = math.floor((butt_h+6)*pnl_scale)}

      --Offset slider
      obj.sections[56] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 4)*pnl_scale),
                          w = math.floor(obj.sections[45].w-90*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --Value offset slider
      obj.sections[65] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 5)*pnl_scale),
                          w = math.floor(obj.sections[45].w-90*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --Default value slider
      obj.sections[57] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 10 - 8)*pnl_scale),
                          w = math.floor(obj.sections[45].w-90*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --Font button
      obj.sections[48] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 6 +8)*pnl_scale -1*pnl_scale),
                          w = math.floor(obj.sections[45].w-70*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Edit name button
      obj.sections[59] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+11 + (butt_h/2+4 + 10) * 7 + 6)*pnl_scale - 2*pnl_scale),
                          w = math.floor(obj.sections[45].w-70*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Scroll control graphic <
      obj.sections[90] = {x = math.floor(4*pnl_scale),
                          y = math.floor(coff/2),
                          w = math.floor(12*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --Scroll control graphic >
      obj.sections[91] = {x = obj.sections[45].w-math.floor(12*pnl_scale)-math.floor(4*pnl_scale),
                          y = math.floor(coff/2),
                          w = math.floor(12*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --XY toggle button
      obj.sections[68] = {x = math.floor(50*pnl_scale+obj.sections[45].w-74*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 4.5)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Max DP button
      obj.sections[66] = {x = math.floor(60*pnl_scale),
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 11 -8)*pnl_scale),
                          w = math.floor(40*pnl_scale),
                          h = math.floor((butt_h)*pnl_scale)}

      --Disable DefVal tick
      obj.sections[962] = {x = obj.sections[59].x + obj.sections[59].w - math.floor(((butt_h/2+4)*pnl_scale)),
                          y = obj.sections[57].y + math.floor(obj.sections[57].h/2) - math.floor(((butt_h/2+4)*pnl_scale)/2),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Set MIDI button
      local xx = obj.sections[66].x+obj.sections[66].w + math.floor(6*pnl_scale)
      obj.sections[960] = {x = xx,
                          y = math.floor(coff+(butt_h+10 + (butt_h/2+4 + 10) * 11 -8)*pnl_scale),
                          w = math.floor(obj.sections[45].w-xx-10*pnl_scale),
                          h = math.floor((butt_h)*pnl_scale)}


      --Open CYCLE OPTIONS button
      obj.sections[67] = {x = math.floor(10*pnl_scale),
                          y = math.floor(coff+(butt_h+7 + (butt_h/2+4 + 10) * 8 +10)*pnl_scale),
                          w = math.floor(35*pnl_scale),
                          h = math.floor((butt_h+6)*pnl_scale)}

      local binh = 45

      --Delete BIN
      obj.sections[60] = {x = plist_w + 10,
                          y = obj.sections[10].y+obj.sections[10].h - (binh + 10),
                          w = binh,
                          h = binh}

      local msgwinw, msgwinh = 500, 200

      --Message window panel
      obj.sections[61] = {x = gfx1.main_w/2-msgwinw/2,
                          y = gfx1.main_h/2-msgwinh/2,
                          w = msgwinw,
                          h = msgwinh}
      --OK button
      local butt_w = 100
      obj.sections[62] = {x = gfx1.main_w/2+20,
                          y = obj.sections[61].y+obj.sections[61].h - butt_h*2,
                          w = butt_w,
                          h = butt_h}

      --MsgBox text box
      obj.sections[63] = {x = gfx1.main_w/2-msgwinw/2,
                          y = gfx1.main_h/2-msgwinh/2 + butt_h*2,
                          w = msgwinw,
                          h = butt_h}

      --NO button
      obj.sections[64] = {x = gfx1.main_w/2-butt_w - 20,
                          y = obj.sections[61].y+obj.sections[61].h - butt_h*2,
                          w = butt_w,
                          h = butt_h}

      --SETTINGS
      --if lvar.panelscaled ~= true then 
        settingswin_maxh = math.floor(560*pnl_scale)
        settingswin_w = math.min(math.floor(700*pnl_scale),gfx1.main_w-100)
        settingswin_h = math.min(settingswin_maxh,gfx1.main_h-100)
  
        local setw, seth = settingswin_w, settingswin_h
        settingswin_off = F_limit(settingswin_off,(-settingswin_maxh)+settingswin_h,0)

        lvar.pnl_scale = pnl_scale
        
      --Settings Panel
        obj.sections[70] = {x = gfx1.main_w/2-setw/2,
                            y = gfx1.main_h/2-seth/2,
                            w = setw,
                            h = seth}
  
        obj.sections[732] = {x = obj.sections[70].x + math.floor(10*pnl_scale),
                             y = obj.sections[70].y + math.floor(34*pnl_scale),
                             w = obj.sections[70].w - math.floor(20*pnl_scale),
                             h = math.floor(20*pnl_scale)}
  
        --local xofft, yoff, yoffm, bh, bw, sw = 200, 32, butt_h/2+14, butt_h/2+4, butt_h/2+4, 80
        obj = PosSetWinCtls(obj)
      --[[else
        local pnl_scale = lvar.pnl_scale
        settingswin_maxh = math.floor(560*pnl_scale)
        settingswin_w = math.min(math.floor(700*pnl_scale),gfx1.main_w-100)
        settingswin_h = math.min(settingswin_maxh,gfx1.main_h-100)
  
        local setw, seth = settingswin_w, settingswin_h
        settingswin_off = F_limit(settingswin_off,(-settingswin_maxh)+settingswin_h,0)

      --Settings Panel
        obj.sections[70] = {x = gfx1.main_w/2-setw/2,
                            y = gfx1.main_h/2-seth/2,
                            w = setw,
                            h = seth}
  
        obj.sections[732] = {x = obj.sections[70].x + math.floor(10*pnl_scale),
                             y = obj.sections[70].y + math.floor(34*pnl_scale),
                             w = obj.sections[70].w - math.floor(20*pnl_scale),
                             h = math.floor(20*pnl_scale)}
  
        --local xofft, yoff, yoffm, bh, bw, sw = 200, 32, butt_h/2+14, butt_h/2+4, butt_h/2+4, 80
        obj = PosSetWinCtls(obj)
      end]]

      --Cycle
      local cw, ch = math.floor(160*pnl_scale), math.floor(380*pnl_scale)

      --Cycle Options panel
      obj.sections[100] = {x = obj.sections[45].x - cw - 10,
                           y = obj.sections[45].y + obj.sections[45].h - ch,
                           w = cw,
                           h = ch}

      obj = PosCycleCtls(obj)


      --Param Learn panel
      obj.sections[115] = {x = obj.sections[10].x,
                           y = obj.sections[10].y,
                           w = math.floor(160*pnl_scale),
                           h = math.floor(200*pnl_scale)}
      obj = PosParamLrnCtls(obj)

      --CTL OPTIONS PG 2

      --Display value offset
      obj.sections[125] = {x = math.floor(60*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 0)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --MINOV value
      obj.sections[126] = {x = math.floor(60*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 5.25)*pnl_scale),
                          w = math.floor(obj.sections[45].w-70*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --MAXOV value
      obj.sections[127] = {x = math.floor(60*pnl_scale),
                          y = math.floor((butt_h+6 + (butt_h/2+4 + 10) * 6.25 +2)*pnl_scale),
                          w = math.floor(obj.sections[45].w-70*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      local kwh = defctls[def_knobsm].cellh

      --MINOV knob control
      obj.sections[128] = {x = math.floor((obj.sections[45].w/4) - (kwh/2)),
                           y = math.floor((butt_h+20 + (butt_h/2+4 + 10) * 1)*pnl_scale),
                          w = kwh,
                          h = kwh}

      --MAXOV knob control
      obj.sections[129] = {x = math.floor((obj.sections[45].w*(3/4)) - (kwh/2)),
                           y = math.floor((butt_h+20 + (butt_h/2+4 + 10) * 1)*pnl_scale),
                          w = kwh,
                          h = kwh}

      --OVERRIDE VALUE
      obj.sections[130] = {x = math.floor(20*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 4)*pnl_scale),
                          w = math.floor(obj.sections[45].w-40*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Scale mode Preset
      obj.sections[131] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h + (butt_h/2+4 + 10) * 8.5 -12)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Scale mode
      obj.sections[132] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h + (butt_h/2+4 + 10) * 9.5 -14)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Frame mode
      obj.sections[133] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h + (butt_h/2+4 + 10) * 10.5 -16)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Horiz tickbox
      obj.sections[134] = {x = math.floor(obj.sections[45].w-(40-butt_h/2+4)*pnl_scale),
                          y = math.floor((butt_h+6 + (butt_h/2+4 + 10) * 12 -16)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --Page snapshot exclude tickbox
      obj.sections[139] = {x = math.floor(obj.sections[45].w-(40-butt_h/2+4)*pnl_scale),
                          y = math.floor((butt_h+6 + (butt_h/2+4 + 10) * 12 + 4)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}

      --NORMAL sensitivity
      obj.sections[135] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 14)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
      --FINE sensitivity
      obj.sections[136] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 15)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
      --WHEEL sensitivity
      obj.sections[137] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 16)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
      --WHEEL FINE sensitivity
      obj.sections[138] = {x = math.floor(70*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 17)*pnl_scale),
                          w = math.floor(obj.sections[45].w-80*pnl_scale),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

      --CTL OPTIONS PG 3

      --Bypass BG Ctl
      obj.sections[860] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 1)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --Bypass BG Name
      obj.sections[861] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 2)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --Bypass BG Value
      obj.sections[862] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 3)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --Clickthrough
      obj.sections[863] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 5)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --DNU
      obj.sections[864] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 7)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --Override Refresh Rate
      obj.sections[869] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 8)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}

      --Target selected track
      obj.sections[865] = {x = obj.sections[45].w-(40-butt_h/2+4)*pnl_scale,
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 10)*pnl_scale,
                          w = (butt_h/2+4)*pnl_scale,
                          h = (butt_h/2+4)*pnl_scale}
      --wordwrap text to control
      obj.sections[868] = {x = obj.sections[45].w-(((80-butt_h/2+4))*pnl_scale),
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 12)*pnl_scale,
                          w = 60*pnl_scale,
                          h = (butt_h)*pnl_scale}

      --limit text to control
      obj.sections[866] = {x = obj.sections[45].w-(((80-butt_h/2+4))*pnl_scale),
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 13)*pnl_scale,
                          w = 60*pnl_scale,
                          h = (butt_h)*pnl_scale}
      obj.sections[867] = {x = obj.sections[45].w-(((80-butt_h/2+4))*pnl_scale),
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 14)*pnl_scale,
                          w = 60*pnl_scale,
                          h = (butt_h)*pnl_scale}

      obj.sections[870] = {x = obj.sections[45].w-(((80-butt_h/2+4))*pnl_scale),
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 15.5)*pnl_scale,
                          w = 60*pnl_scale,
                          h = (butt_h)*pnl_scale}
      obj.sections[871] = {x = obj.sections[45].w-(((80-butt_h/2+4))*pnl_scale),
                          y = (butt_h+10 + (butt_h/2+4 + 10) * 16.5)*pnl_scale,
                          w = 60*pnl_scale,
                          h = (butt_h)*pnl_scale}

      --CTL OPTIONS PG 4
      obj = PosCtlOpts4(obj)

      
      --[[SNAPSHOTS

      local ssh
      if settings_ssdock == true then
        snaph = math.min(math.max((gfx1.main_h-obj.sections[10].y),252*pnl_scale),2048)
        ssh = math.floor(snaph-(208*pnl_scale))
        obj.sections[160] = {x = gfx1.main_w - math.floor(gui.winsz.snaps*pnl_scale),
                            y = math.floor(obj.sections[10].y),
                            w = math.floor(gui.winsz.snaps*pnl_scale),
                            h = snaph}
        update_snaps = true
      else
        snaph = math.floor(math.max(math.min(snaph,obj.sections[10].h),252*pnl_scale))
        ssh = math.floor(snaph-(208*pnl_scale))
        obj.sections[160] = {}
        obj.sections[160].w = math.floor(gui.winsz.snaps*pnl_scale)
        obj.sections[160].h = snaph
        if ss160 == nil then
          obj.sections[160] = {x = gfx1.main_w - gui.winsz.snaps*pnl_scale - (sb_size+2),
                              y = gfx1.main_h - snaph - (sb_size+2),
                              w = math.floor(gui.winsz.snaps*pnl_scale),
                              h = snaph}
          if snapshot_win_pos and snapshot_win_pos.x and snapshot_win_pos.y then
            obj.sections[160].x = snapshot_win_pos.x
            obj.sections[160].y = snapshot_win_pos.y
          end
          if obj.sections[160].x + obj.sections[160].w > gfx1.main_w then
            obj.sections[160].x = math.max(gfx1.main_w - obj.sections[160].w,obj.sections[10].x)
          end
          if obj.sections[160].y + obj.sections[160].h > gfx1.main_h then
            obj.sections[160].y = math.max(gfx1.main_h - obj.sections[160].h,obj.sections[10].y)
          end
        else
          obj.sections[160] = ss160
          obj.sections[160].w = gui.winsz.snaps*pnl_scale
          if snapshot_win_pos and snapshot_win_pos.x and snapshot_win_pos.y then
            obj.sections[160].x = snapshot_win_pos.x
            obj.sections[160].y = snapshot_win_pos.y
          end
          if obj.sections[160].x + obj.sections[160].w > gfx1.main_w then
            obj.sections[160].x = math.max(gfx1.main_w - obj.sections[160].w,obj.sections[10].x)
          end
          if obj.sections[160].y + obj.sections[160].h > gfx1.main_h then
            obj.sections[160].y = math.max(gfx1.main_h - obj.sections[160].h,obj.sections[10].y)
          end
        end
        obj.sections[160].x = math.max(obj.sections[160].x,obj.sections[10].x)
        obj.sections[160].y = math.max(obj.sections[160].y,obj.sections[10].y)
      end


      --Subset button
      obj.sections[161] = {x = math.floor(30*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 0)*pnl_scale),
                          w = math.floor(obj.sections[160].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}

      --Capture button
      obj.sections[162] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 4)*pnl_scale),
                          w = math.floor(obj.sections[160].w-(20*pnl_scale)),
                          h = math.floor((butt_h+8)*pnl_scale)}

      --SS List
      obj.sections[163] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 5 + 4)*pnl_scale),
                          w = math.floor(obj.sections[160].w-(20*pnl_scale)),
                          h = math.floor(ssh)}

      --Rate button
      obj.sections[1010] = {x = math.floor(10*pnl_scale),
                            y = math.floor(obj.sections[163].y + obj.sections[163].h+3),
                            w = math.floor((obj.sections[163].w/3)+2)-1,
                            h = math.floor(butt_h*pnl_scale)}

      --Sync button
      obj.sections[1011] = {x = math.floor(12*pnl_scale+obj.sections[1010].w),
                            y = math.floor(obj.sections[1010].y),
                            w = math.floor(obj.sections[1010].w*.7)-1,
                            h = math.floor(butt_h*pnl_scale)}

      --Transfer shape button
      obj.sections[1012] = {x = math.floor((obj.sections[1011].x+obj.sections[1011].w)+2*pnl_scale),
                            y = obj.sections[1010].y,
                            w = math.floor(obj.sections[1010].w*1.3-3),
                            h = math.floor(butt_h*pnl_scale)}

      --Dir button
      obj.sections[1014] = {x = math.floor(10*pnl_scale),
                            y = math.floor(obj.sections[1010].y + (butt_h+2)*pnl_scale),
                            w = math.floor((obj.sections[163].w/3)+2)-1,
                            h = math.floor(butt_h*pnl_scale)}

      --Paused button
      obj.sections[1013] = {x = math.floor(obj.sections[1014].w+12*pnl_scale),
                            y = obj.sections[1014].y,
                            w = math.floor((obj.sections[163].w/3)+2)-2,
                            h = math.floor(butt_h*pnl_scale)}

      --Loop button
      obj.sections[1015] = {x = math.floor((obj.sections[1014].w*2)+13*pnl_scale),
                            y = obj.sections[1014].y,
                            w = math.floor((obj.sections[163].w/3)-3),
                            h = math.floor(butt_h*pnl_scale)}

      --Dock button
      obj.sections[1160] = {x = obj.sections[160].w - 38,
                            y = 2,
                            w = 34,
                            h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

      --Rename subset button
      obj.sections[164] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 3)*pnl_scale),
                          w = math.floor((obj.sections[160].w-(20*pnl_scale))/2) - 1,
                          h = math.floor(butt_h*pnl_scale)}

      --Resize window area
      obj.sections[165] = {x = 0,
                          y = obj.sections[160].h-12,
                          w = obj.sections[160].w,
                          h = 12}

      --New subset button
      obj.sections[166] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 2)*pnl_scale),
                          w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 1),
                          h = math.floor(butt_h*pnl_scale)}

      --Learn Ctls button
      obj.sections[167] = {x = math.floor(12*pnl_scale + (obj.sections[160].w-(20*pnl_scale))/2) +1,
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 2)*pnl_scale),
                          w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 3),
                          h = math.floor((butt_h*2+2)*pnl_scale)}

      --* button
      obj.sections[168] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 0)*pnl_scale),
                          w = math.floor(18*pnl_scale),
                          h = math.floor(butt_h*pnl_scale)}

      --Randomize button
      obj.sections[169] = {x = math.floor(12*pnl_scale + (obj.sections[160].w-(20*pnl_scale))/2) +1,
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 1)*pnl_scale),
                          w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 3),
                          h = math.floor(butt_h*pnl_scale)}

      --Metalite button
      obj.sections[224] = {x = math.floor(10*pnl_scale),
                          y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 1)*pnl_scale),
                          w = math.floor((obj.sections[160].w-(20*pnl_scale))/2) - 1,
                          h = math.floor(butt_h*pnl_scale)}

      ]]

      --ACTION CHOOSER

      obj.sections[170] = {x = obj.sections[10].x+20,
                           y = obj.sections[10].y+20,
                           w = math.min(obj.sections[10].w-40,750),
                           h = obj.sections[10].h-40}
      obj.sections[171] = {x = obj.sections[170].x+10,
                           y = obj.sections[170].y+10+butt_h,
                           w = obj.sections[170].w-20,
                           h = obj.sections[170].h-60-butt_h}
      obj.sections[172] = {x = obj.sections[171].x,
                           y = obj.sections[171].y+obj.sections[171].h + 15,
                           w = 150,
                           h = butt_h}
      obj.sections[173] = {x = obj.sections[172].x+obj.sections[172].w+10,
                           y = obj.sections[172].y,
                           w = 150,
                           h = butt_h}
      obj.sections[174] = {x = obj.sections[171].x+obj.sections[171].w-310,
                           y = obj.sections[172].y,
                           w = 150,
                           h = butt_h}
      obj.sections[175] = {x = obj.sections[171].x+obj.sections[171].w-150,
                           y = obj.sections[172].y,
                           w = 150,
                           h = butt_h}

      --FLOATING SNAPS

      obj.sections[180] = {x = 0,
                          y = 0,
                          w = 138,
                          h = fsnaph}
      obj.sections[181] = {x = 3,
                          y = 2,
                          w = obj.sections[180].w-6,
                          h = obj.sections[180].h-12}
      obj.sections[182] = {x = 0,
                          y = obj.sections[180].h-6,
                          w = obj.sections[180].w,
                          h = 6}

      --CTL BROWSER

      local slsz = 100

      if lvar.ctlbrowser_docked then
        --local butt_h = butt_h*lvar.zoom
        local cb_bw = lvar.ctlbrowser_docked_w-20
        ctl_browser_size = {w = cb_bw+20 --[[ obj.sections[45].w]], h = math.min(obj.sections[10].h,lvar.maxdim)}
        ctl_browser_size.slotsz = slsz
        ctl_browser_size.slots_x = math.floor((ctl_browser_size.w - 20) / slsz)
        ctl_browser_size.slots_y = math.max(math.min(math.floor((ctl_browser_size.h/2 - (butt_h+2)*2 -20) / slsz),8),1)
        --DBG(ctl_browser_size.slots_y..'  '..obj.sections[10].h)
        obj.sections[200] = {x = gfx1.main_w - ctl_browser_size.w,
                            y = obj.sections[10].y,
                            w = ctl_browser_size.w,
                            h = ctl_browser_size.h}
        local cbw = (ctl_browser_size.slots_x * slsz) + cb_bw+10
        local cbh = (ctl_browser_size.slots_y * slsz) + (butt_h*2)+10
        --obj.sections[200].x = math.max((obj.sections[10].w-cbw)/2 +obj.sections[10].x, plist_w + 10)
        --obj.sections[200].y = math.max((obj.sections[10].h-cbh)/2 +obj.sections[10].y, topbarheight + 10)
        --obj.sections[200].w = obj.sections[210].w + cb_bw+10 + 4
        --obj.sections[200].h = obj.sections[210].h + (butt_h*2)+10 + 4

        obj.sections[237] = {x = obj.sections[200].x+obj.sections[200].w - 38,
                              y = obj.sections[200].y+2,
                              w = 34,
                              h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

        --resize
        obj.sections[236] = {x = obj.sections[200].x,
                             y = obj.sections[200].y,
                             w = 10,
                             h = obj.sections[200].h}

        obj.sections[201] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 1+12,
                             w = cb_bw,
                             h = butt_h}


        obj.sections[202] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 2+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[203] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 3+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[204] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 4+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[205] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 5+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[206] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 6+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[207] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 7+12,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[208] = {x = obj.sections[200].x+10,
                             y = obj.sections[200].y+(butt_h+1) * 8+12,
                             w = cb_bw,
                             h = butt_h}

        local prevh = (butt_h+2) * 5
        obj.sections[213] = {x = obj.sections[200].x+10,
                             y = math.max(obj.sections[200].y+obj.sections[200].h-prevh-10),
                             w = cb_bw,
                             h = prevh}

        local butt_slots = math.floor((obj.sections[200].h/2 - obj.sections[213].h - butt_h*6) / (butt_h+2))

        xsp = math.floor((lvar.ctlbrowser_docked_w - 20 - ((ctl_browser_size.slots_x * slsz)))/2)
        obj.sections[209] = {x = obj.sections[201].x,
                             y = obj.sections[201].y,
                             w = cb_bw,
                             h = butt_slots * (butt_h+2)}

        obj.sections[210] = {x = obj.sections[200].x +10 + xsp,
                             y = obj.sections[209].y + obj.sections[209].h+50,
                             w = ctl_browser_size.slots_x * slsz,
                             h = ctl_browser_size.slots_y * slsz}

        obj.sections[211] = {x = obj.sections[200].x +10,
                             y = obj.sections[210].y - butt_h*2 -10,
                             w = 50,
                             h = butt_h*2}
        obj.sections[212] = {x = obj.sections[200].x + obj.sections[211].w +20 +1,
                             y = obj.sections[210].y - butt_h*2 -10,
                             w = 50,
                             h = butt_h*2}

        local margin = 4
        local shrink = math.max(butt_h-topbarheight,0)
        obj.sections[220] = {x = margin,
                             y = butt_h+margin,
                             w = gfx1.main_w-160-margin*2,
                             h = (gfx1.main_h--[[obj.sections[10].y]])-shrink-margin*2}
        obj.sections[221] = {x = obj.sections[220].x+obj.sections[220].w+2,
                             y = butt_h+margin,
                             w = 160,
                             h = (gfx1.main_h--[[obj.sections[10].y]])-shrink-margin*2}
        obj.sections[222] = {x = obj.sections[220].x+obj.sections[220].w+2,
                             y = 0,
                             w = 160,
                             h = butt_h}

        local ssh2 = obj.sections[221].h - (butt_h+10) - (butt_h/2+4 + 10) * 6 - 10
        obj.sections[223] = {x = 10,
                            y = butt_h+10 + (butt_h/2+4 + 10) * 2,
                            w = obj.sections[221].w-20,
                            h = ssh2}

        obj.sections[225] = {x = 60,
                             y = butt_h+10 + (butt_h/2+4 + 10) * 1,
                             w = 90,
                             h = butt_h/2+4}
        obj.sections[226] = {x = 10,
                            y = butt_h+6 + (butt_h/2+2 + 10) * 0,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[232] = {x = 25,
                            y = obj.sections[223].y + obj.sections[223].h + butt_h + 10,
                            w = obj.sections[221].w-35,
                            h = butt_h+2}
        obj.sections[233] = {x = 25,
                            y = obj.sections[223].y + obj.sections[223].h + (butt_h + 10)*2 - 8,
                            w = obj.sections[221].w-35,
                            h = butt_h+2}
        obj.sections[235] = {x = 10,
                            y = obj.sections[223].y + obj.sections[223].h + (butt_h + 10)*3 - 10,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[227] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 2,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}
        obj.sections[228] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 1,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}
        obj.sections[229] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 0,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[231] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 4,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[230] = {x = obj.sections[220].x,
                            y = 2,
                            w = obj.sections[220].w,
                            h = obj.sections[220].y-4}

      else
        local cb_bw = 160
        ctl_browser_size = {w = math.min(obj.sections[10].w - 50,lvar.maxdim+cb_bw) --[[ obj.sections[45].w]], h = math.min(obj.sections[10].h -200,lvar.maxdim)}
        ctl_browser_size.slotsz = slsz
        --ctl_browser_size.slots_x = math.max(math.min(math.floor((ctl_browser_size.w - 20 - cb_bw) / slsz),2),2)
        ctl_browser_size.slots_x = math.max(math.min(math.floor((ctl_browser_size.w - 20 - cb_bw) / slsz),99),2)
        --ctl_browser_size.slots_y = math.max(math.min(math.floor((ctl_browser_size.h - (butt_h+2)*2 -20) / slsz),6),3)
        ctl_browser_size.slots_y = math.max(math.min(math.floor((ctl_browser_size.h - (butt_h+2)*2 -20) / slsz),99),3)
        obj.sections[200] = {x = (obj.sections[10].w-ctl_browser_size.w)/2 +obj.sections[10].x,
                            y = (obj.sections[10].h-ctl_browser_size.h)/2 +obj.sections[10].y,
                            w = ctl_browser_size.w,
                            h = ctl_browser_size.h}
        local cbw = (ctl_browser_size.slots_x * slsz) + cb_bw+10
        local cbh = (ctl_browser_size.slots_y * slsz) + (butt_h*2)+10
        obj.sections[200].x = math.max((obj.sections[10].w-cbw)/2 +obj.sections[10].x, plist_w + 10)
        obj.sections[200].y = math.max((obj.sections[10].h-cbh)/2 +obj.sections[10].y, topbarheight + 10)
        obj.sections[210] = {x = obj.sections[200].x + cb_bw+10,
                             y = obj.sections[200].y + (butt_h*2)+10,
                             w = ctl_browser_size.slots_x * slsz,
                             h = ctl_browser_size.slots_y * slsz}
        obj.sections[200].w = obj.sections[210].w + cb_bw+10 + 4
        obj.sections[200].h = obj.sections[210].h + (butt_h*2)+10 + 4

        obj.sections[201] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 1+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[237] = {x = obj.sections[200].x+obj.sections[200].w - 38,
                              y = obj.sections[200].y+2,
                              w = 34,
                              h = math.floor(gui.winsz.pnltit-2)}


        obj.sections[202] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 2+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[203] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 3+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[204] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 4+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[205] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 5+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[206] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 6+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[207] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 7+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[208] = {x = obj.sections[200].x+4,
                             y = obj.sections[200].y+(butt_h+1) * 8+2,
                             w = cb_bw,
                             h = butt_h}
        obj.sections[211] = {x = obj.sections[200].x + obj.sections[200].w - 180-1,
                             y = obj.sections[200].y + butt_h+4,
                             w = 40,
                             h = butt_h}
        obj.sections[212] = {x = obj.sections[200].x + obj.sections[200].w -140 +1,
                             y = obj.sections[200].y + butt_h+4,
                             w = 40,
                             h = butt_h}

        local prevh = (butt_h+2) * 4
        obj.sections[213] = {x = obj.sections[200].x+4,
                             y = math.max(obj.sections[200].y+obj.sections[200].h-prevh-10),
                             w = cb_bw,
                             h = prevh}

        local butt_slots = math.floor((obj.sections[200].h - obj.sections[213].h - butt_h*6) / (butt_h+2))

        obj.sections[209] = {x = obj.sections[201].x,
                             y = obj.sections[201].y,
                             w = cb_bw,
                             h = butt_slots * (butt_h+2)}

        local margin = 4
        local shrink = math.max(butt_h-topbarheight,0)
        obj.sections[220] = {x = margin,
                             y = butt_h+margin,
                             w = gfx1.main_w-160-margin*2,
                             h = (gfx1.main_h--[[obj.sections[10].y]])-shrink-margin*2}
        obj.sections[221] = {x = obj.sections[220].x+obj.sections[220].w+2,
                             y = butt_h+margin,
                             w = 160,
                             h = (gfx1.main_h--[[obj.sections[10].y]])-shrink-margin*2}
        obj.sections[222] = {x = obj.sections[220].x+obj.sections[220].w+2,
                             y = 0,
                             w = 160,
                             h = butt_h}

        local ssh2 = obj.sections[221].h - (butt_h+10) - (butt_h/2+4 + 10) * 6 - 10
        obj.sections[223] = {x = 10,
                            y = butt_h+10 + (butt_h/2+4 + 10) * 2,
                            w = obj.sections[221].w-20,
                            h = ssh2}

        obj.sections[225] = {x = 60,
                             y = butt_h+10 + (butt_h/2+4 + 10) * 1,
                             w = 90,
                             h = butt_h/2+4}
        obj.sections[226] = {x = 10,
                            y = butt_h+6 + (butt_h/2+2 + 10) * 0,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[232] = {x = 25,
                            y = obj.sections[223].y + obj.sections[223].h + butt_h + 10,
                            w = obj.sections[221].w-35,
                            h = butt_h+2}
        obj.sections[233] = {x = 25,
                            y = obj.sections[223].y + obj.sections[223].h + (butt_h + 10)*2 - 8,
                            w = obj.sections[221].w-35,
                            h = butt_h+2}
        obj.sections[235] = {x = 10,
                            y = obj.sections[223].y + obj.sections[223].h + (butt_h + 10)*3 - 10,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[227] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 2,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}
        obj.sections[228] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 1,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}
        obj.sections[229] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 0,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[231] = {x = 10,
                            y = butt_h+10 + (butt_h/2+2 + 10) * 4,
                            w = obj.sections[221].w-20,
                            h = butt_h+2}

        obj.sections[230] = {x = obj.sections[220].x,
                            y = 2,
                            w = obj.sections[220].w,
                            h = obj.sections[220].y-4}
      end

      --macros
      --exit macro learn param
      obj.sections[250] = {x = obj.sections[10].x + obj.sections[10].w - 120,
                          y = obj.sections[10].y + obj.sections[10].h - 60,
                          w = 100,
                          h = butt_h*2}

      --eq control
      obj.sections[300] = {x = obj.sections[10].x,
                           y = topbarheight,
                           w = (gfx1.main_w-obj.sections[10].x),
                           h = (gfx1.main_h-topbarheight)}
      obj.sections[301] = {x = 0,
                           y = 0,
                           w = obj.sections[300].w,
                           h = 0}
      obj.sections[302] = {x = 40,
                           y = butt_h,
                           w = math.max(obj.sections[300].w-80,400),
                           h = math.max(obj.sections[300].h-butt_h-220,160)}
      obj.sections[303] = {x = 100,
                           y = obj.sections[302].y + obj.sections[302].h + 20,
                           w = obj.sections[300].w-120,
                           h = butt_h+10}
      obj.sections[304] = {x = 20,
                           y = obj.sections[302].y + obj.sections[302].h + 20,
                           w = 60,
                           h = butt_h}
      obj.sections[305] = {x = 100,
                           y = obj.sections[304].y + obj.sections[304].h + 44,
                           w = 300,
                           h = butt_h}
      obj.sections[306] = {x = 100,
                           y = obj.sections[305].y + obj.sections[305].h + 10,
                           w = 110,
                           h = butt_h}
      obj.sections[307] = {x = 100,
                           y = obj.sections[306].y + obj.sections[306].h + 4,
                           w = 110,
                           h = butt_h}
      obj.sections[308] = {x = 100,
                           y = obj.sections[307].y + obj.sections[307].h + 4,
                           w = 110,
                           h = butt_h}
      obj.sections[309] = {x = 520,
                           y = obj.sections[304].y + obj.sections[304].h + 20,
                           w = 100,
                           h = butt_h}
      obj.sections[310] = {x = 625,
                           y = obj.sections[304].y + obj.sections[304].h + 20,
                           w = 50,
                           h = butt_h}
      obj.sections[311] = {x = 20,
                           y = obj.sections[304].y + obj.sections[304].h + 20,
                           w = 60,
                           h = butt_h}
      obj.sections[312] = {x = 20,
                           y = obj.sections[311].y + obj.sections[311].h + 4,
                           w = 60,
                           h = butt_h}
      obj.sections[313] = {x = 100,
                           y = obj.sections[304].y + obj.sections[304].h + 20,
                           w = 120,
                           h = butt_h}
      obj.sections[314] = {x = 225,
                           y = obj.sections[304].y + obj.sections[304].h + 20,
                           w = 175,
                           h = butt_h}
      obj.sections[315] = {x = 20,
                           y = obj.sections[312].y + obj.sections[312].h + 4,
                           w = 60,
                           h = butt_h}
      obj.sections[316] = {x = 625,
                           y = obj.sections[310].y + obj.sections[310].h + 4,
                           w = 50,
                           h = butt_h}
      obj.sections[317] = {x = 215,
                           y = obj.sections[306].y + obj.sections[306].h + 4,
                           w = 40,
                           h = butt_h}
      obj.sections[318] = {x = 215,
                           y = obj.sections[317].y + obj.sections[317].h + 4,
                           w = 40,
                           h = butt_h}

      obj.sections[351] = {x = obj.sections[302].x+obj.sections[302].w+4,
                           y = obj.sections[302].y,
                           w = 32,
                           h = 32}
      obj.sections[320] = {x = obj.sections[302].x+obj.sections[302].w+4,
                           y = obj.sections[302].y + (32+2) * 2 -16,
                           w = 32,
                           h = 32}
      obj.sections[321] = {x = obj.sections[302].x+obj.sections[302].w+4,
                           y = obj.sections[302].y + (32+2) * 3 -16,
                           w = 32,
                           h = 32}
      obj.sections[322] = {x = 260,
                           y = obj.sections[305].y + obj.sections[305].h + 10,
                           w = 110,
                           h = butt_h}
      obj.sections[323] = {x = 260,
                           y = obj.sections[306].y + obj.sections[306].h + 4,
                           w = 110,
                           h = butt_h}
      obj.sections[324] = {x = 260,
                           y = obj.sections[307].y + obj.sections[307].h + 4,
                           w = 110,
                           h = butt_h}

      local w = gfx.getimgdim(def_eqcknobf)
      local h = ctl_files[def_eqcknobfctl].cellh

      local panw = 615+48-120
      obj.sections[350] = {x = math.max(obj.sections[302].x + (obj.sections[302].w/2) - panw/2,120),
                           y = obj.sections[303].y + 75,
                           w = panw,
                           h = obj.sections[300].h - (obj.sections[303].y + 75)}

      obj.sections[325] = {x = obj.sections[350].x,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      local w = gfx.getimgdim(def_eqcknobg)
      local h = ctl_files[def_eqcknobgctl].cellh
      obj.sections[326] = {x = obj.sections[350].x+70,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      obj.sections[327] = {x = obj.sections[350].x+140,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}

      local w = gfx.getimgdim(def_knobsm)
      local h = ctl_files[def_knobsmctl].cellh
      obj.sections[328] = {x = obj.sections[350].x+255,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      obj.sections[329] = {x = obj.sections[350].x+315,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      obj.sections[330] = {x = obj.sections[350].x+375,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      obj.sections[334] = {x = obj.sections[350].x+435,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}
      obj.sections[335] = {x = obj.sections[350].x+495,
                           y = obj.sections[303].y + 75,
                           w = w,
                           h = h+20}

      obj.sections[331] = {x = 375,
                           y = obj.sections[305].y + obj.sections[305].h + 10,
                           w = 110,
                           h = butt_h}
      obj.sections[332] = {x = 375,
                           y = obj.sections[331].y + obj.sections[331].h + 4,
                           w = 110,
                           h = butt_h}
      obj.sections[333] = {x = 375,
                           y = obj.sections[332].y + obj.sections[332].h + 4,
                           w = 110,
                           h = butt_h}
      obj.sections[337] = {x = obj.sections[309].x,
                           y = obj.sections[309].y + obj.sections[309].h + 4,
                           w = 100,
                           h = butt_h/2+4}
      obj.sections[338] = {x = obj.sections[309].x,
                           y = obj.sections[337].y + obj.sections[337].h + 4,
                           w = 100,
                           h = 56}
      obj.sections[336] = {x = obj.sections[309].x,
                           y = obj.sections[338].y + obj.sections[338].h + 4,
                           w = 100,
                           h = butt_h}

      obj.sections[340] = {x = 20,
                           y = obj.sections[315].y + obj.sections[315].h + 4,
                           w = 60,
                           h = butt_h}

      obj.sections[345] = {x = obj.sections[302].x+obj.sections[302].w+4,
                           y = obj.sections[302].y + (32+2) * 4 - 16,
                           w = 32,
                           h = 32}
      obj.sections[355] = {x = 405,
                           y = obj.sections[313].y,
                           w = butt_h * 2 + 5,
                           h = butt_h * 2 + 4}

      obj.sections[356] = {x = 100,
                           y = obj.sections[308].y + obj.sections[308].h + 10,
                           w = 200,
                           h = butt_h}

      obj.sections[357] = {x = 625,
                           y = obj.sections[316].y + obj.sections[316].h + 10,
                           w = 50,
                           h = (obj.sections[338].y + obj.sections[338].h)-(obj.sections[316].y + obj.sections[316].h+6) + butt_h}

      if not lvar.macrosech then
        lvar.macrosech = 40
      end
      obj = PopMacroEditSec(obj,lvar.macrosech)

      --MIDI OUt
      local mow, moh = math.floor(350*pnl_scale), math.floor(450*pnl_scale)
      obj.sections[950] = {x = math.floor(obj.sections[10].x+obj.sections[10].w/2 - mow/2),
                           y = math.floor(obj.sections[10].y+obj.sections[10].h/2 - moh/2),
                           w = mow,
                           h = moh}
      obj.sections[951] = {x = math.floor(obj.sections[950].x+(100)*pnl_scale),
                           y = math.floor(obj.sections[950].y+(butt_h*3)*pnl_scale),
                           w = math.floor(obj.sections[950].w-(120)*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}
      obj.sections[952] = {x = obj.sections[950].x+math.floor((100)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 2)*pnl_scale),
                           w = math.floor((60)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}
      obj.sections[953] = {x = obj.sections[952].x+obj.sections[952].w+math.floor((80)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 2)*pnl_scale),
                           w = math.floor((60)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}
      obj.sections[954] = {x = obj.sections[950].x+math.floor((100)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 1)*pnl_scale),
                           w = obj.sections[950].w-math.floor((120)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}

      obj.sections[955] = {x = obj.sections[950].x+math.floor((100)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 5)*pnl_scale),
                           w = obj.sections[950].w-math.floor((120)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}

      obj.sections[956] = {x = obj.sections[950].x+math.floor((100)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 8)*pnl_scale),
                           w = math.floor((60)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}
      obj.sections[957] = {x = obj.sections[952].x+obj.sections[952].w+math.floor((80)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 8)*pnl_scale),
                           w = math.floor((60)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}
      obj.sections[958] = {x = obj.sections[952].x+obj.sections[952].w+math.floor((40)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 9)*pnl_scale),
                           w = math.floor((100)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}

      obj.sections[963] = {x = obj.sections[952].x+obj.sections[952].w -math.floor((50)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 10)*pnl_scale),
                           w = math.floor((160)*pnl_scale),
                           h = math.floor((butt_h)*pnl_scale)}

      obj.sections[964] = {x = obj.sections[963].x+obj.sections[963].w +math.floor((50)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 10 +4)*pnl_scale),
                           w = math.floor((butt_h/2+4)*pnl_scale),
                           h = math.floor((butt_h/2+4)*pnl_scale)}

      obj.sections[959] = {x = obj.sections[952].x+obj.sections[952].w+math.floor((120)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 11)*pnl_scale),
                           w = math.floor((butt_h/2+4)*pnl_scale),
                           h = math.floor((butt_h/2+4)*pnl_scale)}
      obj.sections[961] = {x = obj.sections[952].x+obj.sections[952].w+math.floor((120)*pnl_scale),
                           y = obj.sections[950].y+math.floor((butt_h*3 + (butt_h+10) * 12)*pnl_scale),
                           w = math.floor((butt_h/2+4)*pnl_scale),
                           h = math.floor((butt_h/2+4)*pnl_scale)}

      local mow, moh = math.floor(300*pnl_scale), math.floor(150*pnl_scale)
      obj.sections[980] = {x = math.floor(obj.sections[10].x+obj.sections[10].w/2 - mow/2),
                           y = math.floor(obj.sections[10].y+obj.sections[10].h/2 - moh/2),
                           w = mow,
                           h = moh}
      obj.sections[981] = {x = obj.sections[980].x+math.floor(100*pnl_scale),
                           y = obj.sections[980].y+math.floor(butt_h*2*pnl_scale),
                           w = obj.sections[980].w-math.floor(120*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}
      obj.sections[983] = {x = obj.sections[980].x+math.floor(140*pnl_scale),
                           y = obj.sections[980].y+math.floor(butt_h*3.5*pnl_scale),
                           w = obj.sections[980].w-math.floor(160*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}

      obj.sections[982] = {x = obj.sections[980].x+math.floor(200*pnl_scale),
                           y = obj.sections[980].y+math.floor(butt_h*5.5*pnl_scale),
                           w = math.floor(60*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}



      --MUTATE panel

      local mw,mh = math.floor(160*pnl_scale),math.floor(84*pnl_scale)
      if mm1120 then
        obj.sections[1120] = {x = math.max(F_limit(mm1120.x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-mw),obj.sections[10000].x),
                              y = math.max(F_limit(mm1120.y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-mh),obj.sections[10000].y),
                              w = mw,
                              h = mh}
      else
        obj.sections[1120] = {x = obj.sections[10000].x+obj.sections[10000].w - mw, -- math.floor(10*pnl_scale),
                             y = obj.sections[10000].y, --+ math.floor(10*pnl_scale),
                             w = mw,
                             h = mh}
      end
      obj.sections[1121] = {x = math.floor(80*pnl_scale),
                           y = math.floor(30*pnl_scale),
                           w = math.floor(60*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}
      obj.sections[1122] = {x = math.floor(80*pnl_scale),
                           y = obj.sections[1121].y+obj.sections[1121].h+math.floor(4*pnl_scale),
                           w = math.floor(60*pnl_scale),
                           h = math.floor(butt_h*pnl_scale)}

      --Advanced RANDOMIZE panel
      local mw,mh = math.floor(340*pnl_scale),math.floor(300*pnl_scale)
      if mm1130 then
        obj.sections[1130] = {x = math.max(F_limit(mm1130.x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-mw),obj.sections[10000].x),
                              y = math.max(F_limit(mm1130.y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-mh),obj.sections[10000].y),
                              w = mw,
                              h = mh}
      else
        obj.sections[1130] = {x = obj.sections[10000].x+obj.sections[10000].w - mw, -- math.floor(10*pnl_scale),
                             y = obj.sections[10000].y, --+ math.floor(10*pnl_scale),
                             w = mw,
                             h = mh}
      end

      obj.sections[1131] = {x = math.floor(100*pnl_scale),
                            y = math.floor(40*pnl_scale),
                            w = math.floor((butt_h/2+8) * pnl_scale),
                            h = math.floor((butt_h/2+8) * pnl_scale)}

      obj.sections[1132] = {x = math.floor(300*pnl_scale),
                            y = math.floor(40*pnl_scale),
                            w = math.floor((butt_h/2+8) * pnl_scale),
                            h = math.floor((butt_h/2+8) * pnl_scale)}

      obj.sections[1133] = {x = math.floor(80*pnl_scale),
                            y = math.floor((80)*pnl_scale),
                            w = math.floor((300-80) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      local row1 = 100
      local row2 = 240
      obj.sections[1134] = {x = math.floor(row2*pnl_scale),
                            y = math.floor((80 + butt_h * 1.2)*pnl_scale),
                            w = math.floor((90) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1146] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*2)*pnl_scale),
                            w = math.floor((60) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1135] = {x = math.floor(row2*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*2)*pnl_scale),
                            w = math.floor((90) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1136] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2))*pnl_scale),
                            w = math.floor((60) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1137] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*3)*pnl_scale),
                            w = math.floor((60) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1138] = {x = math.floor(row2*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*3)*pnl_scale),
                            w = math.floor((90) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1139] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*4)*pnl_scale),
                            w = math.floor((60) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1140] = {x = math.floor((row2-30)*pnl_scale),
                            y = math.floor((80 + (butt_h * 1.2)*4)*pnl_scale),
                            w = math.floor((90) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1147] = {x = math.floor(obj.sections[1140].x+obj.sections[1140].w+2),
                            y = math.floor((80 + (butt_h * 1.2)*4)*pnl_scale),
                            w = math.floor((34) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      local grph = (obj.sections[1140].y+obj.sections[1140].h+10*pnl_scale)
      local ind = 6
      obj.sections[1141] = {x = math.floor(ind*pnl_scale),
                            y = math.floor(grph),
                            w = math.floor((obj.sections[1130].w - (ind*2 * pnl_scale))),
                            h = math.floor((obj.sections[1130].h-grph -(ind * pnl_scale)))}

      obj.sections[1142] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((70 + (butt_h * 1.2)*6)*pnl_scale),
                            w = math.floor((60) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      obj.sections[1143] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((70 + (butt_h * 1.2)*7)*pnl_scale),
                            w = math.floor((300-row1) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      obj.sections[1144] = {x = math.floor(row1*pnl_scale),
                            y = math.floor((70 + (butt_h * 1.2)*8)*pnl_scale),
                            w = math.floor((100) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}
      obj.sections[1148] = {x = math.floor(row1*pnl_scale)+2+obj.sections[1144].w,
                            y = math.floor((70 + (butt_h * 1.2)*8)*pnl_scale),
                            w = math.floor((34) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      --Param <>
      obj.sections[1145] = {x = math.floor((302)*pnl_scale),
                            y = math.floor((80)*pnl_scale),
                            w = math.floor((30) * pnl_scale),
                            h = math.floor((butt_h) * pnl_scale)}

      --Pin Map
      obj.sections[1200] = {x = 0,
                            y = 0,
                            w = gfx1.main_w - plist_w + 1,
                            h = gfx1.main_h - topbarheight}
      --Chan cnt placeholder
      obj.sections[1203] = {x=0,y=0,w=0,h=0}

      --SAMPLE MANAGER panel

      if not lvar.kb then
        GUI_DrawKeyboard(obj, gui)
      end

      local smw,smh = math.min(math.floor(smwin.w*pnl_scale),obj.sections[10].w-20,lvar.kb.wkey_w*lvar.kb.wkeys+20),
                      math.max(math.min(math.floor((smwin.h*pnl_scale)),obj.sections[10].h),405*pnl_scale)
      if mm1300 then
        obj.sections[1300] = {x = math.max(F_limit(mm1300.x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-smw),obj.sections[10000].x),
                              y = math.max(F_limit(mm1300.y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-smh),obj.sections[10000].y),
                              w = smw,
                              h = smh}
      else
        obj.sections[1300] = {x = math.max(obj.sections[10000].x+math.floor(obj.sections[10000].w/2-smw/2),obj.sections[10000].x),
                              y = math.max(obj.sections[10000].y+math.floor(obj.sections[10000].h/2-smh/2),obj.sections[10000].y),
                              w = smw,
                              h = smh}
      end

      obj = PosSampleManager(obj)

      local gfxpw,gfxph = 300,300
      obj.sections[1400] = {x = obj.sections[10].x + 10,
                            y = obj.sections[10].y + obj.sections[10].h - gfxph,
                            w = gfxpw,
                            h = gfxph}

    pnlscaleflag = nil

      local asw = math.floor(600*pnl_scale)
      local ash = math.floor(math.min(obj.sections[10000].h, 400)*pnl_scale)
      obj.sections[4000] = {x = math.floor(obj.sections[10000].x+(obj.sections[10000].w/2) - (asw/2)),
                            y = math.floor(obj.sections[10000].y+(obj.sections[10000].h/2) - (ash/2)),
                            w = asw,
                            h = ash}
      obj.sections[4001] = {x = obj.sections[4000].x + math.floor(10*pnl_scale),
                            y = obj.sections[4000].y + math.floor(60*pnl_scale),
                            w = math.floor(250*pnl_scale),
                            h = ash-math.floor(70*pnl_scale)}
      obj.sections[4002] = {x = obj.sections[4001].x + obj.sections[4001].w + 10*pnl_scale,
                            y = obj.sections[4001].y,
                            w = math.floor(250*pnl_scale),
                            h = ash-math.floor(70*pnl_scale)}
      obj.sections[4003] = {x = obj.sections[4000].x + obj.sections[4000].w - 70*pnl_scale,
                            y = obj.sections[4001].y + obj.sections[4001].h - math.floor(butt_h*2),
                            w = 60*pnl_scale,
                            h = butt_h*2}
      obj.sections[4004] = {x = obj.sections[4003].x,
                            y = obj.sections[4003].y - math.floor(butt_h*2) - math.floor(10*pnl_scale),
                            w = obj.sections[4003].w,
                            h = obj.sections[4003].h}

      obj.sections[4005] = {x = obj.sections[4002].x,
                            y = obj.sections[4002].y - (butt_h+4),
                            w = obj.sections[4002].w - 44,
                            h = butt_h}
      obj.sections[4006] = {x = obj.sections[4005].x+obj.sections[4005].w+2,
                            y = obj.sections[4005].y,
                            w = 20,
                            h = butt_h}
      obj.sections[4007] = {x = obj.sections[4006].x+obj.sections[4006].w+2,
                            y = obj.sections[4006].y,
                            w = 20,
                            h = butt_h}

      --plugin associations window
      local szw = math.max(math.min(obj.sections[10].w-40,1000),680)
      local szh = math.min(obj.sections[10].h-40,800)
      obj.sections[4500] = {x = obj.sections[10].x + math.floor(obj.sections[10].w/2 - szw/2),
                            y = obj.sections[10].y + math.floor(obj.sections[10].h/2 - szh/2),
                            w = szw, h = szh}
      local ptop = math.floor(butt_h*pnl_scale)+4
      local ptop2 = ptop + 16+math.floor(butt_h*pnl_scale)

      obj.sections[4504] = {y = ptop, h = ptop2-ptop}

      obj.sections[4501] = {x = math.floor(10*pnl_scale),
                            y = ptop2,
                            w = math.floor(szw/2)-math.floor(15*pnl_scale),
                            h = szh - ptop - (ptop2-ptop) - math.floor(10*pnl_scale)}
      obj.sections[4502] = {x = math.floor(szw/2) + math.floor(5*pnl_scale),
                            y = ptop2,
                            w = math.floor(szw/2)-math.floor(15*pnl_scale),
                            h = math.floor((szh - ptop)/2)-ptop2}
      local yy = obj.sections[4502].y+obj.sections[4502].h+math.floor(40*pnl_scale)
      local hh = math.floor(obj.sections[4501].h - obj.sections[4502].h)
      obj.sections[4503] = {x = obj.sections[4502].x,
                            y = yy,
                            w = obj.sections[4502].w,
                            h = hh-math.floor(40*pnl_scale)}
      local yy = obj.sections[4502].y+obj.sections[4502].h+math.floor(2*pnl_scale)
      local hh = math.floor(34*pnl_scale)
      local ww = math.floor((obj.sections[4502].w-8) / 4)
      obj.sections[4505] = {x = obj.sections[4502].x,
                            y = yy,
                            w = ww,
                            h = hh}
      obj.sections[4506] = {x = obj.sections[4505].x+ww+2,
                            y = yy,
                            w = ww,
                            h = hh}
      obj.sections[4507] = {x = obj.sections[4506].x+ww+2,
                            y = yy,
                            w = ww,
                            h = hh}
      obj.sections[4508] = {x = obj.sections[4507].x+ww+2,
                            y = yy,
                            w = ww,
                            h = hh}

      obj.sections[4509] = {x = obj.sections[4503].x + 4,
                            y = obj.sections[4503].y + 4,
                            w = ww-4,
                            h = math.floor(butt_h*pnl_scale)}

    return obj
  end

  function PosCtlOpts4(obj)

    local offy = butt_h+10
    --header
    obj.sections[8000] = {x = math.floor(10*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 0)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(20*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}

    --navictl
    obj.sections[8001] = {x = math.floor(60*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 2)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[8002] = {x = math.floor(60*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 3)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[8003] = {x = math.floor(60*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 4)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

    --action
    obj.sections[8004] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 2)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}
    obj.sections[8005] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 2)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*4*pnl_scale)}

    obj.sections[8006] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 6)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}
    obj.sections[8007] = {x = math.floor(60*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 7)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[8008] = {x = math.floor(60*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 8)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(70*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[8009] = {x = math.floor(100*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 9)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(110*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[8010] = {x = math.floor(100*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 10)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(110*pnl_scale)),
                          h = math.floor((butt_h/2+8)*pnl_scale)}

    --infoctl
    obj.sections[8020] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 2)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}
    obj.sections[8021] = {x = math.floor(obj.sections[45].w-(40-butt_h/2+4)*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 4)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[8022] = {x = math.floor(obj.sections[45].w-(40-butt_h/2+4)*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 5)*pnl_scale),
                          w = math.floor((butt_h/2+4)*pnl_scale),
                          h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[8023] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 7)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}

    obj.sections[8024] = {x = math.floor(20*pnl_scale),
                          y = math.floor((offy + (butt_h/2+4 + 10) * 8)*pnl_scale),
                          w = math.floor(obj.sections[45].w-(40*pnl_scale)),
                          h = math.floor(butt_h*pnl_scale)}
 
    obj.sections[8050] = {x = math.floor(70*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 13)*pnl_scale),
                        w = math.floor(obj.sections[45].w-80*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[8051] = {x = math.floor(70*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 14)*pnl_scale),
                        w = math.floor(obj.sections[45].w-80*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}
    
    obj.sections[8052] = {x = math.floor(70*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 15)*pnl_scale),
                        w = math.floor(obj.sections[45].w-80*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}
    
    obj.sections[8053] = {x = math.floor(70*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 16)*pnl_scale),
                        w = math.floor(obj.sections[45].w-80*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}
    
    obj.sections[8054] = {x = math.floor(70*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 17)*pnl_scale),
                        w = math.floor(obj.sections[45].w-80*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}
    
    return obj
  end

  function PopMacroEditSec(obj,sech)

    --MACRO EDIT

    macroedit = {}
    macroedit.secyoff = 100
    macroedit.secyoff2 = 135
    macroedit.sech = sech
    macroedit.pcnt = math.floor((obj.sections[300].h-macroedit.secyoff-10)/macroedit.sech)
    macroedit.h = macroedit.pcnt*macroedit.sech
    macroedit.pcnt2 = math.floor((obj.sections[300].h-macroedit.secyoff2-10)/macroedit.sech)
    macroedit.h2 = macroedit.pcnt2*macroedit.sech

    macroedit.sliderw = 12
    macroedit.sliderh = 24

    --close macro edit button
    obj.sections[401] = {x = obj.sections[300].w-16,
                         y = 0,
                         w = 16,
                         h = 16}

    --Param name
    local sw = math.max(math.floor((obj.sections[300].w-470)/2),120)

    obj.sections[402] = {x = 20,
                         y = macroedit.secyoff,
                         w = 250,
                         h = macroedit.sech}
    --A - slider
    obj.sections[403] = {x = obj.sections[402].x+obj.sections[402].w+20,
                         y = macroedit.secyoff,
                         w = sw,
                         h = macroedit.h}
    --B - slider
    obj.sections[404] = {x = obj.sections[403].x+obj.sections[403].w+26,
                         y = macroedit.secyoff,
                         w = sw,
                         h = macroedit.h}

    --shape button
    obj.sections[405] = {x = obj.sections[404].x + obj.sections[404].w + 14,
                         y = macroedit.secyoff,
                         w = math.max(obj.sections[300].w - (obj.sections[404].x+obj.sections[404].w)-60,100),
                         h = macroedit.h}

    obj.sections[4051] = {x = obj.sections[405].x + obj.sections[405].w + 2,
                         y = macroedit.secyoff,
                         w = math.max(obj.sections[300].w - (obj.sections[405].x+obj.sections[405].w)-28,30),
                         h = macroedit.h}

    --X button
    obj.sections[407] = {x = obj.sections[402].x+5,
                         y = macroedit.secyoff,
                         w = 20,
                         h = macroedit.h}

    --M button
    obj.sections[406] = {x = obj.sections[402].x+obj.sections[402].w-25,
                         y = macroedit.secyoff,
                         w = 20,
                         h = macroedit.h}

    --Faders
    obj.sections[408] = {x = obj.sections[404].x + 10,
                         y = 30,
                         w = obj.sections[404].w-20,
                         h = butt_h+2}

    --Add parameters button
    obj.sections[409] = {x = 40,
                         y = 20,
                         w = obj.sections[402].w-40,
                         h = butt_h*3}

    local w = gfx.getimgdim(def_eqcknobf)
    local h = ctl_files[def_eqcknobfctl].cellh

    --Knob control
    obj.sections[410] = {x = obj.sections[405].x + math.floor(obj.sections[405].w/2 - w/2),
                         y = obj.sections[405].y /2 - math.floor(h/2),
                         w = w,
                         h = h}

    --Capture A button
    obj.sections[411] = {x = obj.sections[403].x + 10,
                         y = obj.sections[409].y+obj.sections[409].h-(butt_h+4),
                         w = obj.sections[403].w-20,
                         h = butt_h+4}

    --Capture B button
    obj.sections[412] = {x = obj.sections[404].x + 10,
                         y = obj.sections[411].y,
                         w = obj.sections[404].w - 20,
                         h = butt_h+4}

    --Monitor button
    obj.sections[413] = {x = obj.sections[403].x + 10,
                         y = 30,
                         w = obj.sections[403].w-20,
                         h = butt_h+2}

    --BI button
    obj.sections[414] = {x = obj.sections[402].x+obj.sections[402].w-75,
                         y = macroedit.secyoff,
                         w = 20,
                         h = macroedit.h}

    --INV button
    obj.sections[415] = {x = obj.sections[402].x+obj.sections[402].w-50,
                         y = macroedit.secyoff,
                         w = 20,
                         h = macroedit.h}

    --REL button
    obj.sections[416] = {x = obj.sections[402].x+obj.sections[402].w-100,
                         y = macroedit.secyoff,
                         w = 20,
                         h = macroedit.h}


    --SNAP EDIT

    local sw = math.max(math.floor((obj.sections[300].w-280) / 3),120)

    --param
    obj.sections[420] = {x = 20,
                         y = macroedit.secyoff2,
                         w = sw, --math.max(sw,200), --200,
                         h = macroedit.h}
    --stage col
    obj.sections[421] = {x = obj.sections[420].x+obj.sections[420].w+2,
                         y = macroedit.secyoff2,
                         w = 80,
                         h = macroedit.h}
    --morph col
    obj.sections[422] = {x = obj.sections[421].x+obj.sections[421].w+2,
                         y = macroedit.secyoff2,
                         w = 80,
                         h = macroedit.h}
    --mem col
    obj.sections[435] = {x = obj.sections[422].x+obj.sections[422].w+2,
                         y = macroedit.secyoff2,
                         w = 40,
                         h = macroedit.h}

    --snap value
    obj.sections[423] = {x = obj.sections[435].x+obj.sections[435].w+22,
                         y = macroedit.secyoff2,
                         w = sw, --math.min(sw,400),
                         h = macroedit.h2}
    obj.sections[424] = {x = obj.sections[423].x+obj.sections[423].w+14,
                         y = macroedit.secyoff2,
                         w = sw, --math.min(sw,400),
                         h = macroedit.sech}

    local heady = macroedit.secyoff2-butt_h-10

    --stage butt
    obj.sections[427] = {x = obj.sections[421].x,
                         y = heady,
                         w = 80,
                         h = butt_h+8}

    --stages butt
    obj.sections[429] = {x = obj.sections[421].x,
                         y = 25,
                         w = 80,
                         h = (butt_h+8)*2}

    --sstype
    obj.sections[430] = {x = obj.sections[420].x,
                         y = 25,
                         w = sw, --200,
                         h = (butt_h+8) * 2}

    --morph butt
    obj.sections[428] = {x = obj.sections[422].x,
                         y = heady,
                         w = 80,
                         h = butt_h+8}
    --mem butt
    obj.sections[434] = {x = obj.sections[435].x,
                         y = heady,
                         w = 40,
                         h = butt_h+8}

    --ss name
    obj.sections[425] = {x = obj.sections[423].x-12 +(butt_h+8),
                         y = heady,
                         w = obj.sections[423].w+24 -(butt_h+8),
                         h = butt_h+8}
    --*
    obj.sections[433] = {x = obj.sections[423].x-12,
                         y = heady,
                         w = butt_h+8-2,
                         h = butt_h+8}

    --monitor
    obj.sections[426] = {x = obj.sections[424].x,
                         y = heady,
                         w = obj.sections[424].w,
                         h = butt_h+8}
    --stage delays
    obj.sections[431] = {x = obj.sections[423].x,
                             y = 25,
                             w = obj.sections[423].w+obj.sections[424].w+14,
                             h = (butt_h+8)*2}

    obj.sections[432] = {x = obj.sections[431].x-50,
                             y = 10,
                             w = 40,
                             h = butt_h}

    return obj

  end

  function DockableWindows(obj, ss160, mm1350)

    --SNAPSHOTS

    local ssh
    if settings_ssdock == true then
      snaph = math.min(math.max((gfx1.main_h-obj.sections[10000].y),252*pnl_scale),lvar.maxdim)
      ssh = math.floor(snaph-(208*pnl_scale))
      obj.sections[160] = {x = gfx1.main_w - math.floor(gui.winsz.snaps*pnl_scale),
                          y = math.floor(obj.sections[10000].y),
                          w = math.floor(gui.winsz.snaps*pnl_scale),
                          h = snaph}
      lupd.update_snaps = true
    else
      snaph = math.floor(math.max(math.min(snaph,obj.sections[10000].h),252*pnl_scale))
      ssh = math.floor(snaph-(208*pnl_scale))
      obj.sections[160] = {}
      obj.sections[160].w = math.floor(gui.winsz.snaps*pnl_scale)
      obj.sections[160].h = snaph
      if ss160 == nil then
        obj.sections[160] = {x = gfx1.main_w - gui.winsz.snaps*pnl_scale - (sb_size+2),
                            y = gfx1.main_h - snaph - (sb_size+2),
                            w = math.floor(gui.winsz.snaps*pnl_scale),
                            h = snaph}
        if snapshot_win_pos and snapshot_win_pos.x and snapshot_win_pos.y then
          obj.sections[160].x = snapshot_win_pos.x
          obj.sections[160].y = snapshot_win_pos.y
        end
        if obj.sections[160].x + obj.sections[160].w > gfx1.main_w then
          obj.sections[160].x = math.max(gfx1.main_w - obj.sections[160].w,obj.sections[10000].x)
        end
        if obj.sections[160].y + obj.sections[160].h > gfx1.main_h then
          obj.sections[160].y = math.max(gfx1.main_h - obj.sections[160].h,obj.sections[10000].y)
        end
      else
        obj.sections[160] = ss160
        obj.sections[160].w = gui.winsz.snaps*pnl_scale
        if snapshot_win_pos and snapshot_win_pos.x and snapshot_win_pos.y then
          obj.sections[160].x = snapshot_win_pos.x
          obj.sections[160].y = snapshot_win_pos.y
        end
        if obj.sections[160].x + obj.sections[160].w > gfx1.main_w then
          obj.sections[160].x = math.max(gfx1.main_w - obj.sections[160].w,obj.sections[10000].x)
        end
        if obj.sections[160].y + obj.sections[160].h > gfx1.main_h then
          obj.sections[160].y = math.max(gfx1.main_h - obj.sections[160].h,obj.sections[10000].y)
        end
      end
      obj.sections[160].x = math.max(obj.sections[160].x,obj.sections[10000].x)
      obj.sections[160].y = math.max(obj.sections[160].y,obj.sections[10000].y)
    end
    obj.sections[160].w = math.floor(obj.sections[160].w)
    obj.sections[160].h = math.floor(obj.sections[160].h)

    obj = PosSnapshots(obj, ssh)

    --MOD EDIT (LFO)

    local mow, moh, x, y
    if settings_moddock == true and modwinsz and modwinsz.minimized == true then
      mow = math.max(obj.sections[10000].w+1,modwin.minw*pnl_scale)
      moh = gui.winsz.pnltit*pnl_scale
      x = obj.sections[10000].x
      y = gfx1.main_h - moh

    elseif settings_moddock == true then
      mow = math.max(obj.sections[10000].w+1,modwin.minw*pnl_scale)
      if modwinsz then
        moh = modwinsz.h
      else
        moh = 300*pnl_scale
      end
      moh = math.max(math.min(moh,gfx1.main_h-obj.sections[10000].y),modwin.minh*pnl_scale)
      x = obj.sections[10000].x
      y = gfx1.main_h - moh
      if not modwinsz then
        modwinsz = {x = x, y = y, w = mow, h = moh}
      end

    else
      if modwinsz and modwinsz.resize ~= true then
        mow = modwinsz.w*pnl_scale
        moh = (modwinsz.h or 300)*pnl_scale
        x = modwinsz.x
        y = modwinsz.y
      elseif modwinsz then
        mow = modwinsz.w*pnl_scale
        moh = (modwinsz.h or 300)*pnl_scale
        x = modwinsz.x
        y = modwinsz.y
      else
        mow, moh = modwin.minw*pnl_scale, 300*pnl_scale
        x = math.floor(obj.sections[10000].x+obj.sections[10000].w/2 - mow/2)
        y = math.floor(obj.sections[10000].y+obj.sections[10000].h/2 - moh/2)
        modwinsz = {x = x, y = y, w = mow, h = moh}
      end
      if x < obj.sections[10000].x then x = obj.sections[10000].x end
      if y < obj.sections[10000].y then y = obj.sections[10000].y end
    end

    obj.sections[1100] = {x = x,
                         y = y,
                         w = math.floor(mow),
                         h = math.floor(moh)}
    if obj.sections[1100].x < plist_w + 2 then
      obj.sections[1100].x = plist_w + 2
    end
    obj.sections[1100].w = math.floor(obj.sections[1100].w)
    obj.sections[1100].h = math.floor(obj.sections[1100].h)

    obj = PosMod(obj)



    --STRIP BROWSER
    local sbw,sbh
    if settings_sbdock == true then
      if lvar.stripbrowser.dockpos == 1 then
        local maxh2 = math.max(obj.sections[10000].h,0) + sbwin.h

        sbwin.h = math.floor(math.min(math.max(sbwin.h,lvar.sbmin),maxh2))
        --maxh2 = obj.sections[10].h + sbwin.h*pnl_scale
        sbw,sbh = math.floor(math.max(sbwin.w*pnl_scale,lvar.sbmin*pnl_scale)),
                  math.floor(math.max(math.min(sbwin.h*pnl_scale,maxh2*pnl_scale),lvar.sbmin*pnl_scale))

      else
        local maxw2 = obj.sections[10000].w + sbwin.w

        sbwin.w = math.floor(math.min(math.max(sbwin.w,lvar.sbmin),maxw2))
        sbw,sbh = math.floor(math.max(math.floor(sbwin.w*pnl_scale),lvar.sbmin*pnl_scale)),
                  math.floor(math.max(math.min(math.floor((sbwin.h*pnl_scale)),obj.sections[10000].h),lvar.sbmin*pnl_scale))
      end
    else
      sbw,sbh = math.floor(math.max(math.min(math.floor(sbwin.w*pnl_scale),obj.sections[10000].w),lvar.sbmin*pnl_scale)),
                    math.floor(math.max(math.min(math.floor((sbwin.h*pnl_scale)),obj.sections[10000].h),lvar.sbmin*pnl_scale))
    end
    
    if not lvar.stripbrowser.fullscreen then
    
      if mm1350 then
        --[[obj.sections[1350] = {x = math.max(F_limit(mm1350.x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-sbw),obj.sections[10000].x),
                              y = math.max(F_limit(mm1350.y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-sbh),obj.sections[10000].y),
                              w = sbw,
                              h = sbh}]]
        obj.sections[1350] = {x = F_limit(mm1350.x,0,gfx1.main_w-sbw),
                              y = F_limit(mm1350.y,obj.sections[10000].y,gfx1.main_h-sbh),
                              w = sbw,
                              h = sbh}
      elseif sbwin.x and sbwin.y then
        --[[obj.sections[1350] = {x = F_limit(sbwin.x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-sbw),
                              y = F_limit(sbwin.y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-sbh),
                              w = sbw,
                              h = sbh}]]
        obj.sections[1350] = {x = F_limit(sbwin.x,0,gfx1.main_w-sbw),
                              y = F_limit(sbwin.y,obj.sections[10000].y,gfx1.main_h-sbh),
                              w = sbw,
                              h = sbh}
      else
        obj.sections[1350] = {x = math.max(obj.sections[10000].x+math.floor(obj.sections[10000].w/2-sbw/2),obj.sections[10000].x),
                              y = math.max(obj.sections[10000].y+math.floor(obj.sections[10000].h/2-sbh/2),obj.sections[10000].y),
                              w = sbw,
                              h = sbh}
      end
    else
      settings_sbdock = false
      obj.sections[1350] = {x = 0,
                            y = 0,
                            w = gfx1.main_w,
                            h = gfx1.main_h}
    end
    if settings_sbdock == true then
      if lvar.stripbrowser.dockpos == 1 then
        local sb = 0
        if settings_showbars then
          sb = sb_size
        end
        local ypad = 2
        if topbarheight == 0 then
          ypad = 0
        end
        local sbyy = topbarheight + sb + ypad
        local xpad = 0
        if plist_w > 0 then
          xpad = 1
        end
        obj.sections[1350].x = obj.sections[10000].x-xpad
        obj.sections[1350].w = gfx1.main_w - plist_w+xpad
        obj.sections[1350].y = sbyy
      else
        if settings_ssdock == true and show_snapshots == true then
          obj.sections[1350].x = obj.sections[160].x-obj.sections[1350].w
        else
          obj.sections[1350].x = obj.sections[10000].x+obj.sections[10000].w
        end
        if obj.sections[1350].x < plist_w + 2 then
          obj.sections[1350].x = plist_w + 2
          if settings_ssdock == true and show_snapshots == true then
            obj.sections[1350].w = obj.sections[160].x - obj.sections[1350].x
          else
            obj.sections[1350].w = gfx1.main_w - obj.sections[1350].x
          end
          --sbwin.x = math.floor(obj.sections[1350].x / pnl_scale)
          --sbwin.w = math.floor(obj.sections[1350].w / pnl_scale)
        end

        obj.sections[1350].y = obj.sections[10000].y
        local hh = math.floor(math.min(math.max((gfx1.main_h-obj.sections[10000].y),lvar.sbmin*pnl_scale),lvar.maxdim))
        obj.sections[1350].h = hh
      end
    end
    obj.sections[1350].h = math.floor(obj.sections[1350].h)
    obj.sections[1350].w = math.floor(obj.sections[1350].w)

    obj = PosStripBrowser(obj)

    return obj
  end

  function PosSnapshots(obj, ssh)

    local pad = 6

    --Subset button
    obj.sections[161] = {x = math.floor(30*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 0)*pnl_scale),
                        w = math.floor(obj.sections[160].w-(40*pnl_scale)),
                        h = math.floor(butt_h*pnl_scale)}

    --Capture button
    obj.sections[162] = {x = pad,
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 4)*pnl_scale),
                        w = math.floor(obj.sections[160].w-(2*pad)),
                        h = math.floor((butt_h+8)*pnl_scale)}

    --SS List
    obj.sections[163] = {x = pad,
                        y = math.floor((butt_h+10 + (butt_h/2+4 + 10) * 5 + 4)*pnl_scale),
                        w = math.floor(obj.sections[160].w-(2*pad)),
                        h = math.floor(ssh)}

    obj.sections[1016] = {x = obj.sections[163].x+obj.sections[163].w-12,
                             y = obj.sections[163].y+1 + math.floor(butt_h*pnl_scale),
                             w = 12,
                             h = obj.sections[163].h-2 - math.floor(butt_h*pnl_scale) - 2}

    --Rate button
    obj.sections[1010] = {x = pad,
                          y = math.floor(obj.sections[163].y + obj.sections[163].h+3),
                          w = math.floor((obj.sections[163].w/3)+2)-1,
                          h = math.floor(butt_h*pnl_scale)}

    --Sync button
    obj.sections[1011] = {x = obj.sections[1010].x+obj.sections[1010].w+2,
                          y = math.floor(obj.sections[1010].y),
                          w = math.floor(obj.sections[1010].w*.7)-1,
                          h = math.floor(butt_h*pnl_scale)}

    --Transfer shape button
    obj.sections[1012] = {x = math.floor((obj.sections[1011].x+obj.sections[1011].w)+2*pnl_scale),
                          y = obj.sections[1010].y,
                          w = math.floor(obj.sections[1010].w*1.3-3),
                          h = math.floor(butt_h*pnl_scale)}

    --Dir button
    obj.sections[1014] = {x = pad,
                          y = math.floor(obj.sections[1010].y + (butt_h+2)*pnl_scale),
                          w = math.floor((obj.sections[163].w-2)/3),
                          h = math.floor(butt_h*pnl_scale)}

    --Paused button
    obj.sections[1013] = {x = obj.sections[1014].x+obj.sections[1014].w+2,
                          y = obj.sections[1014].y,
                          w = obj.sections[1014].w,
                          h = math.floor(butt_h*pnl_scale)}

    --Loop button
    obj.sections[1015] = {x = obj.sections[1013].x+obj.sections[1013].w+2,
                          y = obj.sections[1014].y,
                          w = obj.sections[1014].w,
                          h = math.floor(butt_h*pnl_scale)}

    --Dock button
    obj.sections[1160] = {x = obj.sections[160].w - 38,
                          y = 2,
                          w = 34,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Edit button
    obj.sections[1161] = {x = 4,
                          y = 2,
                          w = 34,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Rename subset button
    obj.sections[164] = {x = math.floor(10*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 3)*pnl_scale),
                        w = math.floor((obj.sections[160].w-(20*pnl_scale))/2) - 1,
                        h = math.floor(butt_h*pnl_scale)}

    --Resize window area
    obj.sections[165] = {x = 0,
                        y = obj.sections[160].h-12,
                        w = obj.sections[160].w,
                        h = 12}

    --New subset button
    obj.sections[166] = {x = math.floor(10*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 2)*pnl_scale),
                        w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 1),
                        h = math.floor(butt_h*pnl_scale)}

    --Learn Ctls button
    obj.sections[167] = {x = math.floor(12*pnl_scale + (obj.sections[160].w-(20*pnl_scale))/2) +1,
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 2)*pnl_scale),
                        w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 3),
                        h = math.floor((butt_h*2+2)*pnl_scale)}

    --* button
    obj.sections[168] = {x = math.floor(10*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 0)*pnl_scale),
                        w = math.floor(18*pnl_scale),
                        h = math.floor(butt_h*pnl_scale)}

    --Randomize button
    obj.sections[169] = {x = math.floor(12*pnl_scale + (obj.sections[160].w-(20*pnl_scale))/2) +1,
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 1)*pnl_scale),
                        w = math.floor((obj.sections[160].w-(20*pnl_scale))/2 - 3),
                        h = math.floor(butt_h*pnl_scale)}

    --Metalite button
    obj.sections[224] = {x = math.floor(10*pnl_scale),
                        y = math.floor((butt_h+10 + (butt_h/2+2 + 10) * 1)*pnl_scale),
                        w = math.floor((obj.sections[160].w-(20*pnl_scale))/2) - 1,
                        h = math.floor(butt_h*pnl_scale)}

    return obj
  end

  function PosMod(obj)

    modpos = 8

    --assign win
    local ma_w = math.floor(140*pnl_scale)
    local mh
    if show_lfoedit == true then
      mh = gfx1.main_h - obj.sections[1100].h - obj.sections[10].y
    else
      mh = obj.sections[10].h
    end
    obj.sections[1125] = {x = obj.sections[10].x,
                          y = obj.sections[10].y,
                          w = obj.sections[10].w,
                          h = mh}

    --fx
    --[[obj.sections[1126] = {x = 2,
                          y = 30,
                          w = ma_w,
                          h = obj.sections[1125].h-32}]]

    obj.sections[1127] = {x = 2,
                          y = math.floor(30*pnl_scale),
                          w = obj.sections[1125].w-4,
                          h = obj.sections[1125].h-math.floor(30*pnl_scale)-2}


    --Dock button
    obj.sections[1123] = {x = obj.sections[1100].w - 38,
                          y = 2,
                          w = 34,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Main bar display
    obj.sections[1101] = {x = 10,
                         y = 30*pnl_scale,
                         w = obj.sections[1100].w-(20),
                         h = obj.sections[1100].h-(90*pnl_scale)-(modpos*pnl_scale)}

    --Step mult button
    obj.sections[1102] = {x = math.floor(obj.sections[1101].x + obj.sections[1101].w - (102*pnl_scale)),
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(100*pnl_scale),
                         h = math.floor(20*pnl_scale)}


    --ON button
    obj.sections[1106] = {x = obj.sections[1101].x,
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(40*pnl_scale),
                         h = math.floor(42*pnl_scale)}

    --Length button
    obj.sections[1104] = {x = math.floor(obj.sections[1106].x + obj.sections[1106].w + (6*pnl_scale)),
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(80*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Smooth button
    obj.sections[1105] = {x = math.floor(obj.sections[1104].x + obj.sections[1104].w + 2*pnl_scale),
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(80*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Steps button
    obj.sections[1107] = {x = math.floor(obj.sections[1102].x -(82*pnl_scale)),
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(80*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Shift button
    obj.sections[1108] = {x = math.floor(obj.sections[1105].x + obj.sections[1105].w + 2*pnl_scale),
                         y = math.floor(obj.sections[1101].y + obj.sections[1101].h + (10 + modpos)*pnl_scale),
                         w = math.floor(120*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Min button
    obj.sections[1109] = {x = obj.sections[1104].x,
                         y = math.floor(obj.sections[1102].y + obj.sections[1102].h + 2*pnl_scale),
                         w = math.floor(80*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Max button
    obj.sections[1110] = {x = math.floor(obj.sections[1109].x + obj.sections[1109].w + 2*pnl_scale),
                         y = obj.sections[1109].y,
                         w = math.floor(80*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Corner resize
    obj.sections[1111] = {x = obj.sections[1100].w -20,
                         y = obj.sections[1100].h -20,
                         w = 20,
                         h = 20}

    --Title bar
    obj.sections[1112] = {x = 0,
                         y = 0,
                         w = obj.sections[1100].w,
                         h = gui.winsz.pnltit*pnl_scale}

    --Randomize button
    obj.sections[1113] = {x = obj.sections[1102].x,
                         y = math.floor(obj.sections[1102].y + obj.sections[1102].h + 2*pnl_scale),
                         w = math.floor(100*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Mode button
    obj.sections[1114] = {x = math.floor(obj.sections[1110].x+obj.sections[1110].w + 2*pnl_scale),
                         y = math.floor(obj.sections[1102].y + obj.sections[1102].h + 2*pnl_scale),
                         w = math.floor(120*pnl_scale),
                         h = math.floor(20*pnl_scale)}

    --Mod title <
    obj.sections[1115] = {x = 10,
                          y = 2,
                          w = 30,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Mod title >
    obj.sections[1116] = {x = obj.sections[1115].x+obj.sections[1115].w+2,
                          y = 2,
                          w = 30,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Mod title Assign
    obj.sections[1117] = {x = obj.sections[1116].x+obj.sections[1116].w+8,
                          y = 2,
                          w = 60,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    --Mod title Clear all
    obj.sections[1118] = {x = obj.sections[1117].x+obj.sections[1117].w+8,
                          y = 2,
                          w = 80,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}
    return obj
  end

  function PosStripBrowser(obj)

    local pad = 4

    --[[if obj.sections[1350].w <= 360*pnl_scale then
      obj.sections[1353] = {x = math.floor(pad*pnl_scale),
                             y = math.floor(30*pnl_scale),
                             w = (140*pnl_scale),
                             h = butt_h*pnl_scale}
    else]]
    local th = math.floor(gui.winsz.pnltit*pnl_scale)
    obj.sections[1353] = {x = math.floor(pad--[[*pnl_scale]]),
                           y = 2,
                           w = math.min((140*pnl_scale),obj.sections[1350].w - 44),
                           h = th-2}

    --end

    local h = (#strip_folders + 2) * butt_h*pnl_scale
    obj.sections[1351] = {x = math.floor(pad--[[*pnl_scale]]),
                           y = obj.sections[1353].y + (obj.sections[1353].h+2) + math.floor(pad--[[*pnl_scale]]),
                           w = (140*pnl_scale),
                           h = math.min(h, obj.sections[1350].h - (obj.sections[1353].y+th) - pad*2--[[*pnl_scale]])}

    obj.sections[1352] = {x = obj.sections[1351].x,
                           y = obj.sections[1353].y+obj.sections[1353].h+2 + pad--[[*pnl_scale]],
                           w = obj.sections[1350].w - 2*pad--[[*pnl_scale]],
                           h = obj.sections[1350].h - (obj.sections[1353].y+th) - 2*pad--[[*pnl_scale]]}

    --resize
    obj.sections[1354] = {x = obj.sections[1350].w-15,
                         y = obj.sections[1350].h-15,
                         w = 15,
                         h = 15}
    obj.sections[1355] = {x = 0,
                         y = obj.sections[1350].h-10,
                         w = obj.sections[1350].w-15,
                         h = 10}
    obj.sections[1356] = {x = 0,
                         y = 0,
                         w = 15,
                         h = obj.sections[1350].h}

    --Dock button
    obj.sections[1357] = {x = obj.sections[1350].w - 38,
                          y = 2,
                          w = 34,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    obj.sections[1359] = {x = obj.sections[1353].x + obj.sections[1353].w + 6,
                          y = 2,
                          w = 50,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}
    obj.sections[1360] = {x = obj.sections[1359].x + obj.sections[1359].w + 2,
                          y = 2,
                          w = 50,
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}

    obj.sections[1358] = {x = obj.sections[1360].x + obj.sections[1360].w + 6,
                          y = 2,
                          w = obj.sections[1357].x - (obj.sections[1360].x + obj.sections[1360].w + 12),
                          h = math.floor(gui.winsz.pnltit*pnl_scale-2)}
    local bw = 140
    local nb = math.ceil(obj.sections[1358].w / (bw+2))
    lvar.sb_folbtn_w = math.floor(obj.sections[1358].w / nb)
    lvar.sb_folbtn_c = nb

    --DBG(lvar.sb_folbtn_c..'  '..lvar.sb_folbtn_w)
    if not lvar.stripbrowser.minw then
      lvar.stripbrowser.minw = 120 * pnl_scale
      lvar.stripbrowser.minh = 90 * pnl_scale
    end

    lvar.stripbrowser.xnum = math.max(math.floor((obj.sections[1352].w-20) / (lvar.stripbrowser.minw+10)),1)
    local lbl = 30
    --if lvar.stripbrowser.showlabel == true then
    --  lbl = 30
    --end
    lvar.stripbrowser.ynum = math.max(math.floor((obj.sections[1352].h-20) / (lvar.stripbrowser.minh+lbl)),1)

    lvar.stripbrowser.imgw = math.max(math.floor((obj.sections[1352].w-20) / lvar.stripbrowser.xnum)-10,lvar.stripbrowser.minw)
    lvar.stripbrowser.imgh = math.max(math.floor((obj.sections[1352].h-20) / lvar.stripbrowser.ynum)-10,lvar.stripbrowser.minh)

    return obj

  end

  function PosSampleManager(obj)

    --folder
    obj.sections[1301] = {x = math.floor(80*pnl_scale),
                         y = math.floor(30*pnl_scale),
                         w = math.floor((obj.sections[1300].w-(90*pnl_scale))),--*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}
    --sample list
    obj.sections[1302] = {x = math.floor(20*pnl_scale),
                         y = math.floor(30*pnl_scale) + math.floor((butt_h+10)*pnl_scale),
                         w = math.floor((obj.sections[1300].w-(120*pnl_scale))),
                         h = 0}
    obj.sections[1302].h = obj.sections[1300].h - obj.sections[1302].y - lvar.kb.wkey_h - 20
    --scroll bar
    obj.sections[1303] = {x = obj.sections[1302].x+obj.sections[1302].w-14,
                         y = obj.sections[1302].y+1,
                         w = 12,
                         h = obj.sections[1302].h-2}
    --keyb
    obj.sections[1304] = {x = 10,
                         y = obj.sections[1302].y+obj.sections[1302].h+10,
                         w = math.min(obj.sections[1300].w-20,lvar.kb.wkey_w*lvar.kb.wkeys),
                         h = lvar.kb.wkey_h}
    --out
    local bw = obj.sections[1300].w - (obj.sections[1302].x+obj.sections[1302].w + 10) - 10
    obj.sections[1305] = {x = obj.sections[1302].x+obj.sections[1302].w + 10,
                         y = obj.sections[1302].y+obj.sections[1302].h - (math.floor(butt_h*pnl_scale*2)),
                         w = bw,
                         h = math.floor(butt_h*pnl_scale*2)}

    --add
    obj.sections[1306] = {x = obj.sections[1305].x,
                         y = obj.sections[1302].y + 8,
                         w = bw,
                         h = math.floor(butt_h*pnl_scale*2)}
    --replace
    obj.sections[1307] = {x = obj.sections[1305].x,
                         y = obj.sections[1306].y + obj.sections[1306].h + 4,
                         w = bw,
                         h = math.floor(butt_h*pnl_scale*2)}
    --clear
    obj.sections[1308] = {x = obj.sections[1305].x,
                         y = obj.sections[1307].y + obj.sections[1307].h + 4,
                         w = bw,
                         h = math.floor(butt_h*pnl_scale*2)}

    obj.sections[1309] = {x = obj.sections[1305].x,
                         y = obj.sections[1308].y + obj.sections[1308].h + 4,
                         w = bw,
                         h = math.floor(butt_h*pnl_scale*2)}

    --resize
    obj.sections[1310] = {x = obj.sections[1300].w-15,
                         y = obj.sections[1300].h-15,
                         w = 15,
                         h = 15}
    obj.sections[1311] = {x = 0,
                         y = obj.sections[1300].h-10,
                         w = obj.sections[1300].w-15,
                         h = 10}

    return obj

  end

  function PosSetWinCtls(obj)

    --local pnl_scale = pnl_scale
    --[[if lvar.panelscaled then 
      pnl_scale = lvar.pnl_scale  
    end]]
    
    lvar.settingsy = math.floor(60*pnl_scale)
    local xofft, yoff, yoffm, bh, bw, sw = math.floor(250*pnl_scale), math.floor(lvar.settingsy+10), math.floor((butt_h/2+14)*pnl_scale), 
                                           math.floor((butt_h/2+8)*pnl_scale), math.floor((butt_h/2+8)*pnl_scale), math.floor(80*pnl_scale)
    local xofftm = math.floor(obj.sections[70].w/2+math.floor(60*pnl_scale))
    local swm = math.floor(160*pnl_scale)

    --PAGE 2
    obj.sections[74] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*4,
                              w = swm,
                              h = bh}
    obj.sections[731] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*5,
                              w = math.floor(80*pnl_scale),
                              h = bh}
    obj.sections[88] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*1,
                              w = bw,
                              h = bh}
    obj.sections[715] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*8,
                              w = bw,
                              h = bh}
    obj.sections[726] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*9,
                              w = bw,
                              h = bh}
    obj.sections[72] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*10,
                              w = bw,
                              h = bh}
    obj.sections[738] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*12,
                              w = bw,
                              h = bh}

    obj.sections[740] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*14,
                              w = 80*pnl_scale,
                              h = bh}

    --PAGE 3

    obj.sections[73] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*1,
                              w = bw,
                              h = bh}
    obj.sections[87] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*4,
                              w = bw,
                              h = bh}
    obj.sections[95] = {x = xofftm,
                                    y = settingswin_off + yoff + yoffm*5,
                                    w = math.floor(150*pnl_scale),
                                    h = bh+10}
    obj.sections[98] = {x = xofftm,
                               y = settingswin_off + yoff+10 + yoffm*8,
                               w = bw,
                               h = bh}
    obj.sections[728] = {x = xofftm,
                              y = settingswin_off + yoff+10 + yoffm*9,
                              w = bw,
                              h = bh}

    --PAGE 4

    obj.sections[720] = {x = xofft-80,
                               y = settingswin_off + yoff + yoffm*1,
                               w = math.floor(150*pnl_scale),
                               h = bh+10}

    obj.sections[721] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*3,
                               w = math.floor(70*pnl_scale),
                               h = bh}

    obj.sections[724] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*4,
                               w = math.floor(70*pnl_scale),
                               h = bh}

    obj.sections[725] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*5,
                               w = math.floor(70*pnl_scale),
                               h = bh}

    obj.sections[722] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*6,
                               w = math.floor(70*pnl_scale),
                               h = bh}
    obj.sections[723] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*7,
                               w = math.floor(70*pnl_scale),
                               h = bh}

    obj.sections[702] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*1,
                        w = math.floor(40*pnl_scale),
                        h = bh}
    obj.sections[741] = {x = obj.sections[702].x+obj.sections[702].w+10,
                        y = obj.sections[702].y,
                        w = bw,
                        h = bh}

    obj.sections[742] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*4,
                        w = bw,
                        h = bh}
    obj.sections[743] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*5,
                        w = math.floor(70*pnl_scale),
                        h = bh}
    obj.sections[744] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*6,
                        w = math.floor(70*pnl_scale),
                        h = bh}
    obj.sections[745] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*7,
                        w = math.floor(70*pnl_scale),
                        h = bh}


    obj.sections[86] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*2,
                              w = 40*pnl_scale,
                              h = bh}

    obj.sections[85] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*10,
                              w = bw,
                              h = bh}
    obj.sections[89] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*11,
                              w = bw,
                              h = bh}
    obj.sections[706] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*10,
                              w = bw,
                              h = bh}
    obj.sections[717] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*11,
                              w = bw,
                              h = bh}
    obj.sections[737] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*12,
                              w = bw,
                              h = bh}
    obj.sections[96] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*12,
                               w = bw,
                               h = bh}
    obj.sections[739] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*13,
                               w = bw,
                               h = bh}

    obj.sections[753] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*14,
                               w = bw,
                               h = bh}
    obj.sections[754] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*15,
                               w = bw,
                               h = bh}
                               
    obj.sections[751] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*14,
                              w = bw,
                              h = bh}

    -- PAGE 5

    obj.sections[703] = {x = xofftm,
                        y = settingswin_off + yoff + yoffm*1,
                        w = sw,
                        h = butt_h}

    obj.sections[748] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*3,
                              w = bw,
                              h = bh}

    obj.sections[749] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*4,
                              w = bw,
                              h = bh}

    obj.sections[704] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*5,
                              w = bw,
                              h = bh}
    obj.sections[712] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*6,
                              w = bw,
                              h = bh}
    obj.sections[714] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*7,
                              w = bw,
                              h = bh}
    obj.sections[729] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*9,
                              w = bw,
                              h = bh}

    obj.sections[730] = {x = xofftm,
                              y = settingswin_off + yoff + yoffm*11,
                              w = bw,
                              h = bh}

    obj.sections[736] = {x = xofft-math.floor(100*pnl_scale),
                              y = settingswin_off + yoff + yoffm*13,
                              w = math.floor(500*pnl_scale),
                              h = butt_h}
                              
    obj.sections[750] = {x = xofft-math.floor(100*pnl_scale),
                              y = settingswin_off + yoff + yoffm*15,
                              w = math.floor(500*pnl_scale),
                              h = butt_h}

    -----------------------------------------------

    obj.sections[727] = {x = obj.sections[70].w - math.floor(170*pnl_scale),
                               y = settingswin_off + yoff + yoffm*0,
                               w = math.floor(150*pnl_scale),
                               h = bh+10}

    obj.sections[71] = {x = xofft,
                        y = settingswin_off +yoff + yoffm*1,
                        w = bw,
                        h = bh}
    obj.sections[79] = {x = xofft+bw+10,
                              y = settingswin_off + yoff + yoffm*3,
                              w = math.floor(40*pnl_scale),
                              h = bh}
    obj.sections[80] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*3,
                              w = bw,
                              h = bh}
    obj.sections[733] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*4,
                              w = math.floor(40*pnl_scale),
                              h = bh}

    obj.sections[735] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*6,
                              w = bw,
                              h = bh}
    obj.sections[81] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*7,
                              w = bw,
                              h = bh}
    obj.sections[82] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*8,
                              w = bw,
                              h = bh}

    obj.sections[75] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*15,
                              w = bw,
                              h = bh}
    obj.sections[76] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*16,
                              w = bw,
                              h = bh}
    obj.sections[77] = {x = xofft+bw+10,
                              y = settingswin_off + yoff + yoffm*15,
                              w = math.floor(40*pnl_scale),
                              h = bh}
    obj.sections[78] = {x = xofft+bw+10,
                              y = settingswin_off + yoff + yoffm*16,
                              w = math.floor(40*pnl_scale),
                              h = bh}
    obj.sections[83] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*9,
                              w = bw,
                              h = bh}
    obj.sections[84] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*10,
                              w = bw,
                              h = bh}
    obj.sections[97] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*11,
                               w = bw,
                               h = bh}
    obj.sections[719] = {x = xofft,
                               y = settingswin_off + yoff + yoffm*12,
                               w = bw,
                               h = bh}
    obj.sections[718] = {x = xofft,
                              y = settingswin_off + yoff + yoffm*13,
                              w = bw,
                              h = bh}



    obj.sections[700] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*2,
                        w = sw,
                        h = butt_h}
    obj.sections[701] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*3,
                        w = bw,
                        h = bh}
    obj.sections[734] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*4,
                        w = bw,
                        h = bh}

    --send midi data on track change
    obj.sections[705] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*6,
                              w = bw,
                              h = bh}
    obj.sections[707] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*8,
                              w = bw,
                              h = bh}
    obj.sections[708] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*9,
                        w = bw,
                        h = bh}
    obj.sections[709] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*10,
                        w = math.floor(40*pnl_scale),
                        h = bh}
    obj.sections[710] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*11,
                        w = math.floor(40*pnl_scale),
                        h = bh}
    obj.sections[711] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*12,
                        w = math.floor(40*pnl_scale),
                        h = bh}
    obj.sections[713] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*15,
                              w = bw,
                              h = bh}
    obj.sections[716] = {x = obj.sections[70].w/2+xofft,
                        y = settingswin_off + yoff + yoffm*13.5,
                        w = math.floor(40*pnl_scale),
                        h = bh}

    obj.sections[752] = {x = obj.sections[70].w/2+xofft,
                              y = settingswin_off + yoff + yoffm*16,
                              w = bw,
                              h = bh}

    return obj

  end

  function PosParamLrnCtls(obj)

    obj.sections[116] = {x = obj.sections[115].x,
                         y = obj.sections[115].y+(butt_h*4)*pnl_scale,
                         w = obj.sections[115].w,
                         h = obj.sections[115].h-(obj.sections[115].y+(butt_h*4)*pnl_scale)}
    --learn track
    obj.sections[117] = {x = obj.sections[115].x,
                         y = obj.sections[115].y+butt_h*pnl_scale,
                         w = obj.sections[115].w,
                         h = butt_h*pnl_scale}
    --learn fx
    obj.sections[118] = {x = obj.sections[115].x,
                         y = obj.sections[115].y+(butt_h*2)*pnl_scale,
                         w = obj.sections[115].w,
                         h = butt_h*pnl_scale}
    --learn param
    obj.sections[119] = {x = obj.sections[115].x,
                         y = obj.sections[115].y+(butt_h*3)*pnl_scale,
                         w = obj.sections[115].w,
                         h = butt_h*pnl_scale}

    return obj

  end

  function PosTemplates(obj)

    local tmpcmax = 6
    if lvar.template_strips then
      tmpcmax = #lvar.template_strips + 1
    end
    lvar.template_h = 60
    local tmpw = math.min(400*pnl_scale,gfx1.main_w-100)
    local tmph = lvar.template_h*pnl_scale
    local o10h = obj.sections[10].h
    if lvar.livemode == 2 and lvar.trmix_show then
      o10h = o10h + lvar.trmix_h
    end
    local tmph2 = math.min((tmph*tmpcmax),math.floor((o10h -100)/tmph)*tmph) + butt_h*pnl_scale + 10

    local tmpc = math.floor(tmph2/tmph)
    obj.sections[5050] = {x = math.max(math.floor(gfx1.main_w/2 - tmpw/2), obj.sections[10].x),
                          y = math.max(math.floor(obj.sections[10].h/2 - tmph2/2) + obj.sections[10].y, obj.sections[10].y), --butt_h+2,
                          w = tmpw,
                          h = tmph2}
    lvar.tempchooser = {w = tmpw, h = tmph2, x = obj.sections[5050].x, y = obj.sections[5050].y, th = tmph, tmpc = tmpc}

    return obj
  end

  function Repos5001(o)

    if not o then o = obj end

    local mmov = 0
    if lvar.mmov_show and lvar.mixmodedir == 0 then
      mmov = lvar.mmov_vsize + 2*lvar.mmov_pad
    end
    if lvar.mixmodedir == 0 then
      o.sections[5001].y = o.sections[10].y
      o.sections[5001].x = o.sections[10].x + 10 + mmov
    else
      o.sections[5001].x = o.sections[10].x + 10
      o.sections[5001].y = o.sections[10].y + mmov
    end
    return o

  end

  function Repos5005()

    --[[local mmov = 0
    if lvar.mmov_show and lvar.mixmodedir == 0 then
      mmov = lvar.mmov_vsize + 2*lvar.mmov_pad
    end
    --local mmovw = (#lvar.dm_trackbtns) * (obj.sections[5004].w + 10)-10
    local mmovw = math.min((#lvar.dm_trackbtns+1),lvar.dm_maxvistracks+1,lvar.trov_maxrows) * (obj.sections[5004].w + 10)-10

    obj.sections[5005].w = mmovw
    obj.sections[5027].w = mmovw
    obj.sections[5005].x = math.max(obj.sections[4999].x + mmov + math.floor((obj.sections[4999].w-mmov)/2 - (mmovw/2)) + math.floor((obj.sections[5004].w + 10)/2))
    obj.sections[5025].x = obj.sections[5005].x
    obj.sections[5027].x = obj.sections[5005].x
    ]]
    obj = PosTrBtns(obj)

    lupd.update_trbtns = true
    lupd.update_trmix = true

  end

  function PosTrBtns(obj)

    lvar.mixerchan_redraw = true

    local sz = lvar.trbtns_size
    local msz = lvar.trmixbtns_size

    local offs = 0
    if show_lfoedit and settings_moddock then
      offs = obj.sections[1100].h
    end
    obj.sections[4999] = {x = obj.sections[10].x,
                          y = gfx1.main_h - (sz+10) - offs,
                          w = math.max(obj.sections[10].w,(sz+10)*5+10),
                          h = sz+10}
    --offs = 0
    if show_stripbrowser and settings_sbdock and lvar.stripbrowser.dockpos == 1 then
      offs = offs + obj.sections[1350].h
    end

    local sss
    if lvar.trmix_h < lvar.trmix_seth then
      lvar.trmix_h = lvar.trmix_seth
      sss = true
    end

    if lvar.trmix_h > gfx1.main_h - obj.sections[4999].h-offs-topbarheight then
      lvar.trmix_h = math.max(gfx1.main_h - obj.sections[4999].h -offs-topbarheight,10)
      sss = true
    end
    if sss then
      SetSurfaceSize2(obj)
      obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])

    end

    --DYNAMIC MODE REFRESH
    obj.sections[5000] = {x = obj.sections[4999].x+obj.sections[4999].w-(sz+10),
                        y = obj.sections[4999].y+3,
                        w = sz,
                        h = sz}
    --FOLDER SELECTOR
    obj.sections[5041] = {x = obj.sections[5000].x-(sz+10),
                          y = obj.sections[5000].y,
                          w = sz,
                          h = sz}

    --DM Track title
    local mmov = 0
    if lvar.mmov_show and lvar.mixmodedir == 0 then
      mmov = lvar.mmov_vsize + 2*lvar.mmov_pad
    end

    obj.sections[5001] = {x = obj.sections[10].x,
                        y = obj.sections[10].y,
                        w = obj.sections[10].w,
                        h = 40}
    obj = Repos5001(obj)

    if LBX_GTRACK then
      --GLOBAL
      obj.sections[5007] = {x = obj.sections[10].x+10,
                          y = obj.sections[5000].y,
                          w = sz,
                          h = sz}
      if obj.sections[5007].y >= gfx1.main_h then
        obj.sections[5007].y = obj.sections[10].y + obj.sections[10].h - obj.sections[5007].h - 10
      end

      --BACK
      obj.sections[5006] = {x = obj.sections[5007].x+obj.sections[5007].w+10,
                          y = obj.sections[5000].y,
                          w = sz,
                          h = sz}
    else
      --BACK
      obj.sections[5006] = {x = obj.sections[10].x+10,
                          y = obj.sections[5000].y,
                          w = sz,
                          h = sz}
    end

    --DM Track < >
    local nsz = sz*0.5-2
    obj.sections[5002] = {x = obj.sections[5006].x+obj.sections[5006].w+10,
                        y = obj.sections[5000].y,
                        w = nsz,
                        h = sz}
    obj.sections[5003] = {x = obj.sections[5002].x+obj.sections[5002].w+2,
                        y = obj.sections[5000].y,
                        w = nsz,
                        h = sz}
    obj.sections[5004] = {x = obj.sections[5003].x+obj.sections[5003].w+10,
                        y = obj.sections[5000].y,
                        w = sz,
                        h = sz}

    local panelw = math.max(lvar.trmix_panelsz, (obj.sections[5003].x+obj.sections[5003].w+10) - (obj.sections[10].x+10),(sz+10)*2+10)
    panelw = math.min(panelw, math.floor((obj.sections[10].w - (sz+10)*2) /2))
    
    lvar.trov_maxsize = obj.sections[10].w - panelw - panelw   
    lvar.trov_maxrows = math.floor(lvar.trov_maxsize/(sz+10))
    
    panelw = (obj.sections[10].w - (lvar.trov_maxrows*(sz+10)))/2
    --lvar.trmix_panelsz = math.min(lvar.trmix_panelsz, panelw)
    
    local mmovw = math.min(--[[(#lvar.dm_trackbtns[lvar.dm_tbidx]+1),]]lvar.dm_maxvistracks+1,lvar.trov_maxrows) * (obj.sections[5004].w + 10)-10
    obj.sections[5005] = {x = math.max(obj.sections[4999].x + mmov + math.floor((obj.sections[4999].w-mmov)/2 - (mmovw/2)) + math.floor((obj.sections[5004].w + 10)/2),
                                       obj.sections[5004].x), 
                          y = obj.sections[5000].y,
                          w = mmovw,
                          h = sz}

    obj.sections[5008] = {x = obj.sections[5005].w-sz,
                          y = 10,
                          w = sz, h = sz}

    local sz2 = sz --math.floor(sz-20)
    local by = lvar.trmix_h - (sz+10) --math.floor((lvar.trmix_h-10-sz2)/(sz+10))*(sz+10)+10
    obj.sections[5009] = {x = obj.sections[5008].x+5+2,
                          y = by+5,
                          w = sz-7, h = sz2-5}
    obj.sections[5010] = {x = obj.sections[5009].x,
                          y = obj.sections[5009].y-sz2-5,
                          w = sz-7, h = sz2-5}
    local ah = math.min(sz2-5,lvar.trmix_h-40-(sz2-5)*2)
    obj.sections[5011] = {x = obj.sections[5009].x,
                          y = obj.sections[5010].y-(ah)-10,
                          w = sz-7, h = ah}

    local ah = math.max(0,math.min(sz2-5,lvar.trmix_h-50-(sz2-5)*3))
    lvar.trmix_sizebtn = true
    if ah < 30 then
      lvar.trmix_sizebtn = false
    end
    
    obj.sections[5012] = {x = obj.sections[5009].x,
                          y = 10, --obj.sections[5011].y-(ah)-10,
                          w = sz-7, h = ah}
    

    obj.sections[5020] = {x = obj.sections[10].x+obj.sections[10].w - (sz+10),
                          y = obj.sections[10].y+obj.sections[10].h - (sz+10),
                          w = sz,
                          h = sz}
    obj.sections[5021] = {x = obj.sections[10].x+obj.sections[10].w - (sz+10)*2,
                          y = obj.sections[10].y+obj.sections[10].h - (sz+10),
                          w = sz,
                          h = sz}
    obj.sections[5022] = {x = obj.sections[10].x+obj.sections[10].w - (sz+10)*3,
                          y = obj.sections[10].y+obj.sections[10].h - (sz+10),
                          w = sz,
                          h = sz}

    --Track mixer
    --[[if lvar.trmix_h > obj.sections[10].h then
      lvar.trmix_h = obj.sections[10].h
    end]]
    obj.sections[5024] = {x = obj.sections[4999].x,
                        y = obj.sections[4999].y-lvar.trmix_h,
                        w = obj.sections[4999].w,
                        h = lvar.trmix_h}
    obj.sections[5025] = {x = obj.sections[5005].x,
                        y = obj.sections[5024].y,
                        w = sz,
                        h = lvar.trmix_h}
    obj.sections[5027] = {x = obj.sections[5005].x,
                        y = obj.sections[5024].y,
                        w = obj.sections[5005].w,
                        h = lvar.trmix_h}
    --panel sizer
    obj.sections[5080] = {x = obj.sections[5005].x-10,
                          y = obj.sections[5024].y,
                          w = 10,
                          h = lvar.trmix_h}
    --panel sizer
    --[[obj.sections[5081] = {x = obj.sections[5005].x+obj.sections[5005].w+1,
                          y = obj.sections[5024].y,
                          w = 10,
                          h = lvar.trmix_h}]]


    local aoff = 0
    if lvar.analyzer.showcontrols then
      aoff = lvar.trbtns_size+10
    end
    obj.sections[5046] = {x = obj.sections[5005].x+10 + aoff,
                        y = obj.sections[4999].y-lvar.trmix_h+10,
                        w = obj.sections[5005].w-(lvar.trbtns_size)-20-aoff,
                        h = lvar.trmix_h-20}

    obj.sections[5047] = {x = obj.sections[5005].x,
                          y = obj.sections[4999].y-lvar.trmix_h+10,
                          w = (lvar.trbtns_size)+10,
                          h = lvar.trmix_h-20}
    obj.sections[5048] = {x = obj.sections[5046].x,
                          y = obj.sections[4999].y-lvar.trmix_h+10,
                          w = obj.sections[5046].w,
                          h = 15}

    --vol
    local toff = 30
    local poff = 28
    local slidlen = lvar.trmix_h - 145 - toff
    local nnx = math.min(math.floor(((sz+10)) - ((sz+10)/4)-skin.sliderknb_w/2),(sz+10)-skin.sliderknb_w-4)

    --peak
    local ww = nnx-4 --((sz+10) - (obj.sections[5026].x--[[+obj.sections[5026].w]]))
    lvar.trmix_peak_w = math.max(math.floor(ww/2)-12,12)
    local xx = --[[(obj.sections[5026].x+obj.sections[5026].w) +]] math.floor(ww/2) -lvar.trmix_peak_w
    obj.sections[5029] = {x = xx,
                          y = 122+toff+poff,--math.floor(skin.sliderknb_h/2),
                          w = lvar.trmix_peak_w,
                          h = slidlen-poff}

    local ppw = lvar.trmix_peak_w*2+2
    nnx = math.floor(xx + ppw + ((sz+10) - ppw - xx)/2 - (skin.sliderknb_w/2))

    obj.sections[5026] = {x = nnx, --(sz+10)-12-skin.sliderknb_w,
                        y = 122 + toff,--math.floor(skin.sliderknb_h/2),
                        w = skin.sliderknb_w,
                        h = slidlen}
    obj.sections[5028] = {x = nnx, --sz+10-12-skin.rotknb_w,
                        y = 15+toff,
                        w = skin.rotknb_w,
                        h = skin.rotknb_w}

    --record
    obj.sections[5070] = {x = nnx,
                          y = 10,
                          w = skin.rotknb_w,
                          h = 30}
    --fx bypass
    local bw = math.max(math.min(ww-16,50),28)
    local bx = --[[(obj.sections[5026].x+obj.sections[5026].w) +]] math.floor(ww/2) - math.floor(bw/2) +1
    obj.sections[5071] = {x = bx,
                          y = 10+poff,
                          w = bw,
                          h = 25}
    --mute
    obj.sections[5073] = {x = bx,
                          y = 38+poff,
                          w = bw,
                          h = 30}
    --solo
    obj.sections[5074] = {x = bx,
                          y = 70+poff,
                          w = bw,
                          h = 30}
    --phase
    obj.sections[5072] = {x = bx,
                          y = 102+poff,
                          w = bw,
                          h = 25}
    --master
    obj.sections[5075] = {x = bx,
                          y = 10,
                          w = bw,
                          h = 30}


    --sends/receives
    lvar.sndpnl_cwidth = sz-10
    lvar.sndpnl_maxsize = obj.sections[4999].x + obj.sections[4999].w - (obj.sections[5005].x+obj.sections[5005].w)-20
    lvar.sndpnl_maxrows = math.min(math.floor(lvar.sndpnl_maxsize/(lvar.sndpnl_cwidth+10)),lvar.dm_maxvissends)

    local sw = lvar.sndpnl_maxrows * (lvar.sndpnl_cwidth+10)
    obj.sections[5030] = {x = obj.sections[5005].x+math.floor(obj.sections[5005].w) + math.floor(lvar.sndpnl_maxsize/2) - math.floor(sw/2) +10,
                          y = obj.sections[4999].y-lvar.trmix_h,
                          w = sw,
                          h = lvar.trmix_h}
    local slidlen = lvar.trmix_h - 180
    obj.sections[5031] = {x = 10,
                        y = 155,--math.floor(skin.sliderknb_h/2),
                        w = sz-20,
                        h = slidlen}
    obj.sections[5032] = {x = 10,
                        y = 45,
                        w = sz-20,
                        h = skin.rotknb_w}

    --Btn Panel
    local hh = obj.sections[5030].h-10
    local rows = math.floor((hh-20)/(msz+10))
    hh = rows*(msz+10)
    --[[obj.sections[5040] = {x = obj.sections[10].x+10,
                          y = obj.sections[5030].y+10,
                          w = obj.sections[5005].x - (obj.sections[10].x+10) - 10,
                          h = obj.sections[5030].h-10}]]
    local p1ww = panelw --obj.sections[5005].x - (obj.sections[10].x+10) - 10
    obj.sections[5040] = {x = obj.sections[10].x+10,
                          y = obj.sections[4999].y-hh,
                          w = p1ww,
                          h = obj.sections[5030].h-10}
    --Btn Panel 2
    local pw = obj.sections[4999].x+obj.sections[4999].w - (obj.sections[5005].x+obj.sections[5008].x+obj.sections[5008].w+10) --math.ceil((obj.sections[5005].x+obj.sections[5005].w)/(sz+10))*(sz+10)
    local pww = pw
    local px = (obj.sections[4999].x+obj.sections[4999].w-pw)
    local pxx = (obj.sections[4999].x+obj.sections[4999].w-pww)
    local cols = math.floor(pw/(msz+10))
    pw = cols*(msz+10)
    lvar.trmix_btnpnl2_cols = cols+1

    px = obj.sections[4999].x+obj.sections[4999].w - pw
    obj.sections[5042] = {x = px,
                          y = obj.sections[5040].y,
                          w = pw-10,
                          h = obj.sections[5040].h}

    local xp = math.floor((obj.sections[5040].w - msz)/(msz+10))*(msz+10)
    if lvar.trov_maxrows then
      --[[local mmovw = (lvar.dm_maxvistracks+1) * (obj.sections[5004].w + 10)-10
      local x5005 = math.max(obj.sections[4999].x + mmov + math.floor((obj.sections[4999].w-mmov)/2 - (mmovw/2)) + math.floor((obj.sections[5004].w + 10)/2), obj.sections[5004].x)
      local ww = x5005 - (obj.sections[10].x+10) - 10]]
      local ww = panelw
      lvar.trmix_btnpnl_maxcols = math.floor((ww+10)/(msz+10))
    end
    lvar.trmix_btnpnl_cols = math.min(math.floor((obj.sections[5040].w+10)/(msz+10)),lvar.trmix_btnpnl_maxcols or 99)
    lvar.trmix_btnpnl_rows = rows --math.floor((obj.sections[5040].h+10)/(sz+10))

    obj.sections[5043] = {x = obj.sections[5040].x,
                          y = obj.sections[4999].y-lvar.trmix_h,
                          w = obj.sections[5040].w,
                          h = obj.sections[5040].h}
    obj.sections[5044] = {x = pxx,
                          y = obj.sections[4999].y-lvar.trmix_h,
                          w = pww,
                          h = obj.sections[5042].h}
    obj.sections[5045] = {x = obj.sections[5040].x,
                          y = obj.sections[4999].y-lvar.trmix_h,
                          w = lvar.trmix_btnpnl_cols*(msz+10),
                          h = obj.sections[5040].y - obj.sections[5024].y}--lvar.trmix_h-obj.sections[5040].h}

    --panel sizer
    obj.sections[5081] = {x = obj.sections[5005].x+obj.sections[5005].w+5,
                          y = obj.sections[5024].y,
                          w = 10,
                          h = lvar.trmix_h}

    return obj
  end

  function PosGfxOptCtls(obj)

    --LBL OPTIONS
    --EDIT
    obj.sections[140] = {x = math.floor(obj.sections[49].x+20*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 0)*pnl_scale),
                        w = math.floor(obj.sections[49].w-40*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}

    local yo = 5
    obj.sections[141] = {x = math.floor(obj.sections[49].x+50*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 2 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-60*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[142] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 3 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[143] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 4 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[144] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 5 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[145] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 6 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[151] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 7 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[146] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 8 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[147] = {x = math.floor(obj.sections[49].x+20*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 1)*pnl_scale),
                        w = math.floor(obj.sections[49].w-40*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[148] = {x = math.floor(obj.sections[49].x+50*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 9 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-60*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[149] = {x = math.floor(obj.sections[49].x+50*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 10 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-60*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[150] = {x = math.floor(obj.sections[49].x+50*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 11 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-60*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[910] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 0 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[911] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 1 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[913] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 3 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[914] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 4 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[915] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 5 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[916] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 6 + yo)*pnl_scale),
                        w = math.floor(obj.sections[49].w-85*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[912] = {x = math.floor(obj.sections[49].x+20*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 7 + 12)*pnl_scale),
                        w = math.floor(obj.sections[49].w-40*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[917] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                              y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 9)*pnl_scale),
                              w = math.floor(obj.sections[49].w-85*pnl_scale),
                              h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[918] = {x = math.floor(obj.sections[49].x+75*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 10)*pnl_scale),
                        w = math.floor(obj.sections[49].w-125*pnl_scale),
                        h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[919] = {x = math.floor(obj.sections[49].x+obj.sections[49].w-(40-butt_h/2+4)*pnl_scale),
                        y = math.floor(obj.sections[49].y+(butt_h+10 + (butt_h/2+4 + 10) * 11 + yo)*pnl_scale),
                        w = math.floor((butt_h/2+4)*pnl_scale),
                        h = math.floor((butt_h/2+4)*pnl_scale)}

    
    return obj

  end

  function PosGaugeEdCtls(obj)

    local gaw, gah = math.floor(320*pnl_scale), math.floor(500*pnl_scale)
    local gsw = math.floor(90*pnl_scale)
    local gofs = math.floor(270*pnl_scale)
    obj.sections[806] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + butt_h*pnl_scale),
                         w = math.floor(gaw-120*pnl_scale),
                         h = math.floor(gofs-100*pnl_scale)}

    obj.sections[801] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs - 8*pnl_scale),
                         w = gsw,
                         h = math.floor(butt_h*pnl_scale)}
    --radius, len
    obj.sections[802] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*4 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[803] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*5 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[804] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*6 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[805] = {x = math.floor(obj.sections[800].x + 60*pnl_scale + gsw/2),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+8) +18)*pnl_scale),
                         w = math.floor(gsw/2),
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[807] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*7 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[808] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*8 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    --x, y
    obj.sections[809] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs +(-8 + (butt_h/2+13)*0)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[810] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs +(-8 + (butt_h/2+13)*1)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[811] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + 25*pnl_scale),
                         w = math.floor(50*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[812] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + (25+ butt_h)*pnl_scale),
                         w = math.floor(50*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[813] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + (25 + butt_h*2)*pnl_scale),
                         w = math.floor(50*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[814] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*4 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[815] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 - 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2)*pnl_scale),
                         w = math.floor(120*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[816] = {x = math.floor(obj.sections[800].x +5*pnl_scale),
                         y = math.floor(obj.sections[800].y + 25*pnl_scale),
                         w = math.floor(35*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[817] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*5 -20)*pnl_scale),
                         w = math.floor(35*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[827] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 105*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*6 -20)*pnl_scale),
                         w = math.floor((butt_h/2+4)*pnl_scale),
                         h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[832] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + (105 + butt_h)*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*6 -20)*pnl_scale),
                         w = math.floor((butt_h/2+4)*pnl_scale),
                         h = math.floor((butt_h/2+4)*pnl_scale)}

    obj.sections[818] = {x = math.floor(obj.sections[800].x + 60*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+8) - 4)*pnl_scale),
                         w = gsw,
                         h = math.floor(butt_h*pnl_scale)}

    obj.sections[823] = {x = math.floor(obj.sections[800].x + 15*pnl_scale),
                         y = math.floor(obj.sections[800].y + obj.sections[800].h - (butt_h*1.5 + 8)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h*1.5)*pnl_scale)}
    obj.sections[824] = {x = math.floor(obj.sections[823].x + obj.sections[823].w + 10*pnl_scale),
                         y = math.floor(obj.sections[823].y),
                         w = gsw,
                         h = math.floor((butt_h*1.5)*pnl_scale)}
    obj.sections[819] = {x = math.floor(obj.sections[824].x + obj.sections[824].w + 10*pnl_scale),
                         y = math.floor(obj.sections[823].y),
                         w = gsw,
                         h = math.floor((butt_h*1.5)*pnl_scale)}

    obj.sections[820] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - (53 + butt_h)*pnl_scale),
                         y = math.floor(obj.sections[800].y + 27*pnl_scale),
                         w = math.floor((butt_h/2+4)*pnl_scale),
                         h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[821] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - (53 + butt_h)*pnl_scale),
                         y = math.floor(obj.sections[800].y + (27+ butt_h)*pnl_scale),
                         w = math.floor((butt_h/2+4)*pnl_scale),
                         h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[822] = {x = math.floor(obj.sections[800].x + obj.sections[800].w - (53 + butt_h)*pnl_scale),
                         y = math.floor(obj.sections[800].y + (27 + butt_h*2)*pnl_scale),
                         w = math.floor((butt_h/2+4)*pnl_scale),
                         h = math.floor((butt_h/2+4)*pnl_scale)}
    obj.sections[825] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 55*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*7 -20)*pnl_scale),
                         w = gsw,
                         h = math.floor((butt_h/2+8)*pnl_scale)}

    obj.sections[826] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 79*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2+1)*pnl_scale),
                         w = math.floor(60*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}

    obj.sections[833] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 79*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2+1)*pnl_scale - butt_h*pnl_scale-2),
                         w = math.floor(60*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}

    obj.sections[828] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 - 140*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2+1)*pnl_scale),
                         w = math.floor(30*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[829] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 - 108*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2+1)*pnl_scale),
                         w = math.floor(30*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[830] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 - (140 +1)*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs -(butt_h*2+3 + (butt_h/2+8))*pnl_scale),
                         w = math.floor(60*pnl_scale),
                         h = math.floor((butt_h/2+8)*pnl_scale)}
    obj.sections[831] = {x = math.floor(obj.sections[800].x + obj.sections[800].w/2 + 35*pnl_scale),
                         y = math.floor(obj.sections[800].y + gofs + ((butt_h/2+13)*3 -26)*pnl_scale),
                         w = math.floor(gsw+20*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}

    return obj
  end

  function PosCycleCtls(obj)

    local xofft, yoff, yoffm, bh, bw, sw = math.floor(200*pnl_scale), math.floor(28*pnl_scale), math.floor((butt_h/2+14)*pnl_scale), math.floor((butt_h/2+4)*pnl_scale), math.floor((butt_h/2+4)*pnl_scale), math.floor(80*pnl_scale)
    local kw,_ = gfx.getimgdim(0)
    local kh = defctls[def_knob].cellh
    obj.sections[101] = {x = obj.sections[100].x+obj.sections[100].w/2-kw/2,
                         y = math.floor(obj.sections[100].y+(butt_h/2 +4)*pnl_scale),
                         w = kw,
                         h = kh}
    obj.sections[102] = {x = math.floor(obj.sections[100].x+obj.sections[100].w-(40+10)*pnl_scale),
                         y = math.floor(obj.sections[101].y+obj.sections[101].h+butt_h*pnl_scale),
                         w = math.floor(40*pnl_scale),
                         h = bh}

    local yy = math.floor(obj.sections[102].y+bh+(60+butt_h)*pnl_scale)

    obj.sections[103] = {x = math.floor(obj.sections[100].x+8*pnl_scale),
                         y = yy,
                         w = math.floor(obj.sections[100].w-16*pnl_scale),
                         h = math.floor(obj.sections[100].h - (yy-obj.sections[100].y + butt_h*pnl_scale + 10))} --(butt_h*8)*pnl_scale}

    obj.sections[104] = {x = obj.sections[102].x,
                         y = math.floor(obj.sections[102].y-bh-2*pnl_scale),
                         w = math.floor(40*pnl_scale),
                         h = obj.sections[102].h}
    obj.sections[110] = {x = math.floor(obj.sections[100].x +45*pnl_scale),
                         y = math.floor(obj.sections[102].y-bh-2*pnl_scale),
                         w = math.floor(40*pnl_scale),
                         h = obj.sections[102].h}


    obj.sections[105] = {x = obj.sections[103].x,
                         y = math.floor(obj.sections[103].y-butt_h*pnl_scale),
                         w = obj.sections[103].w,
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[106] = {x = math.floor(obj.sections[103].x-2*pnl_scale),
                         y = math.floor(obj.sections[103].y+obj.sections[103].h+2*pnl_scale),
                         w = math.floor(obj.sections[103].w+4*pnl_scale),
                         h = math.floor(butt_h*pnl_scale)}
    obj.sections[107] = {x = obj.sections[102].x,
                         y = math.floor(obj.sections[102].y+obj.sections[102].h+4*pnl_scale),
                         w = bh,
                         h = bh}
    obj.sections[109] = {x = obj.sections[107].x,
                         y = math.floor(obj.sections[107].y+obj.sections[107].h+4*pnl_scale),
                         w = bh,
                         h = bh}
    obj.sections[108] = {x = obj.sections[107].x,
                         y = math.floor(obj.sections[109].y+obj.sections[107].h+4*pnl_scale),
                         w = bh,
                         h = bh}

    obj.sections[111] = {x = obj.sections[107].x + obj.sections[107].w + 10,
                         y = math.floor(obj.sections[102].y+obj.sections[102].h+4*pnl_scale),
                         w = bh,
                         h = bh}
    return obj

  end
  -----------------------------------------------------------------------

  function GetGUI_vars()
    gfx.mode = gmode

    local gui = {}
      gui.aa = 1
      gui.fontname = fontname_def
      gui.fontsize_tab = 20
      gui.fontsz_knob = fontsize_def
      --gui.fontsz_get = fontsize_def

      if OS == "OSX32" or OS == "OSX64" then gui.fontsize_tab = gui.fontsize_tab - 5 end
      if OS == "OSX32" or OS == "OSX64" then gui.fontsz_knob = gui.fontsz_knob - 5 end
      --if OS == "OSX32" or OS == "OSX64" then gui.fontsz_get = gui.fontsz_get - 5 end

      gui.color = {['back'] = '71 71 71 ',
                 ['back2'] = '51 63 56',
                 ['black'] = '0 0 0',
                 ['green'] = '102 255 102',
                 ['green1'] = '0 120 169', --'0 156 36',
                 ['green_dark1'] = '0 76 0',
                 ['blue'] = '127 204 255',
                 ['white'] = '255 255 255',
                 ['red'] = '255 0 0',
                 ['green_dark'] = '102 153 102',
                 ['yellow'] = '200 200 0',
                 ['yellow1'] = '160 160 0',
                 ['bryellow'] = '220 220 0',
                 ['bryellow1'] = '255 255 0',
                 ['cbobg'] = '4 4 4',
                 ['cbobg2'] = '64 64 64',
                 ['grey'] = '0 13 25', --'64 64 64',
                 ['grey1'] = '0 25 50', --'32 32 32',
                 ['dgrey1'] = '0 25 50', --'16 16 16',
                 ['dgrey2'] = '16 16 16',
                 ['red1'] = '165 8 46',
                 ['red2'] = '93 4 28',
                 ['red3'] = '200 13 66',
                 ['blue1'] = '0 120 169',
                 ['dblue1'] = '0 25 50',
                 ['backg'] = '5 0 10'
               }

      SetSkinCols(gui)
    return gui
  end
  ------------------------------------------------------------

  function MacRevC(c)
    local b = (c & 255)
    local g = (c >> 8 & 255)
    local r = (c >> 16 & 255)
    local ret = (b << 16) + (g << 8) + r
    return ret
  end

  function f_Get_SSV(s)
    if not s then return end
    local t = {}
    for i in s:gmatch("[%d%.]+") do
      t[#t+1] = tonumber(i) / 255
    end
    gfx.r, gfx.g, gfx.b = t[1], t[2], t[3]
  end

  function ConvertColor(c)
    local r = (c & 255)
    local g = (c >> 8 & 255)
    local b = (c >> 16 & 255)
    return math.floor(r) .. ' ' .. math.floor(g) .. ' ' .. math.floor(b)
  end

  function ConvertColorString(s)
    if not s then return end
    local t = {}
    for i in s:gmatch("[%d%.]+") do
      t[#t+1] = tonumber(i)
    end
    return t[1] + (t[2] << 8) + (t[3] << 16)
  end

  ------------------------------------------------------------

  function GUI_text(gui, xywh, text)
        f_Get_SSV(gui.color.white)
        gfx.a = 1
        gfx.setfont(1, gui.fontname, gui.fontsz_knob)
        local text_len = gfx.measurestr(text)
        gfx.x, gfx.y = xywh.x+(xywh.w-text_len)/2,xywh.y+(xywh.h-gfx.texth)/2 + 1
        gfx.drawstr(text)
  end

  function GUI_textXY(gui, x, y, text, col, fsz)
        f_Get_SSV(col)
        gfx.a = 1
        gfx.x, gfx.y = x,y
        gfx.drawstr(text)
  end

  function GUI_textsm_LJ(gui, xywh, text, c, offs, limitx)
        text = nz(text,'')
        f_Get_SSV(c)
        gfx.a = 1
        gfx.setfont(1, gui.fontname, gui.fontsz_knob + offs)
        local text_len, newlen = gfx.measurestr(text), string.len(text)
        if limitx ~= nil and text_len+4 > limitx then
          for l = string.len(text), 1, -2 do
            text_len = gfx.measurestr(string.sub(text,0,l))+4
            if text_len <= limitx then newlen = l break end
          end
        end
        gfx.x, gfx.y = xywh.x+4,xywh.y+(xywh.h-gfx.texth)/2 + 1
        gfx.drawstr(string.sub(text,1,newlen))
  end

  function GUI_textsm_CJ(gui, xywh, text, c, offs, limitx)
        text = nz(text,'')
        f_Get_SSV(c)
        gfx.a = 1
        gfx.setfont(1, gui.fontname, gui.fontsz_knob + offs)
        local text_len, newlen = gfx.measurestr(text), string.len(text)
        if limitx ~= nil and text_len+4 > limitx then
          for l = string.len(text), 1, -2 do
            text_len = gfx.measurestr(string.sub(text,0,l))+4
            if text_len <= limitx then newlen = l break end
          end
        end
        gfx.x, gfx.y = xywh.x+(xywh.w-text_len)/2,xywh.y+(xywh.h-gfx.texth)/2 + 1
        gfx.drawstr(string.sub(text,1,newlen))
  end

  function GUI_textsm_RJ(gui, xywh, text, c, offs)
        f_Get_SSV(c)
        gfx.a = 1
        gfx.setfont(1, gui.fontname, gui.fontsz_knob + offs)
        local text_len = gfx.measurestr(text)
        gfx.x, gfx.y = xywh.x+xywh.w-text_len, xywh.y+(xywh.h-gfx.texth)/2 + 1
        gfx.drawstr(text)
  end

  function GUI_textC(gui, xywh, text, color, offs, alpha, yoff)
        f_Get_SSV(color)
        if alpha then gfx.a = alpha else gfx.a = 1 end
        if yoff == nil then yoff = 0 end
        gfx.setfont(1, gui.fontname, gui.fontsz_knob + offs)
        local text_len = gfx.measurestr(text)
        gfx.x, gfx.y = xywh.x+(xywh.w-text_len)/2,xywh.y+(xywh.h-gfx.texth)/2 + 1 + yoff
        gfx.drawstr(text)
  end

  function GUI_textC_shadow(gui, xywh, text, color, offs, alpha, yoff, colshad, flags, fontnm)
        if alpha then gfx.a = alpha else gfx.a = 1 end
        if yoff == nil then yoff = 0 end
        if fontnm == nil then fontnm = gui.fontname end
        gfx.setfont(1, fontnm, gui.fontsz_knob + offs, flags)
        local text_len = gfx.measurestr(text)
        local x = xywh.x+(xywh.w-text_len)/2+2
        local y = xywh.y+(xywh.h-gfx.texth)/2 + 1 + yoff+2
        if colshad ~= '' then
          gfx.x, gfx.y = x,y
          f_Get_SSV(colshad)
          gfx.a = 0.5
          gfx.drawstr(text)
          gfx.x, gfx.y = x-1,y-1
          gfx.a = 1
          gfx.drawstr(text)
        end
        gfx.x, gfx.y = x-2, y-2
        f_Get_SSV(color)
        gfx.drawstr(text)
  end

  function GUI_StrFontOnly(gui, size_offset, fontnm, flags)

    gfx.setfont(1, fontnm or gui.fontname, gui.fontsz_knob + size_offset, flags)

  end

  function GUI_Str(gui, xywh, text, justify, color, size_offset, alpha, shadowcol, fontnm, flags)

    --Could size_offset need to be different for Mac?
    gfx.setfont(1, fontnm or gui.fontname, gui.fontsz_knob + size_offset, flags)

    if (shadowcol or '') ~= '' then
      gfx.x, gfx.y = xywh.x+2, xywh.y+2
      f_Get_SSV(shadowcol)
      gfx.a = (alpha or 1)*0.5
      gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
      gfx.x, gfx.y = xywh.x+1, xywh.y+1
      gfx.a = alpha or 1
      gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
    end
    gfx.x, gfx.y = xywh.x, xywh.y
    gfx.a = alpha or 1
    f_Get_SSV(color)
    gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)

    return gfx.measurestr(text)
  end

  function GUI_StrB(gui, xywh, text, justify, color, size_offset, alpha, shadowcol, fontnm, flags, backcolor)

    --Could size_offset need to be different for Mac?
    gfx.setfont(1, fontnm or gui.fontname, gui.fontsz_knob + size_offset, flags)
    if backcolor then
      local w, h = gfx.measurestr(text)
      local ho = math.floor((xywh.h-h)/2)
      f_Get_SSV(backcolor)
      if justify == 4 then
        gfx.rect(xywh.x-4,xywh.y+ho,w,h,1)
      elseif justify == 5 then
        gfx.rect(xywh.x-4+math.floor(xywh.w/2)-math.floor(w/2),xywh.y+ho,w,h,1)
      elseif justify == 6 then
        gfx.rect(xywh.x-4+xywh.w-w,xywh.y+ho,w,h,1)
      end
    end
    if (shadowcol or '') ~= '' then
      gfx.x, gfx.y = xywh.x+2, xywh.y+2
      f_Get_SSV(shadowcol)
      gfx.a = 0.5
      gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
      gfx.x, gfx.y = xywh.x+1, xywh.y+1
      gfx.a = alpha or 1
      gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
    end
    gfx.x, gfx.y = xywh.x, xywh.y
    gfx.a = alpha or 1
    f_Get_SSV(color)
    gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
  end

  function GUI_textCtl(gui, xywh, text, color, offs, alpha, yoff)
    f_Get_SSV(color)
    if alpha then gfx.a = alpha else gfx.a = 1 end
    if yoff == nil then yoff = 0 end
    local text_len = gfx.measurestr(text)
    gfx.x, gfx.y = xywh.x+(xywh.w-text_len)/2,xywh.y+(xywh.h-gfx.texth)/2 + 1 + yoff
    gfx.drawstr(text)
  end

  function GUI_textCtl2(gui, xywh, text, color, offs, alpha, flags)
    f_Get_SSV(color)
    if alpha then gfx.a = alpha else gfx.a = 1 end
    gfx.x, gfx.y = xywh.x,xywh.y
    gfx.drawstr(text, flags, xywh.x+xywh.w,xywh.y+xywh.h)
  end

  function GUI_textC_LIM(gui, xywh, text, color, offs, colshad, flags, fontnm, justify)
        text = nz(text,'')
        if fontnm == nil then fontnm = gui.fontname end
        gfx.setfont(1, fontnm, gui.fontsz_knob + offs, flags)
        if colshad == nil then colshad = '' end
        if colshad ~= '' then
          gfx.x, gfx.y = xywh.x+2, xywh.y+2
          f_Get_SSV(colshad)
          gfx.a = 0.5
          gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
          gfx.x, gfx.y = xywh.x+1, xywh.y+1
          gfx.a = 1
          gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
        end
        f_Get_SSV(color)
        gfx.a = 1
        gfx.x, gfx.y = xywh.x, xywh.y
        gfx.drawstr(text,justify,xywh.x+xywh.w,xywh.y+xywh.h)
  end

  ------------------------------------------------------------

  function CropFXName(n)

    if n == nil then
      return ""
    else
      local fxn = string.match(n, ': (.+)%(')
      if fxn then
        return fxn
      else
        fxn = string.match(n, '.+/(.*)')
        if fxn and fxn ~= '' then
          return fxn
        else
          return n
        end
      end
    end

  end

  function CropFXName2(n)

    if n == nil then
      return ""
    else
      local fxn = string.match(n, ': (.-)%(')
      if fxn then
        return fxn
      else
        fxn = string.match(n, '.+/(.*)')
        if fxn and fxn ~= '' then
          return fxn
        else
          return n
        end
      end
    end

  end

  function CropFXName3(n)

    if n == nil then
      return
    else
      local fxn = string.match(n, ': (.-)%(')
      if fxn then
        return fxn
      else
        fxn = string.match(n, '.+/(.*)')
        if fxn and fxn ~= '' then
          return fxn
        else
          return n
        end
      end
    end

  end
------------------------------------------------------------

  function Strip_AddGFX(type)

    --loadimg and set imageidx in graphics_files and strip.graphics
    if tracks[track_select] then

      local strip = Strip_INIT()

      if type == lvar.gfxtype.img then
        if graphics_files[graphics_folder_files[gfx_select]].imageidx == nil then
          local iidx = LoadGraphics(graphics_files[graphics_folder_files[gfx_select]].fn)
          if iidx then
            local w, h = gfx.getimgdim(iidx)
            if w == 0 or h == 0 then OpenMsgBox(1, 'Invalid gfx file: '..graphics_files[graphics_folder_files[gfx_select]].fn, 1) return end

            if iidx > image_count then
              image_count = iidx
            end
            graphics_files[graphics_folder_files[gfx_select]].imageidx = iidx
          end
          --[[image_count = F_limit(image_count + 1,0,image_max)
          gfx.loadimg(image_count, paths.graphics_path..graphics_files[gfx_select].fn)
          graphics_files[gfx_select].imageidx = image_count]]
        end

        local x,y
        --x = math.floor(((draggfx.x-obj.sections[10].x)/lvar.zoom)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.x/settings_gridsize)*settings_gridsize -- math.floor((obj.sections[10].x)/settings_gridsize)*settings_gridsize
        --y = math.floor(((draggfx.y-obj.sections[10].y)/lvar.zoom)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.y/settings_gridsize)*settings_gridsize -- math.floor((obj.sections[10].y)/settings_gridsize)*settings_gridsize

        x = round(((draggfx.x - obj.sections[10].x + surface_offset.x*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize
        y = round(((draggfx.y - obj.sections[10].y + surface_offset.y*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize

        --x = math.floor((draggfx.x/lvar.zoom)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.x/settings_gridsize)*settings_gridsize - math.floor((obj.sections[10].x)/settings_gridsize)*settings_gridsize
        --y = math.floor((draggfx.y/lvar.zoom)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.y/settings_gridsize)*settings_gridsize - math.floor((obj.sections[10].y)/settings_gridsize)*settings_gridsize
        local w, h = gfx.getimgdim(graphics_files[graphics_folder_files[gfx_select]].imageidx)
        gfxnum = #strips[strip][page].graphics + 1
        strips[strip][page].graphics[gfxnum] = {g_id = GenID(),
                                          gfxtype = type,
                                          fn = graphics_files[graphics_folder_files[gfx_select]].fn,
                                          imageidx = graphics_files[graphics_folder_files[gfx_select]].imageidx,
                                          x = x,
                                          y = y,
                                          w = w,
                                          h = h,
                                          scale = 1,
                                          stretchw = w,
                                          stretchh = h,
                                          font = {idx = nil,
                                                  name = nil,
                                                  size = nil,
                                                  bold = nil,
                                                  italics = nil,
                                                  underline = nil,
                                                  vertical = nil,
                                                  shadow = nil
                                                  },
                                          text = nil,
                                          text_col = nil,
                                          poslock = false,
                                          bright = 0.5,
                                          contr = 0.5,
                                          rmult = 0.5,
                                          gmult = 0.5,
                                          bmult = 0.5,
                                          alpha = 1,
                                          shadow = false,
                                          stretchmode = 1,
                                          edgesz = 8,
                                         }
      elseif type == lvar.gfxtype.txt then
        local x,y
        x = math.floor((label_add.x)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.x/settings_gridsize)*settings_gridsize - math.floor((obj.sections[10].x)/settings_gridsize)*settings_gridsize
        y = math.floor((label_add.y)/settings_gridsize)*settings_gridsize + math.floor(surface_offset.y/settings_gridsize)*settings_gridsize - math.floor((obj.sections[10].y)/settings_gridsize)*settings_gridsize
        local w, h = 50, 50--gfx.getimgdim(graphics_files[gfx_select].imageidx)
        gfxnum = #strips[strip][page].graphics + 1
        strips[strip][page].graphics[gfxnum] = {g_id = GenID(),
                                          gfxtype = type,
                                          fn = '',
                                          imageidx = -1,
                                          x = x,
                                          y = y,
                                          w = w,
                                          h = h,
                                          scale = 1,
                                          stretchw = w,
                                          stretchh = h,
                                          font = {idx = gfx_font_select.idx,
                                                  name = gfx_font_select.name,
                                                  size = gfx_font_select.size,
                                                  bold = gfx_font_select.bold,
                                                  italics = gfx_font_select.italics,
                                                  underline = gfx_font_select.underline,
                                                  vertical = gfx_font_select.vertical,
                                                  shadow = gfx_font_select.shadow,
                                                  shadow_x = gfx_font_select.shadow_x,
                                                  shadow_y = gfx_font_select.shadow_y,
                                                  shadow_a = gfx_font_select.shadow_a
                                                  },
                                          text = gfx_text_select,
                                          text_col = gfx_textcol_select,
                                          poslock = false
                                         }

      end
    end

  end

------------------------------------------------------------

  function Strip_INIT(trn)

    local track_select = trn or track_select
    if tracks[track_select] then

      local strip

      if tracks[track_select].strip == -1 then
        strip = #strips+1
        strips[strip] = {track = tracks[track_select], page = page, {}}
        for i = 1, lvar.maxpage do
          strips[strip][i] = {surface_x = 0,
                             surface_y = 0,
                             controls = {},
                             graphics = {}}
          Snapshots_INIT()
          --[[if snapshots and snapshots[strip] then
            snapshots[strip][i] = {}
            snapshots[strip][i][1] = {morph_time = 0,
                                      morph_sync = false,
                                      morph_syncv = 15,
                                      morph_scale = 1}
          end]]
        end
        tracks[track_select].strip = strip
      else
        strip = tracks[track_select].strip
      end

      return strip

    end

  end

  --[[function Strip_INIT2(trguid)

    local strip
    if not lvar.stripstore[trguid] then
      strip = #strips+1
      strips[strip] = {dm_trguid = trguid, track = tracks[track_select], page = page, {}}
      for i = 1, lvar.maxpage do
        strips[strip][i] = {surface_x = 0,
                           surface_y = 0,
                           controls = {},
                           graphics = {}}
        Snapshots_INIT()

      end
    else
      strip = lvar.stripstore[trguid].strip
    end

    return strip

  end]]

------------------------------------------------------------

  function Strip_AddParam()

    if tracks[track_select] then

      local strip = Strip_INIT()

      if ctl_files[knob_select].imageidx == nil then
        image_count = F_limit(image_count + 1,0,image_max)
        gfx.loadimg(image_count, paths.controls_path..ctl_files[knob_select].fn)
        ctl_files[knob_select].imageidx = image_count
      end

      local x,y, stripid_add, parent_switcher, swid_grpid
      if mode == 0 and lvar.livemode >= 1 then
        local strip = tracks[track_select].strip
        local _, stripidx, stripid = GetControlAtXY(strip, page, dragparam.x, dragparam.y)
        if stripidx and lvar.stripdim then
          local xx, yy = TranslateMixPos(mouse.mx, mouse.my, nil, lvar.stripdim.swidx[stripid])
          local w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
          x, y = math.floor(xx-(w/2)), math.floor(yy-(h/2))
          stripid_add = stripid
          parent_switcher = tonumber(Switcher_GetTopLevelSwitcher(lvar.stripdim.swidx[stripid]))
          swid_grpid = switchers[parent_switcher].current
          if not x or not y or not stripid_add or not parent_switcher or not swid_grpid then
            return
          end
          if x < lvar.stripdim.swdata[parent_switcher].l or x+w > lvar.stripdim.swdata[parent_switcher].r or
             y < lvar.stripdim.swdata[parent_switcher].t or y+h > lvar.stripdim.swdata[parent_switcher].b then
            return
          end
        else
          return
        end
      else
        dragparam.x = dragparam.x-obj.sections[10].x
        dragparam.y = dragparam.y-obj.sections[10].y
        x = round(((dragparam.x + surface_offset.x*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize
        y = round(((dragparam.y + surface_offset.y*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize
      end

      --x = round((dragparam.x)/settings_gridsize)*settings_gridsize
      --    + round(surface_offset.x/settings_gridsize)*settings_gridsize - round((obj.sections[10].x)/settings_gridsize)*settings_gridsize
      --y = round((dragparam.y)/settings_gridsize)*settings_gridsize
      --    + round(surface_offset.y/settings_gridsize)*settings_gridsize - round((obj.sections[10].y)/settings_gridsize)*settings_gridsize
      local w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
      ctlnum = #strips[strip][page].controls + 1
      if dragparam.type == 'track' then
        local ccats = ctlcats.fxparam
        local cts = ctltype_select
        local spv = show_paramval
        local toff = textoff_select
        local param = trackfxparam_select

        if trackfxparam_select == #trackfxparams-5 then
          ccats = ctlcats.gr_meter
          cts = 5
        
        elseif trackfxparam_select == #trackfxparams-4 then
          ccats = ctlcats.fxoffline
          cts = 2
        elseif trackfxparam_select == #trackfxparams-3 then
          ccats = ctlcats.fxmulti
          cts = 2
        elseif trackfxparam_select == #trackfxparams-2 then
          ccats = ctlcats.fxgui
          cts = 2
          spv = false
          toff = 8
        elseif trackfxparam_select == #trackfxparams-1 then
          --dummy param
          param = -1
        elseif trackfxparam_select == #trackfxparams then
          --fx name
          cts = 5
          param = -2
        end

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ccats,
                                                fxname=trackfx[trackfx_select].name,
                                                fxguid=trackfx[trackfx_select].guid,
                                                fxnum=trackfx[trackfx_select].fxnum,
                                                fxfound = true,
                                                param = param,
                                                param_info = trackfxparams[trackfxparam_select],
                                                ctltype = cts,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = spv,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = toff,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = GetParamValue(ccats,
                                                                    tracks[trackedit_select].tracknum,
                                                                    trackfx[trackfx_select].fxnum,
                                                                    trackfxparam_select, nil),
                                                defval = GetParamValue(ccats,
                                                                    tracks[trackedit_select].tracknum,
                                                                    trackfx[trackfx_select].fxnum,
                                                                    trackfxparam_select, nil),
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                                }
        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'rcmswitch' then
        local ccats = ctlcats.rcm_switch
        local cts = 5
        local spv = true
        local toff = textoff_select
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ccats,
                                                fxname='RCM Switch',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = false,
                                                param = -1,
                                                param_info = {paramname = 'RCM (Unassigned)',
                                                              paramidx = nil},
                                                ctltype = cts,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = spv,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = toff,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                                }
        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'midimsgctl' then
        local ccats = ctlcats.midictl
        local cts = 1
        local spv = true
        local toff = textoff_select
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ccats,
                                                fxname='MIDI CTL',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = -1,
                                                param_info = {paramname = 'MIDI/OSC (Unassigned)',
                                                              paramidx = nil},
                                                ctltype = cts,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = spv,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = toff,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                                }
        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'learn' then
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.fxparam,
                                                fxname=last_touch_fx.fxname,
                                                fxguid=last_touch_fx.fxguid,
                                                fxnum=last_touch_fx.fxnum,
                                                fxfound = true,
                                                param = last_touch_fx.paramnum,
                                                param_info = {paramname = last_touch_fx.prname,
                                                              paramnum = last_touch_fx.paramnum},
                                                ctltype = ctltype_select,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = GetParamValue(ctlcats.fxparam,
                                                                    last_touch_fx.tracknum,
                                                                    last_touch_fx.fxnum,
                                                                    last_touch_fx.paramnum, nil),
                                                defval = GetParamValue(ctlcats.fxparam,
                                                                    last_touch_fx.tracknum,
                                                                    last_touch_fx.fxnum,
                                                                    last_touch_fx.paramnum, nil),
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = last_touch_fx.tracknum,
                                                trackguid = last_touch_fx.trguid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                                }
        if last_touch_fx.tracknum == strips[strip].track.tracknum then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'trctl' then
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.trackparam,
                                                fxname='Track Parameter',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Track '..trctls_table[trctl_select].name,
                                                              paramnum = trctl_select},
                                                ctltype = ctltype_select,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = GetParamValue(ctlcats.trackparam,
                                                                    tracks[trackedit_select].tracknum,
                                                                    nil,
                                                                    trctl_select, nil),
                                                defval = GetParamValue(ctlcats.trackparam,
                                                                    tracks[trackedit_select].tracknum,
                                                                    nil,
                                                                    trctl_select, nil),
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                                }
        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'trsnd' then
        --local unique, guid = CheckTrackUnique(trsends_table[trctl_select].sendname)

        --if unique == true then
          local sidx = math.floor((trctl_select-1) / 3)
          local pidx = (trctl_select-1) % 3 +1
          strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                  ctlcat = ctlcats.tracksend,
                                                  fxname='Track Send',
                                                  fxguid=nil,
                                                  fxnum=nil,
                                                  fxfound = true,
                                                  param = trctl_select,
                                                  param_info = {paramname = trsends_table[sidx][pidx].name,
                                                                paramnum = trctl_select,
                                                                paramidx = trsends_table[sidx].idx,
                                                                paramstr = trsends_table[sidx][pidx].parmname,
                                                                paramdesttrnum = trsends_table[sidx].desttracknum,
                                                                paramdestguid = trsends_table[sidx].desttrackguid,
                                                                paramdestchan = trsends_table[sidx].dstchan,
                                                                paramsrcchan = trsends_table[sidx].srcchan},
                                                  ctltype = ctltype_select,
                                                  knob_select = knob_select,
                                                  ctl_info = {fn = ctl_files[knob_select].fn,
                                                              frames = ctl_files[knob_select].frames,
                                                              imageidx = ctl_files[knob_select].imageidx,
                                                              cellh = ctl_files[knob_select].cellh},
                                                  x = x,
                                                  y = y,
                                                  w = w,
                                                  poslock = false,
                                                  scale = scale_select,
                                                  xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                  ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                  wsc = w*scale_select,
                                                  hsc = ctl_files[knob_select].cellh*scale_select,
                                                  show_paramname = show_paramname,
                                                  show_paramval = show_paramval,
                                                  ctlname_override = '',
                                                  font = ctlfont_select,
                                                  textcol = textcol_select,
                                                  textoff = textoff_select,
                                                  textoffval = textoffval_select,
                                                  textoffx = textoff_selectx,
                                                  textoffvalx = textoffval_selectx,
                                                  textsize = textsize_select,
                                                  textsizev = textsizev_select,
                                                  textcolv = textcolv_select,
                                                  enabledefval = enabledefval_select,
                                                  val = 0,
                                                  defval = 0,
                                                  maxdp = maxdp_select,
                                                  cycledata = {statecnt = 0,val = 0,mapptof = mapptof_select,draggable = draggable_select,spread = spread_select, {}},
                                                  xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                  membtn = {state = false,
                                                            mem = nil},
                                                  id = stripid_add,
                                                  switcher = parent_switcher,
                                                  grpid = swid_grpid,
                                                  tracknum = tracks[trackedit_select].tracknum,
                                                  trackguid = tracks[trackedit_select].guid,
                                                  scalemode = 8,
                                                  framemode = 1,
                                                  horiz = horiz_select,
                                                  poslock = false,
                                                  bypassbg_c = bypass_bgdraw_c_select,
                                                  bypassbg_n = bypass_bgdraw_n_select,
                                                  bypassbg_v = bypass_bgdraw_v_select,
                                                  clickthrough = clickthrough_select,
                                                  knobsens = table.copy(settings_defknobsens)
                                                  }

          if track_select == trackedit_select then
            strips[strip][page].controls[ctlnum].tracknum = nil
            strips[strip][page].controls[ctlnum].trackguid = nil
          end
          strips[strip][page].controls[ctlnum].val = GetParamValue(ctlcats.tracksend,
                                                                    tracks[trackedit_select].tracknum,
                                                                    nil,
                                                                    trctl_select, ctlnum)
          strips[strip][page].controls[ctlnum].defval = strips[strip][page].controls[ctlnum].val

        --else
          --not unique
        --  OpenMsgBox(1, 'Please ensure the target track name for send is unique.', 1)
        --end
      elseif dragparam.type == 'action' then
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.action,
                                                fxname='Action Trigger',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Unassigned Action',
                                                              paramidx = nil},
                                                ctltype = 9,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
      elseif dragparam.type == 'navictl' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.navictl,
                                                fxname='Navigation Ctl',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 1,
                                                param_info = {paramname = 'Navigation Ctl',
                                                              paramidx = -4,
                                                              paramnum = -4,
                                                              paramstr = nil},
                                                ctltype = 9,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

      elseif dragparam.type == 'pkmeter' then
        local tcs = trctl_select - special_offs
        --local pname = 'Tr' .. tracks[trackedit_select].tracknum .. ' '
        local pname = ''
        if tcs >= lvar.special_table_chans then
          pname = pname .. 'Ch' .. string.format('%i',tcs+1-lvar.special_table_chans)
          tcs = tcs - lvar.special_table_chans + 64
        else
          pname = pname .. 'Ch' .. string.format('%i',tcs+1)
        end
        if tcs >= 64 then
          pname = pname .. ' Clip'
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.pkmeter,
                                                fxname='Peak Meter',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = tcs,
                                                param_info = {paramname = pname,
                                                              paramnum = tcs,
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end
        lvar.readpeaks = PopReadPeaks()

      elseif dragparam.type == 'snapctl' then
        local pname = 'Page Snapshots'
        if sstype_select > 1 then
          pname = snapshots[strip][page][sstype_select].subsetname .. ' SNAPSHOTS'
        end

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.snapshot,
                                                fxname='Snapshot Selector',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = sstype_select,
                                                param_info = {paramname = pname,
                                                              paramidx = sstype_select},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = 1,
                                                xsc = x + math.floor(w/2 - (w*1)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*1)/2),
                                                wsc = w*1,
                                                hsc = ctl_files[knob_select].cellh*1,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 14.25,
                                                textoffval = -4.0,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
        StoreSnapshotControlIdxs(strip,page)

      elseif dragparam.type == 'xyctl' then
        local pname = 'XY'
        if snapshots[strip][page][sstype_select] then
          pname = snapshots[strip][page][sstype_select].subsetname
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.xy,
                                                fxname='XY Pad',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = sstype_select,
                                                param_info = {paramname = pname,
                                                              paramidx = sstype_select},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = 1,
                                                xsc = x + math.floor(w/2 - (w*1)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*1)/2),
                                                wsc = w*1,
                                                hsc = ctl_files[knob_select].cellh*1,
                                                show_paramname = show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 90.25,
                                                textoffval = -6.0,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
      elseif dragparam.type == 'macro' then
        local mcnt = 0
        for c = 1, #strips[strip][page].controls do
          if strips[strip][page].controls[c].ctlcat == ctlcats.macro and strips[strip][page].controls[c].macrotype == 0 then
            mcnt = mcnt + 1
          end
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.macro,
                                                macrotype = 0,
                                                fxname='Macro Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Macro '..string.format('%i',mcnt+1),
                                                              paramidx = nil},
                                                ctltype = 1,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

      elseif dragparam.type == 'macro_updateparam' then
        local mcnt = 0
        for c = 1, #strips[strip][page].controls do
          if strips[strip][page].controls[c].ctlcat == ctlcats.macro and strips[strip][page].controls[c].macrotype == 1 then
            mcnt = mcnt + 1
          end
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.macro_updateparam,
                                                macrotype = 1,
                                                fxname='Param Update Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Param UC'..string.format('%i',mcnt+1),
                                                              paramidx = nil},
                                                ctltype = 2,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

      elseif dragparam.type == 'paramvalue_glob' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.paramvalue_glob,
                                                macrotype = 1,
                                                fxname='Param Value Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Param Value Control',
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = false,
                                                show_paramval = true,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

      elseif dragparam.type == 'infoctl' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.infoctl,
                                                macrotype = 1,
                                                fxname='Info Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 1, --trctl_select,
                                                param_info = {paramname = 'Info Control',
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = false,
                                                show_paramval = true,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'sk2ctl' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.sk2ctl,
                                                macrotype = 1,
                                                fxname='SK2 Control (unassigned)',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 4, --trctl_select,
                                                param_info = {paramname = '',
                                                              paramidx = nil,
                                                              paramnum = 0},
                                                ctltype = ctltype_select,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = false,
                                                show_paramval = true,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end
        
      elseif dragparam.type == 'statectl' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.statectl,
                                                macrotype = 1,
                                                fxname='State Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 1, --trctl_select,
                                                param_info = {paramname = 'State Control',
                                                              paramidx = nil},
                                                ctltype = 1,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = false,
                                                show_paramval = true,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                stateinfo = {extname = nil,
                                                             key = nil,
                                                             min = 0,
                                                             max = 1,
                                                             step = 0.1},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'statectl_str' then

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.statectl_str,
                                                macrotype = 1,
                                                fxname='State Control (str)',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 1, --trctl_select,
                                                param_info = {paramname = 'State Control',
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = false,
                                                show_paramval = true,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                stateinfo = {extname = '[NoState]',
                                                             key = nil,
                                                             min = 0,
                                                             max = 1,
                                                             step = 0.1},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracks[trackedit_select].tracknum,
                                                trackguid = tracks[trackedit_select].guid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }

        if track_select == trackedit_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'eqcontrol' then
        local mcnt = 0
        for c = 1, #strips[strip][page].controls do
          if strips[strip][page].controls[c].ctlcat == ctlcats.eqcontrol then
            mcnt = mcnt + 1
          end
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.eqcontrol,
                                                fxname='EQ Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'EQ '..string.format('%i',mcnt+1),
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 1,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                knobsens = table.copy(settings_defknobsens),
                                                clickthrough = clickthrough_select,
                                                eqgraph = def_graph
                                               }

      elseif dragparam.type == 'rs5k' then
        local mcnt = 0
        for c = 1, #strips[strip][page].controls do
          if strips[strip][page].controls[c].ctlcat == ctlcats.rs5k then
            mcnt = mcnt + 1
          end
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.rs5k,
                                                fxname='RS5K Control',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'RS5K '..string.format('%i',mcnt+1),
                                                              paramidx = nil},
                                                ctltype = 1,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = textoff_select,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                knobsens = {norm = 0.05,
                                                            fine = 0.01,
                                                            wheel = 0.005,
                                                            wheelfine = 0.003},
                                                clickthrough = clickthrough_select,
                                                eqgraph = nil
                                               }


      elseif dragparam.type == 'switcher' then
        local swcnt = #switchers+1
        switchers[swcnt] = {grpids ={},
                            current = -1}

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.switcher,
                                                fxname='Strip Switcher',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Switcher '..string.format('%i',swcnt+1),
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 1,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                switcherid = swcnt,
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                knobsens = table.copy(settings_defknobsens),
                                                clickthrough = clickthrough_select,
                                                eqgraph = nil
                                               }


      elseif dragparam.type == 'snaprand' then
        local pname = 'RND PAGE'
        if sstype_select > 1 then
          pname = 'RND '..snapshots[strip][page][sstype_select].subsetname
        end

        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.snapshotrand,
                                                fxname='Snapshot Randomize',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = sstype_select,
                                                param_info = {paramname = pname,
                                                              paramidx = sstype_select},
                                                ctltype = 2,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = 1,
                                                xsc = x + math.floor(w/2 - (w*1)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*1)/2),
                                                wsc = w*1,
                                                hsc = ctl_files[knob_select].cellh*1,
                                                show_paramname = show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 0,
                                                textoffval = -6.0,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
      elseif dragparam.type == 'takeswitcher' then
        local pname = 'Take Selector'
        local item = reaper.GetSelectedMediaItem(0, 0)
        local iteminfo
        local itemno, tracknum, trackguid
        if item then
          iteminfo = GetMediaItemDetails(item)
          itemno = iteminfo.itemno
          tracknum = iteminfo.tracknum
          trackguid = iteminfo.trackguid
        else
          pname = 'Unassigned Take Selector'
        end
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.takeswitcher,
                                                fxname=pname,
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                iteminfo = iteminfo,
                                                param = itemno,
                                                param_info = {paramname = pname},
                                                ctltype = 1,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = 1,
                                                xsc = x + math.floor(w/2 - (w*1)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*1)/2),
                                                wsc = w*1,
                                                hsc = ctl_files[knob_select].cellh*1,
                                                show_paramname = show_paramname,
                                                show_paramval = show_paramval,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 40,
                                                textoffval = 0,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = tracknum,
                                                trackguid = trackguid,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                clickthrough = clickthrough_select,
                                                knobsens = table.copy(settings_defknobsens)
                                               }
        strips[strip][page].controls[ctlnum].knobsens.norm = 0.1
        strips[strip][page].controls[ctlnum].knobsens.wheel = 0.01

        if tracknum == track_select then
          strips[strip][page].controls[ctlnum].tracknum = nil
          strips[strip][page].controls[ctlnum].trackguid = nil
        end

      elseif dragparam.type == 'midieditor_pageswitch' then

        --param = off page, paramidx = on page
        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.midieditor_pageswitch,
                                                fxname='ME_PageSwitch',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = 1,
                                                param_info = {paramname = 'ME_PS',
                                                              paramidx = 2},
                                                ctltype = 5,
                                                knob_select = knob_select,
                                                ctl_info = {fn = ctl_files[knob_select].fn,
                                                            frames = ctl_files[knob_select].frames,
                                                            imageidx = ctl_files[knob_select].imageidx,
                                                            cellh = ctl_files[knob_select].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale_select,
                                                xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                                ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                                wsc = w*scale_select,
                                                hsc = ctl_files[knob_select].cellh*scale_select,
                                                show_paramname = show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = ctlfont_select,
                                                textcol = textcol_select,
                                                textoff = 1,
                                                textoffval = textoffval_select,
                                                textoffx = textoff_selectx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = textsize_select,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                id = stripid_add,
                                                switcher = parent_switcher,
                                                grpid = swid_grpid,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                knobsens = table.copy(settings_defknobsens),
                                                clickthrough = true,
                                                hidden = true,
                                               }
      end
    end

    GUI_DrawCtlBitmap()
    ctls_dnu, ctls_upd, ctls_orr = CtlDNU(ctlnum)

    return ctlnum
  end

  function Strip_AddSwitcher_Ext(x,y,knob_sel,cp_switchid,extpos,insertfx, fxloc)

    if tracks[track_select] then

      --knob_select = knob_sel or def_switchctl
      local scale = lvar.extswitch_format.scale
      local knob_select = lvar.extswitch_format.knob or def_switchctl
      local knob = knob_select

      local strip = Strip_INIT()

      if ctl_files[knob_select].imageidx == nil then
        image_count = F_limit(image_count + 1,0,image_max)
        gfx.loadimg(image_count, paths.controls_path..ctl_files[knob_select].fn)
        ctl_files[knob_select].imageidx = image_count
      end

      local w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
      ctlnum = #strips[strip][page].controls + 1

      local swcnt = #switchers+1
      switchers[swcnt] = {}

      if cp_switchid and switchers[cp_switchid] then
        switchers[swcnt] = table.copy(switchers[cp_switchid])
      else
        fxloc = 0
        if lvar.livemode ~= 2 then
          insertfx = true
        end
        extpos = 1
        switchers[swcnt].switchmode = 1
        switchers[swcnt].extendmode = true
        switchers[swcnt].extendid = GenID()
        switchers[swcnt].stripfolder = '__LBXFAVS' --strip_folders[1].fn
        switchers[swcnt].extenddir = 1
      end
      switchers[swcnt].grpids = {}
      switchers[swcnt].current = -1
      switchers[swcnt].extendpos = extpos
      switchers[swcnt].fxguids = nil

      local cp_c, cp_ctl
      if cp_switchid then
        cp_c = Switchers_FindCtl(cp_switchid)
        cp_ctl = strips[strip][page].controls[cp_c]
      end

      if cp_ctl then

        strips[strip][page].controls[ctlnum] = GetControlTable(strip,page,cp_c)
        local ctl = strips[strip][page].controls[ctlnum]
        ctl.switcherid = swcnt
        ctl.x = x
        ctl.y = y
        ctl.xsc = x + math.floor(ctl.w/2 - (ctl.w*ctl.scale)/2)
        ctl.ysc = y + math.floor(ctl_files[ctl.knob_select].cellh/2 - (ctl_files[ctl.knob_select].cellh*ctl.scale)/2)
        ctl.param_info = {paramname = '[INSERT]' --[['Switcher '..string.format('%i',swcnt+1)]],
                          paramidx = nil}
      else


        strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                                ctlcat = ctlcats.switcher,
                                                fxname='Strip Switcher',
                                                fxguid=nil,
                                                fxnum=nil,
                                                fxfound = true,
                                                param = trctl_select,
                                                param_info = {paramname = 'Switcher '..string.format('%i',swcnt+1),
                                                              paramidx = nil},
                                                ctltype = 5,
                                                knob_select = knob,
                                                ctl_info = {fn = ctl_files[knob].fn,
                                                            frames = ctl_files[knob].frames,
                                                            imageidx = ctl_files[knob].imageidx,
                                                            cellh = ctl_files[knob].cellh},
                                                x = x,
                                                y = y,
                                                w = w,
                                                poslock = false,
                                                scale = scale,
                                                xsc = x + math.floor(w/2 - (w*scale)/2),
                                                ysc = y + math.floor(ctl_files[knob].cellh/2 - (ctl_files[knob].cellh*scale)/2),
                                                wsc = w*scale,
                                                hsc = ctl_files[knob].cellh*scale,
                                                show_paramname = lvar.extswitch_format.show_paramname,
                                                show_paramval = false,
                                                ctlname_override = '',
                                                font = lvar.extswitch_format.font or ctlfont_select,
                                                textcol = lvar.extswitch_format.textcol,
                                                textoff = lvar.extswitch_format.textoff,
                                                textoffval = textoffval_select,
                                                textoffx = lvar.extswitch_format.textoffx,
                                                textoffvalx = textoffval_selectx,
                                                textsize = lvar.extswitch_format.textsize,
                                                textsizev = textsizev_select,
                                                textcolv = textcolv_select,
                                                enabledefval = enabledefval_select,
                                                val = 0,
                                                defval = 0,
                                                maxdp = maxdp_select,
                                                cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                                xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                                membtn = {state = false,
                                                          mem = nil},
                                                switcherid = swcnt,
                                                id = stripid_add,
                                                --switcher = parent_switcher,
                                                grpid = nil,
                                                tracknum = nil,
                                                trackguid = nil,
                                                scalemode = 8,
                                                framemode = 1,
                                                horiz = horiz_select,
                                                poslock = false,
                                                bypassbg_c = bypass_bgdraw_c_select,
                                                bypassbg_n = bypass_bgdraw_n_select,
                                                bypassbg_v = bypass_bgdraw_v_select,
                                                knobsens = table.copy(settings_defknobsens),
                                                clickthrough = clickthrough_select,
                                                eqgraph = nil,
                                                limittext = lvar.extswitch_format.limittext,
                                                wwtext = lvar.extswitch_format.wwtext,
                                                textflags = lvar.extswitch_format.textflags,
                                                adjust_active = lvar.extswitch_format.adjust_active or false,
                                                adjust = {bright = lvar.extswitch_format.adjust_bright or 255,
                                                          contrast = lvar.extswitch_format.adjust_contrast or 255,
                                                          r = lvar.extswitch_format.adjust_r or 255,
                                                          g = lvar.extswitch_format.adjust_g or 255,
                                                          b = lvar.extswitch_format.adjust_b or 255
                                                          }
                                               }
      end

      if insertfx == true then
        Switchers_AddInsertFX(swcnt, tracks[track_select].strip, page, ctlnum, fxloc)
      end

      return ctlnum, swcnt
    end
  end

  function GetMediaItemDetails(item, preservemaxtakes)

    tr = reaper.GetMediaItem_Track(item)

    local iteminfo = {}
    iteminfo.itemno = reaper.GetMediaItemInfo_Value(item, 'IP_ITEMNUMBER')
    iteminfo.tracknum = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')
    iteminfo.trackguid = GetTrackGUID(tr)

    if preservemaxtakes ~= true then
      iteminfo.maxtakes = takeswitch_max
    end

    if reaper.APIExists('BR_GetMediaItemGUID') == true then
      iteminfo.guid = reaper.BR_GetMediaItemGUID(item)
    else
      --item guid via track chunk?
    end
    iteminfo.numtakes = reaper.GetMediaItemNumTakes(item)
    local tkidx = reaper.GetMediaItemInfo_Value(item,'I_CURTAKE')
    if tkidx then
      local take = reaper.GetTake(item, tkidx)
      if take then
        _, iteminfo.curtake = reaper.GetSetMediaItemTakeInfo_String(take, 'P_NAME', '', false)
      end
    end

    return iteminfo
  end

  -------------------------------------------------------

  function PopulateStripFolders(sort)

    strip_folders = {}
    sflist_offset = 0

    local i = 0
    local sf = reaper.EnumerateSubdirectories(paths.strips_path,i)
    while sf ~= nil do
      strip_folders[i] = {fn = sf}
      i=i+1
      sf = reaper.EnumerateSubdirectories(paths.strips_path,i)
    end

    if sort then
      strip_folders = table_slowsort_gen2(strip_folders, 'fn', 0, true)
    end

  end

  -------------------------------------------------------

  function PopulateStrips(sort)

    strip_files = {}
    slist_offset = 0

    local i = 0
    local ii = 0
    if strip_folders[stripfol_select] then
      local sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[stripfol_select].fn,i)
      while sf ~= nil do
        if string.match(sf,'.+%.(.*)') == 'strip' then
          strip_files[ii] = {fn = sf, fol = strip_folders[stripfol_select].fn}
          ii = ii + 1
        end
        i=i+1
        sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[stripfol_select].fn,i)
      end
    end
    
    if sort then
      strip_files = table_slowsort_gen2(strip_files, 'fn', 0, true)
    end
    
  end

  function PopulateStrips2(fol, sort)

    local strip_files = {}

    local i = 0
    local ii = 1

    strip_files[0] = {fn = 'Blank'}
    local sf = reaper.EnumerateFiles(paths.strips_path..'/'..fol,i)
    while sf ~= nil do
      if string.match(sf,'.+%.(.*)') == 'strip' then
        strip_files[ii] = {fn = sf}
        ii = ii + 1
      end
      i=i+1
      sf = reaper.EnumerateFiles(paths.strips_path..'/'..fol,i)
    end

    if sort then
      strip_files = table_slowsort_gen2(strip_files, 'fn', 0, true)
    end

    return strip_files
  end

  function FindStripFolder(fn)

    for f = 0, #strip_folders do
      if strip_folders[f] then
        local i = 0

        local sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[f].fn,i)
        while sf ~= nil do
          if sf == fn then
            return strip_folders[f].fn, f
          end
          i=i+1
          sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[f].fn,i)
        end
      end

    end

  end

  -------------------------------------------------------
  function PopGfxFolder(folnum)

    graphics_folder_files = {}
    glist_offset = 0

    gf = 0
    if graphics_files and graphics_files[0] then
      for i = 0, #graphics_files do
        if graphics_files[i].fol == graphics_folders[folnum] then
          graphics_folder_files[gf] = i
          gf = gf + 1
        end
      end
    end

  end

  function PopulateGFXIdx()

    local gfxidx = {}
    if graphics_files and graphics_files[0] then
      for i = 0, #graphics_files do

        gfxidx[graphics_files[i].fn] = i

      end
    end
    return gfxidx

  end

  function PopulateGFX(loadtest, sort)

    graphics_files = {}
    graphics_folders = {}
    glist_offset = 0
    gflist_offset = 0

    local i = 0
    local gf = reaper.EnumerateFiles(paths.graphics_path,i)
    while gf ~= nil do
      graphics_files[i] = {fn = gf, fol = 'GENERAL', imageidx = nil}
      i=i+1
      gf = reaper.EnumerateFiles(paths.graphics_path,i)
    end

    local f = 0
    graphics_folders[f] = 'GENERAL'
    local gfo = reaper.EnumerateSubdirectories(paths.graphics_path,f)
    while gfo ~= nil do
      gi = 0
      graphics_folders[f+1] = gfo
      local gf = reaper.EnumerateFiles(paths.graphics_path..gfo,gi)
      while gf ~= nil do
        graphics_files[i] = {fn = gf, fol = gfo, imageidx = nil}

        if loadtest then
          local img = gfx.loadimg(984,paths.graphics_path..gfo..'/'..graphics_files[i].fn)
          if img and img > -1 then
            --DBG(gfo..graphics_files[i].fn..': OK')
          else
            DBG(gfo..graphics_files[i].fn..': FAILED')
          end
        end

        i=i+1
        gi=gi+1
        gf = reaper.EnumerateFiles(paths.graphics_path..gfo,gi)
      end
      if loadtest then
        DBG('Graphics folder load test complete: '..gfo)
      end
      f=f+1
      gfo = reaper.EnumerateSubdirectories(paths.graphics_path,f)
    end

    if sort then
    
      graphics_folders = table_slowsort_val2(graphics_folders, 0, true, true)
      graphics_files = table_slowsort_gen2(graphics_files, 'fn', 0, true)
    
    end

    PopGfxFolder(gfxfol_select)
    lvar.gfxfiles_idx = PopulateGFXIdx()
  end

  function RepopulateGFX()

    local gfxtab = {}
    --glist_offset = 0

    for i = 0, #graphics_files do
      gfxtab[graphics_files[i].fn] = true
    end

    local i = 0
    local gf = reaper.EnumerateFiles(paths.graphics_path,i)
    while gf ~= nil do
      if gfxtab[gf] ~= true then
        graphics_files[#graphics_files+1] = {fn = gf, fol = 'GENERAL', imageidx = nil}
      end
      i=i+1
      gf = reaper.EnumerateFiles(paths.graphics_path,i)
    end

    local f = 0
    local gfo = reaper.EnumerateSubdirectories(paths.graphics_path,f)
    while gfo ~= nil do
      gi = 0
      local gf = reaper.EnumerateFiles(paths.graphics_path..gfo,gi)
      while gf ~= nil do
        if gfxtab[gf] ~= true then
          graphics_files[#graphics_files+1] = {fn = gf, fol = gfo, imageidx = nil}
        end
        i=i+1
        gi=gi+1
        gf = reaper.EnumerateFiles(paths.graphics_path..gfo,gi)
      end
      f=f+1
      gfo = reaper.EnumerateSubdirectories(paths.graphics_path,f)
    end

    if sort then
    
      --graphics_folders = table_slowsort_val(graphics_folders)
      graphics_files = table_slowsort_gen2(graphics_files, 'fn', 0, true)
    
    end

    PopGfxFolder(gfxfol_select)
    lvar.gfxfiles_idx = PopulateGFXIdx()
  end

  -------------------------------------------------------

  function PopulateControls(loadtest, sort)

    ctl_files = {}
    --ctl_files.idx = {}
    klist_offset = 0
    local fidx = lvar.ctlfiles_idx

    local i = 0
    local c = 0
    local kf = reaper.EnumerateFiles(paths.controls_path,i)
    while kf ~= nil do
      if string.sub(kf,string.len(kf)-3) == '.knb' then
        local file
        file=io.open(paths.controls_path..kf,"r")
        local content=file:read("*a")
        file:close()
        ctl_files[c] = unpickle(content)
        if ctl_files[c] then
          --[[if string.sub(kf,1,string.len(kf)-3)..'png' ~= ctl_files[c].fn then
            DBG('error in knb file: '..ctl_files[c].fn..'  '..string.sub(kf,1,string.len(kf)-3)..'png')
          end]]

          if loadtest then
            local img = gfx.loadimg(984,paths.controls_path..ctl_files[c].fn)
            if img and img > -1 then
              --DBG(ctl_files[c].fn..': OK')
            else
              DBG(ctl_files[c].fn..': FAILED')
            end
          end

          fidx[ctl_files[c].fn] = c

          if ctl_files[c].ctltype == nil then
            ctl_files[c].ctltype = 4
          end
           --= --{fn = kf, imageidx = nil, cellh = 100, frames = 101}
          if kf == '__default.knb' then
            ctl_files[c].imageidx = 0
            knob_select = c
          elseif kf == '__Snapshot.knb' then
            ctl_files[c].imageidx = def_snapshot
            def_snapshotctl = c
          elseif kf == '__XY.knb' then
            ctl_files[c].imageidx = def_XY
            def_xyctl = c
          elseif kf == '__XYTarget.knb' then
            ctl_files[c].imageidx = def_xytarget
            def_xytargetctl = c
          elseif kf == 'SimpleFlat_48.knb' then
            ctl_files[c].imageidx = def_knobsm
            def_knobsmctl = c
          elseif kf == 'SimpleFlat_64.knb' then
            ctl_files[c].imageidx = def_eqcknobf
            def_eqcknobfctl = c
          elseif kf == 'SimpleFlat2_64.knb' then
            ctl_files[c].imageidx = def_eqcknobg
            def_eqcknobgctl = c
          elseif kf == 'SimpleBox_9632.knb' then
            ctl_files[c].imageidx = def_box
            def_boxctl = c
          elseif kf == 'Switcher.knb' then
            ctl_files[c].imageidx = def_switch
            def_switchctl = c
          end
        else
          DBG('Error found with control file: '..kf)
        end
        c = c + 1
      end
      i=i+1
      kf = reaper.EnumerateFiles(paths.controls_path,i)
    end
    
    if sort then
      local ntab, fidx = sortcontrols(ctl_files)
      ctl_files = ntab
      lvar.ctlfiles_idx = fidx
    end
    
    if loadtest then
      DBG('Controls load test complete.')
    end
  end

  function sortcontrols(ctl_files)
    local ntab = table_slowsort_gen2(ctl_files, 'fn', 0, true)
    local fidx = {}
    --make zero based
    --[[for c = 0, #ntab-1 do
      ntab[c] = ntab[c+1]
    end
    ntab[#ntab] = nil]]
    --DBG('test '..string.match('ggg.png','(.+)%.png'))
    for c = 0, #ntab do
      fidx[ntab[c].fn] = c
      local kf = string.match(ntab[c].fn,'(.+)%..*') --.. '.knb'
      if kf == '__default' then
        knob_select = c
      elseif kf == '__Snapshot' then
        def_snapshotctl = c
      elseif kf == '__XY' then
        def_xyctl = c
      elseif kf == '__XYTarget' then
        def_xytargetctl = c
      elseif kf == 'SimpleFlat_48' then
        def_knobsmctl = c
      elseif kf == 'SimpleFlat_64' then
        def_eqcknobfctl = c
      elseif kf == 'SimpleFlat2_64' then
        def_eqcknobgctl = c
      elseif kf == 'SimpleBox_9632' then
        def_boxctl = c
      elseif kf == 'Switcher' then
        def_switchctl = c 
      end
    end
    return ntab, fidx    
  end

  function RepopulateControls(sort)
    local ctltab = {}
    for i = 0, #ctl_files do
      ctltab[ctl_files[i].fn] = true
    end

    local fidx = lvar.ctlfiles_idx

    local i = 0
    local c = #ctl_files+1 --0
    local kf = reaper.EnumerateFiles(paths.controls_path,i)
    while kf ~= nil do
      if string.sub(kf,string.len(kf)-3) == '.knb' then
        local file
        file=io.open(paths.controls_path..kf,"r")
        local content=file:read("*a")
        file:close()

        if ctltab[kf] ~= true then
          ctl_files[c] = unpickle(content)
          if ctl_files[c] then
            fidx[ctl_files[c].fn] = c
            c = c + 1
          end
        end
      end
      i=i+1
      kf = reaper.EnumerateFiles(paths.controls_path,i)
    end
    
    if sort then
      local ntab, fidx = sortcontrols(ctl_files)
      ctl_files = ntab
      lvar.ctlfiles_idx = fidx
    end
    
    LoadDefSwitchFormat()
    lupd.update_gfx = true

  end

  function LoadControl(iidx, fn)

    if string.sub(fn,string.len(fn)-3) == '.knb' then
      if reaper.file_exists(paths.controls_path..fn) then
        local file
        file=io.open(paths.controls_path..fn,"r")
        local content=file:read("*a")
        file:close()

        defctls[iidx] = unpickle(content)
        if defctls[iidx] then
          gfx.loadimg(iidx,paths.controls_path..defctls[iidx].fn)
          return iidx
        else
          return -1
        end
      else
        --DBG('missing: '..fn)
        return -1
      end
    end

  end

  function LoadSkinIMG(iidx, fn, ignoremissing)

    if reaper.file_exists(paths.skins_path..skin_select..fn) then

      gfx.loadimg(iidx,paths.skins_path..skin_select..fn)
      return iidx, gfx.getimgdim(iidx)

    elseif reaper.file_exists(paths.skins_path..defskin_select..fn) then

      gfx.loadimg(iidx,paths.skins_path..defskin_select..fn)
      return iidx, gfx.getimgdim(iidx)

    else
      if ignoremissing ~= true then
        DBG('Skin file: '..fn..' missing.  Please ensure you have the latest skin folder from LBXCS_resources.zip on github installed inside your LBXCS_resources folder.')
      end
      return -2
    end

  end

  function LoadSkin()

    local fn = paths.skins_path..skin_select..'skincols.lbx'
    if not reaper.file_exists(fn) then
      skin_select = defskin_select
    end

    local skin = {}
    local ret = true

    skin.butt18O = LoadSkinIMG(847, 'Button18O.png')
    skin.butt18Gr = LoadSkinIMG(848, 'Button18Gr.png')
    skin.butt18B = LoadSkinIMG(849, 'Button18B.png')
    skin.butt18W = LoadSkinIMG(965, 'Button18W.png')
    skin.panela_top = LoadSkinIMG(850, 'PanelA_TOP.png')
    skin.panela_mid = LoadSkinIMG(851, 'PanelA_MID.png')
    skin.panela_bot = LoadSkinIMG(852, 'PanelA_BOT.png')
    skin.slider_fg = LoadSkinIMG(854, 'Slider_FG.png')
    skin.butt18 = LoadSkinIMG(855, 'Button18.png')
    skin.butt18G = LoadSkinIMG(853, 'Button18G.png')
    skin.butt18R = LoadSkinIMG(856, 'Button18R.png')
    skin.butt18T = LoadSkinIMG(857, 'Button18T.png')
    skin.bar = LoadSkinIMG(858, 'Bar.png')
    skin.barR = LoadSkinIMG(859, 'BarR.png')
    skin.barUD = LoadSkinIMG(860, 'BarUD.png')
    skin.arrowup = LoadSkinIMG(861, 'ArrowUp.png')
    skin.arrowdn = LoadSkinIMG(862, 'ArrowDown.png')
    skin.highlight = LoadSkinIMG(863, 'ListHighlight.png')
    skin.barG = LoadSkinIMG(864, 'BarG.png')
    skin.butt18Y = LoadSkinIMG(865, 'Button18Y.png')
    skin.slidbutt = LoadSkinIMG(866, 'SliderButton.png')
    skin.star = LoadSkinIMG(867, 'Star.png')
    skin.starout = LoadSkinIMG(868, 'StarOut.png')
    skin.morph_pop = LoadSkinIMG(869, 'morph_pop.png')
    skin.morph_popbar = LoadSkinIMG(870, 'morph_popbar.png')
    skin.morph_popbarr = LoadSkinIMG(871, 'morph_popbarr.png')
    skin.morph_lp = LoadSkinIMG(872, 'morph_lp.png')
    skin.updn = LoadSkinIMG(873, 'arrow_updown.png')
    skin.lr = LoadSkinIMG(874, 'arrow_lr.png')
    skin.panela_cnrbl = LoadSkinIMG(875, 'PanelA_CornerBL.png', true)
    skin.panela_cnrbr = LoadSkinIMG(876, 'PanelA_CornerBR.png', true)
    skin.panela_cnrtl = LoadSkinIMG(877, 'PanelA_CornerTL.png', true)
    skin.panela_cnrtr = LoadSkinIMG(878, 'PanelA_CornerTR.png', true)
    skin.sbicon = LoadSkinIMG(879, 'sbdeficon.png')
    skin.stripctlbtns = LoadSkinIMG(880, 'stripctlbtns.png')
    skin.stripctlbtnsX = LoadSkinIMG(881, 'stripctlbtnsX.png')
    skin.stripctlbtnslock = LoadSkinIMG(882, 'stripctlbtnslock.png')
    skin.padlock = LoadSkinIMG(883, 'padlock_red.png')
    skin.pnl_ledoff = LoadSkinIMG(884, 'pnl_ledoff.png')
    skin.pnl_ledon = LoadSkinIMG(885, 'pnl_ledon.png')
    skin.cp_aligntop = LoadSkinIMG(886, 'icon_aligntop.png')
    skin.cp_alignleft = LoadSkinIMG(887, 'icon_alignleft.png')
    skin.cp_distv = LoadSkinIMG(888, 'icon_distv.png')
    skin.cp_disth = LoadSkinIMG(889, 'icon_disth.png')
    skin.cp_copy = LoadSkinIMG(890, 'icon_copy.png')
    skin.cp_blank = LoadSkinIMG(891, 'icon_blank.png')
    skin.cp_paste = LoadSkinIMG(892, 'icon_paste.png')
    skin.cp_alignright = LoadSkinIMG(893, 'icon_alignright.png')
    skin.cp_alignbottom = LoadSkinIMG(894, 'icon_alignbottom.png')
    skin.cp_aligncentreh = LoadSkinIMG(895, 'icon_aligncentreh.png')
    skin.cp_aligncentrev = LoadSkinIMG(896, 'icon_aligncentrev.png')
    skin.cp_lockx = LoadSkinIMG(897, 'icon_lockx.png')
    skin.cp_locky = LoadSkinIMG(898, 'icon_locky.png')
    skin.cp_undo = LoadSkinIMG(901, 'icon_undo.png')
    skin.cp_redo = LoadSkinIMG(900, 'icon_redo.png')
    skin.barB = LoadSkinIMG(902, 'BarB.png')
    skin.shadow = LoadSkinIMG(904, 'shadow.png')
    skin.sliderknb, skin.sliderknb_w, skin.sliderknb_h = LoadSkinIMG(960, 'sliderknb.png')
    skin.rotknb, skin.rotknb_w, skin.rotknb_h = LoadSkinIMG(961, 'rotknb.png')

    if skin.panela_top == -2 or
       skin.panela_mid == -2 or
       skin.panela_bot == -2 or
       skin.slider_fg == -2 or
       skin.butt18 == -2 or
       skin.butt18G == -2 or
       skin.butt18Gr == -2 or
       skin.butt18O == -2 or
       skin.butt18R == -2 or
       skin.butt18T == -2 or
       skin.butt18B == -2 or
       skin.butt18W == -2 or
       skin.bar == -2 or
       skin.barR == -2 or
       skin.barUD == -2 or
       skin.arrowup == -2 or
       skin.arrowdn == -2 or
       skin.highlight == -2 or
       skin.barG == -2 or
       skin.butt18Y == -2 or
       skin.slidbutt == -2 or
       skin.star == -2 or
       skin.starout == -2 or
       skin.morph_pop == -2 or
       skin.morph_popbar == -2 or
       skin.morph_popbarr == -2 or
       skin.morph_lp == -2 or
       skin.updn == -2 or
       skin.lr == -2 or
       skin.sbicon == -2 or
       skin.stripctlbtns == -2 or
       skin.stripctlbtnsX == -2 or
       skin.stripctlbtnslock == -2 or
       skin.padlock == -2 or
       skin.cp_aligntop == -2 or
       skin.cp_alignleft == -2 or
       skin.cp_distv == -2 or
       skin.cp_disth == -2 or
       skin.cp_copy == -2 or
       skin.cp_blank == -2 or
       skin.cp_paste == -2 or
       skin.cp_alignright == -2 or
       skin.cp_alignbottom == -2 or
       skin.cp_aligncentreh == -2 or
       skin.cp_aligncentrev == -2 or
       skin.cp_lockx == -2 or
       skin.cp_locky == -2 or
       skin.cp_undo == -2 or
       skin.cp_redo == -2 or
       skin.BarB == -2 or
       skin.sliderknb == -2 or
       skin.rotknb == -2
       then
      OpenMsgBox(1,'A skin file is missing.  Please update your resources folder.',1)
      ret = false
    end

    return skin, ret

  end

  -------------------------------------------------------

  function GetTrack(t)

    local tr
    t = t or -1

    if t < 0 then
      if t == -3 then
        track = reaper.GetSelectedTrack2(0,0,true)
      elseif t == -1 then
        track = reaper.GetMasterTrack(0)
      elseif t == -2 then
        track = nil
      end
    else
      track = reaper.GetTrack(0, t)
    end
    return track

  end

  -------------------------------------------------------

  function CheckTrackUnique(name)

    local cnt = 0
    local guid
    for i = 0, reaper.CountTracks(0)-1 do

      local track = GetTrack(i)
      if name == reaper.GetTrackState(track) then
        if guid == nil then
          guid = GetTrackGUID(track)
        end
        cnt = cnt + 1
      end

    end
    local retval = true
    if cnt > 1 then
      guid = nil
      retval = false
    end
    return retval, guid

  end

  -------------------------------------------------------

  function splitln(str)

      local array = {}
      for line in (str..'\n'):gmatch'(.-)\r?\n' do
        array[#array+1] = line
      end
      return array
  end

  function split2(str,sep)

      local array = {}
      local reg = string.format("([^%s]+)",sep)
      local cnt = 1
      for mem in string.gmatch(str,reg) do
        array[cnt] = mem
        cnt = cnt + 1
      end
      return array
  end

  function GetTRNfromGUID(guid)

    local guids = lvar.trackguids or {}
    if guids[guid] then
      local track = GetTrack(guids[guid])
      if GetTrackGUID(track) == guid then
        return guids[guid], track
      end
    end

    for t = 0, reaper.CountTracks(0)-1 do

      local tr = reaper.GetTrack(0, t)
      local tguid = GetTrackGUID(tr)
      guids[tguid] = t
      if guid == tguid then
        lvar.trackguids = guids
        return t, tr
      end
    end

    lvar.trackguids = guids
    return nil, nil
  end

  function CheckStripSends(tsends)

    if tsends == nil then
      tsends = {}
    end
    if track_select and tracks[track_select] and strips[tracks[track_select].strip] then

      local tn = strips[tracks[track_select].strip].track.tracknum
      if tsends[tn] == nil then
        tsends[tn] = PopSendInfo(tn)
      end

      if tsends and tsends[tn] then
        for c = 1, #strips[tracks[track_select].strip][page].controls do
          if strips[tracks[track_select].strip][page].controls[c].ctlcat == ctlcats.tracksend then

            local paramnum = strips[tracks[track_select].strip][page].controls[c].param_info.paramnum
            local tnl = strips[tracks[track_select].strip][page].controls[c].tracknum
            if tnl == nil then
              tnl = tn
            elseif tsends[tnl] == nil then
              tsends[tnl] = PopSendInfo(tnl)
            end
            local sidx = math.floor((paramnum-1) / 3)
            local pidx = (paramnum-1) % 3 +1
            if tsends[tnl] and tsends[tnl][sidx] and strips[tracks[track_select].strip][page].controls[c].param_info.paramdestguid ==
               tsends[tnl][sidx].desttrackguid and
                   tsends[tnl][sidx].dstchan == strips[tracks[track_select].strip][page].controls[c].param_info.paramdestchan and
                   tsends[tnl][sidx].srcchan == strips[tracks[track_select].strip][page].controls[c].param_info.paramsrcchan then
            else
              for i = 0, #tsends[tnl] do

                if tsends[tnl][i] and tsends[tnl][i].desttrackguid == strips[tracks[track_select].strip][page].controls[c].param_info.paramdestguid and
                   tsends[tnl][i].dstchan == strips[tracks[track_select].strip][page].controls[c].param_info.paramdestchan and
                   tsends[tnl][i].srcchan == strips[tracks[track_select].strip][page].controls[c].param_info.paramsrcchan then
                  strips[tracks[track_select].strip][page].controls[c].param_info.paramnum = i*3+pidx-1
                  strips[tracks[track_select].strip][page].controls[c].param_info.param = i*3+pidx-1
                  strips[tracks[track_select].strip][page].controls[c].param_info.paramidx = tsends[tnl][i].idx
                  break
                end
              end
            end
          end

        end
      else
      end
    end

    return tsends
  end

  function CheckSendGUID(tr, dtracknum, paramnum, guid, dstchan, srcchan, sendinfo)

    local check = false
    local sidx = math.floor((paramnum-1) / 3)
    local pidx = (paramnum-1) % 3 +1
    if sendinfo == nil then
      sendinfo = PopSendInfo(tr)
    end
    if sendinfo[sidx] and sendinfo[sidx].desttrackguid == guid and sendinfo[sidx].dstchan == dstchan and sendinfo[sidx].srcchan == srcchan then
      check = true
    end
    return check, sendinfo

  end

  function PopSendInfo(tr)

    if settings_ExtendedAPI == false then
      return PopSendInfoFromChunk(tr)
    else

      tbl = {}

      local track = GetTrack(tr)

      if track then
        local sndcnt = reaper.GetTrackNumSends(track,0)
        for i = 0, sndcnt-1 do
          local dsttrack = reaper.BR_GetMediaTrackSendInfo_Track(track, 0, i, 1)
          if dsttrack then
            local guid = GetTrackGUID(dsttrack)
            local dst = reaper.GetTrackSendInfo_Value(track, 0, i, 'I_DSTCHAN')
            local src = reaper.GetTrackSendInfo_Value(track, 0, i, 'I_SRCCHAN')

            tbl[i] = {}
            local sname, _ = reaper.GetTrackState(dsttrack)

            t = -1 --not used
            tbl[i] = {idx = i,
                          sendname = sname,
                          desttracknum = t,
                          desttrackguid = guid,
                          dstchan = dst,
                          srcchan = src,
                          {}}
            tbl[i][1] = {
                                  name = 'Send Volume '..tostring(sname),
                                  parmname = 'D_VOL'
                                 }
            tbl[i][2] = {
                                  name = 'Send Pan '..tostring(sname),
                                  parmname = 'D_PAN'
                                 }
            tbl[i][3] = {
                                  name = 'Send Mute '..tostring(sname),
                                  parmname = 'B_MUTE'
                                 }
          end
        end
      end
      return tbl
    end

  end

  function PopSendInfoFromChunk(tr)

      tbl = {}
      local sidx = 0
      local auxrcv = ''
      for t = 0, reaper.CountTracks(0)-1 do

        local track = GetTrack(t)
        local chunk = GetTrackChunk(track, settings_usetrackchunkfix)
        local guid = GetTrackGUID(track)
        local s, e, le = _, 1, 0
        s,e = string.find(string.sub(chunk,e),'AUXRECV .-\n')
        while s and s > 0 do
          ns = le-1+s
          le = le + e

          auxrcv = string.sub(chunk,ns,le-1)
          local tx = split2(auxrcv, ' ')
          src_tr = tonumber(tx[2])
          src = tonumber(tx[9])
          dst = tonumber(tx[10])

          if tonumber(src_tr) == tr then
            tbl[sidx] = {}
            local sname, _ = reaper.GetTrackState(track)
            tbl[sidx] = {idx = sidx,
                          sendname = sname,
                          desttracknum = t,
                          desttrackguid = guid,
                          dstchan = dst,
                          srcchan = src,
                          {}}
            tbl[sidx][1] = {
                                  name = 'Send Volume '..tostring(sname),
                                  parmname = 'D_VOL'
                                 }
            tbl[sidx][2] = {
                                  name = 'Send Pan '..tostring(sname),
                                  parmname = 'D_PAN'
                                 }
            tbl[sidx][3] = {
                                  name = 'Send Mute '..tostring(sname),
                                  parmname = 'B_MUTE'
                                 }

            sidx = sidx + 1
          end

          s,e = string.find(string.sub(chunk,le),'AUXRECV .-\n')
        end
      end
      return tbl

  end

  -------------------------------------------------------

  function PopulateTrackSendsInfo()

    --CheckStripSends()
    if tracks[trackedit_select] then
      trsends_table = PopSendInfo(tracks[trackedit_select].tracknum)
    end

    trsends_mmtable = {}

    trsends_mmtable[1] = {paramstr = 'D_VOL', min = 0, max = 4,
                          func = reaper.CSurf_OnSendVolumeChange,
                          funcget = reaper.GetTrackSendUIVolPan,
                          getret = 1}
    trsends_mmtable[2] = {paramstr = 'D_PAN', min = -1, max = 1,
                          func = reaper.CSurf_OnSendPanChange,
                          funcget = reaper.GetTrackSendUIVolPan,
                          getret = 1}
    trsends_mmtable[3] = {paramstr = 'B_MUTE', min = 0, max = 1}

  end

  function PopulateSpecial()

    lvar.special_table = {}
    local trn = trackedit_select
    local tr
    if trn == -1 then
      tr = reaper.GetMasterTrack(0)
    else
      tr = reaper.GetTrack(0, trn)
    end
    if tr then
      local nchan = reaper.GetMediaTrackInfo_Value(tr, 'I_NCHAN')
      special_offs = 1 --#lvar.special_table+1
      for i = 0, nchan-1 do
        lvar.special_table[i+special_offs] = 'Peak Meter Ch'..i+1
        lvar.special_table[i+special_offs+nchan] = 'Clip Indicator Ch'..i+1
      end
      lvar.special_table_chans = nchan
    end

  end

  -------------------------------------------------------

  function PopulateMediaItemInfo()

    trctls_table = {}
    trctls_table[1] = {idx = 1,
                       name = 'Volume',
                       parmname = 'D_VOL',
                       min = 0,
                       max = 4,
                       func = reaper.CSurf_OnVolumeChange,
                       funcget = reaper.GetTrackUIVolPan,
                       getret = 1}
    trctls_table[2] = {idx = 2,
                       name = 'Pan',
                       parmname = 'D_PAN',
                       min = -1,
                       max = 1,
                       func = reaper.CSurf_OnPanChange,
                       funcget = reaper.GetTrackUIVolPan,
                       getret = 2}
    trctls_table[3] = {idx = 3,
                       name = 'Width',
                       parmname = 'D_WIDTH',
                       min = -1,
                       max = 1,
                       func = reaper.CSurf_OnWidthChange}
    trctls_table[4] = {idx = 4,
                       name = 'Pan (Left)',
                       parmname = 'D_DUALPANL',
                       min = -1,
                       max = 1,
                       }
    trctls_table[5] = {idx = 5,
                       name = 'Pan (Right)',
                       parmname = 'D_DUALPANR',
                       min = -1,
                       max = 1,
                       }
    trctls_table[6] = {idx = 6,
                       name = 'Mute',
                       parmname = 'B_MUTE',
                       min = 0,
                       max = 1,
                       }
    trctls_table[7] = {idx = 7,
                       name = 'Solo',
                       parmname = 'I_SOLO',
                       min = 0,
                       max = 2,
                       }
    trctls_table[8] = {idx = 8,
                       name = 'Pan Mode',
                       parmname = 'I_PANMODE',
                       min = 0,
                       max = 6,
                       }
    trctls_table[9] = {idx = 9,
                       name = 'Record Arm',
                       parmname = 'I_RECARM',
                       min = 0,
                       max = 1,
                       }
    trctls_table[10] = {idx = 10,
                       name = 'FX Enabled',
                       parmname = 'I_FXEN',
                       min = 0,
                       max = 1,
                       }
    trctls_table[11] = {idx = 11,
                       name = 'Phase',
                       parmname = 'B_PHASE',
                       min = 0,
                       max = 1,
                       }
    trctls_table[12] = {idx = 12,
                       name = 'Monitor',
                       parmname = 'I_RECMON',
                       min = 0,
                       max = 2,
                       }


  end

  -------------------------------------------------------

  function PopulateTracks()

    local LBX_CTL_TRACK_INF_CNT
    if LBX_CTL_TRACK_INF then
      LBX_CTL_TRACK_INF_CNT = LBX_CTL_TRACK_INF.count
    end
    LBX_GTRACK = nil
    LBX_CTL_TRACK = nil
    LBX_CTL_TRACK_INF = nil
    local tracks_tmp = {}
    local guid_tr = {}
    local sendsdirty = false
    --tracks_idx = {}
    --tracksused_idx = {}
    for i = -1, reaper.CountTracks(0) do
      local track = GetTrack(i)
      if track ~= nil then
        local trname, _ = reaper.GetTrackState(track)

        tracks_tmp[i] = {name = trname,
                         guid = GetTrackGUID(track),
                         tracknum = i,
                         strip = -1
                        }
        guid_tr[tracks_tmp[i].guid] = i
        if trname == LBX_CTL_TRNAME then
          LBX_CTL_TRACK = i
          LBX_CTL_TRACK_INF = {count = reaper.TrackFX_GetCount(track),
                               guids = {}}
          if LBX_CTL_TRACK_INF.count > 0 then
            for f = 0, LBX_CTL_TRACK_INF.count-1 do
              LBX_CTL_TRACK_INF.guids[f] = reaper.TrackFX_GetFXGUID(track,f)
            end
            if LBX_CTL_TRACK_INF_CNT ~= LBX_CTL_TRACK_INF.count then
              faders = Faders_INIT(_, faders)
            end
          end
        elseif trname == LBX_GTRACK_NAME then
          LBX_GTRACK = i
        end

        --if tracks then
          --if tracks_tmp[i].guid ~= tracks[i].guid then
          --  sendsdirty = true
          --end
        --end
      end
    end
    tracks = tracks_tmp
    lvar.trackguids = guid_tr

    if #strips > 0 then
      for j = 1, #strips do
        if not lvar.striploadoverride_active then
          if strips[j].track.tracknum == -1 then
            tracks_tmp[-1].strip = j
          elseif guid_tr[strips[j].track.guid] then
            tracks_tmp[guid_tr[strips[j].track.guid]].strip = j
          elseif lvar.deletestripwhentrackdeleted then
            --make strip inaccessible even if track re-added
            strips[j].track.guid = '[deleted]'
            strips[j].track.tracknum = -99
          end
        else
          if tracks_tmp[strips[j].track.tracknum] then
            strips[j].track.guid = tracks_tmp[strips[j].track.tracknum].guid
            tracks_tmp[strips[j].track.tracknum].strip = j
            track_select = strips[j].track.tracknum
          else
            strips[j].track.guid = tracks_tmp[-1].guid
            strips[j].track.tracknum = -1
            tracks_tmp[-1].strip = j
          end
        end
      end
    end

    PopulateUsedTracksTable()

    if LBX_GTRACK then
      CheckGlobalTrackSel(true)
      if obj then
        obj = PosTrBtns(obj)
      end
    end
    --if sendsdirty == true then
      --CheckStripSends()
    --end
  end

  function PopulateUsedTracksTable()
    local tt = 0
    tracksused_idx = {}
    tracksused_idx2 = {}
    tracksused_idx2.count = 0
    for i = -1, reaper.CountTracks(0) do
      if tracks[i] and tracks[i].strip ~= -1 then
        local strip = tracks[i].strip
        if strips[strip] and (#strips[strip][1].controls > 0 or
                              #strips[strip][2].controls > 0 or
                              #strips[strip][3].controls > 0 or
                              #strips[strip][4].controls > 0) then
          tracksused_idx[tt] = i
          tracksused_idx2[i] = tt
          tracksused_idx2.count = tracksused_idx2.count + 1
          tt = tt + 1
        end
      end
    end

  end

  function UpdateCtlTrackGUIDs()

    PopulateTracks()

    for s = 1, #strips do

      local trn = strips[s].track.tracknum
      if trn then
        strips[s].track.guid = tracks[trn].guid
      end

      for p = 1, lvar.maxpage do

        if strips[s][p].controls then
          for c = 1, #strips[s][p].controls do

            local ctl = strips[s][p].controls[c]
            local trn = ctl.tracknum
            if trn and tracks[trn] then
              ctl.trackguid = tracks[trn].guid
            end
            if ctl.iteminfo then
              local trn = ctl.iteminfo.tracknum
              if trn and tracks[trn] then
                ctl.iteminfo.trackguid = tracks[trn].guid
              end
            end
          end
        end
      end
    end

  end

  function TrackFX_GetCount(track)
    
    if track then
      if lvar.tfx_type == lvar.trackfxtype_input then
        return reaper.TrackFX_GetRecCount(track)
      else
        return reaper.TrackFX_GetCount(track)
      end
    end
    
  end

  function PopulateTrackFX()

    trackfx = {}
    trackfx_select = 0
    flist_offset = 0

    if trackedit_select and tracks[trackedit_select] then
      local track = GetTrack(tracks[trackedit_select].tracknum)
      if track then
        local fxc = TrackFX_GetCount(track)
        for i = 0, fxc-1 do
          local _, name = reaper.TrackFX_GetFXName(track,i+lvar.tfx_type,'')

          trackfx[i] = {name = name,
                        guid = reaper.TrackFX_GetFXGUID(track,i+lvar.tfx_type),
                        fxnum = i+lvar.tfx_type,
                        found = true}
        end
        PopulateTrackFXParams()
        ofxcnt = fxc
      end
    end

  end

  function PopulateTrackFXParams()

    trackfxparams = {}
    trackfxparam_select = 0
    plist_offset = 0

    if trackedit_select and tracks[trackedit_select] and trackfx[trackfx_select] then
      local track = GetTrack(tracks[trackedit_select].tracknum)
      for i = 0, reaper.TrackFX_GetNumParams(track, trackfx[trackfx_select].fxnum)-1 do
        local _, name = reaper.TrackFX_GetParamName(track, trackfx[trackfx_select].fxnum, i, '')

        trackfxparams[i] = {paramnum = i,
                            paramname = name}
      end

      local p = #trackfxparams+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'Gain Reduction (*)'}
      p=p+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'Offline'}
      p=p+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'Off/Byp/Wet'}
      p=p+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'Open GUI'}
      p=p+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'Dummy'}
      p=p+1
      trackfxparams[p] = {paramnum = p,
                          paramname = 'FX Name'}

    end
  end

  function CalcTListPos(t)
    local oldp = tlist_offset
    if hideunusedtracks ~= true then
      if t > oldp-2 and t < oldp+T_butt_cnt-2 then
        return oldp
      else
        return math.max(math.min(t-(math.floor(T_butt_cnt/2)-1), (#tracks+1)-(T_butt_cnt-2)),0)
      end
    else
      if t > oldp-2 and t < oldp+T_butt_cnt-1 then
        return oldp
      else
        return math.max(math.min(t-(math.floor(T_butt_cnt/2)-1), (#tracksused_idx+1)-(T_butt_cnt-1)),0)
      end
    end
  end

  function GUI_DrawTracks(obj, gui)

    gfx.dest = 1001

    local butt_h = tb_butt_h

    if T_butt_cnt == nil then
      T_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
      tlist_offset = CalcTListPos(track_select)
    else
      T_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
    end

    for i = 0, T_butt_cnt-1 do

      local ii
      if hideunusedtracks == true then
        ii = tracksused_idx[i + tlist_offset]
      else
        ii = i-1 + tlist_offset
      end

      if ii and tracks[ii] then
      
        local strip = tracks[ii].strip
        local lm = 0
        if lvar.livemode == 2 and ((strip and strips[strip] and strips[strip][page].lmode) or lvar.dm_fixtrack == ii) then
          if (strip and strips[strip] and strips[strip][page].lmode == 2) or lvar.dm_fixtrack == ii then
            lm = 1
          end
        end
        
        local xywh = {x = obj.sections[500].x + 2,
                      y = obj.sections[500].y + butt_h + 2 + butt_h*(i)+1,
                      w = obj.sections[500].w-6,
                      h = butt_h-1}
        local c = gui.skol.track_nostrip

        if lvar.multiselecttracks then
          if lvar.multiselecttracks[ii] == 1 then
            f_Get_SSV('64 64 64')
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1, 1)
          end
        end
        if lvar.livemode == 2 and lvar.dynamicmode_trn == ii then
          f_Get_SSV(gui.color.blue)
          gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   xywh.h, 1, 1)
          c = gui.color.black
        
        elseif track_select == ii and (lvar.livemode ~= 2 or not lvar.dm_trackslocked) then
          f_Get_SSV(gui.color.white)
          gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   xywh.h, 1, 1)
          c = gui.color.black
        elseif lvar.livemode ~= 2 or not lvar.dm_trackslocked then
          local s = tracks[ii].strip
          if tracks[ii].name == LBX_GTRACK_NAME or
             tracks[ii].name == LBX_CTL_TRNAME then
            c = gui.skol.track_special

          elseif strips and strips[s] then
            if (strips[s][1] and #strips[s][1].controls > 0) or --error s3 (nil)
               (strips[s][2] and #strips[s][2].controls > 0) or
               (strips[s][3] and #strips[s][3].controls > 0) or
               (strips[s][4] and #strips[s][4].controls > 0) or
               (strips[s][1] and #strips[s][1].graphics > 0) or
               (strips[s][2] and #strips[s][2].graphics > 0) or
               (strips[s][3] and #strips[s][3].graphics > 0) or
               (strips[s][4] and #strips[s][4].graphics > 0) then
              c = gui.skol.track_strip
            end
          end

        end

        local nm = tracks[ii].name
        if nm == '' then
          nm = '[unnamed track]'
        elseif nm == LBX_GTRACK_NAME then
          nm = '[LBX GLOBAL]'
        elseif nm == LBX_CTL_TRNAME then
          nm = '[LBX CTL]'
        end
        xywh.x=xywh.x+2
        xywh.w=xywh.w-4
        GUI_Str(gui, xywh, tracks[ii].tracknum+1 ..' - '..nm, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
      
        if lm == 1 then
          --draw padlock
          local img = skin.stripctlbtnslock
          local w,h = gfx.getimgdim(img)
          local scale = math.min(xywh.h / h,1)
          xywh.x = xywh.x + xywh.w - (w*scale)-2
          xywh.y = xywh.y + math.floor((xywh.h/2) - (h*scale)/2)
          local a = 1
          if not lvar.dm_trackslocked then
            a = 0.25
          end
          gfx.a = a
          gfx.blit(img,scale,0,0,0,w,h,xywh.x,xywh.y)
          gfx.a = 1
        end
      end
    end

    local xywh = {x = obj.sections[500].x,
                  y = obj.sections[500].y,
                  w = obj.sections[500].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

    local xywh = {x = obj.sections[500].x+1,
                  y = obj.sections[500].y+obj.sections[500].h-butt_h,
                  w = obj.sections[500].w-43,
                  h = butt_h-1}
    local txt
    if hideunusedtracks == true then
      txt = 'SHOW ALL'
    else
      txt = 'HIDE UNUSED'
    end
    GUI_DrawBar(gui,txt,xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    local sb = skin.bar
    local st = gui.skol.sb_txt_on
    if not settings_followselectedtrack then
      sb = skin.barG
      st = gui.skol.sb_txt_off
    end
    local xywh = {x = obj.sections[500].w-41,
                  y = obj.sections[500].y+obj.sections[500].h-butt_h,
                  w = 40,
                  h = butt_h-1}
    GUI_DrawBar(gui,'FLW',xywh,sb,true,st,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    f_Get_SSV(gui.color.black)
    gfx.rect(obj.sections[500].x,xywh.y,obj.sections[500].w,2,1)
  end

  function GUI_DrawFaders(obj, gui)

    gfx.dest = 1001

    local butt_h = tb_butt_h

    if FD_butt_cnt == nil then
      FD_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
      fdlist_offset = 0
      --fdlist_offset = CalcTListPos(track_select)

    else
      FD_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
    end

    if LBX_CTL_TRACK_INF --[[and faders]] then
      for i = 1, FD_butt_cnt-1 do
        local f = faders[i+fdlist_offset]

        if f and i+fdlist_offset <= lvar.LBX_FB_CNT*LBX_CTL_TRACK_INF.count then
          local xywh = {x = obj.sections[500].x+2,
                        y = obj.sections[500].y + butt_h + 2 + butt_h*(i)+3,
                        w = obj.sections[500].w-6,
                        h = butt_h-2}
          local c = gui.skol.lst_txt
          if fader_select == i + fdlist_offset then
            --GUI_DrawBar(gui,'',xywh,skin.highlight,true,gui.color.black,nil,-2)
            if faders[fader_select] and faders[fader_select].targettype then
              f_Get_SSV(gui.skol.faderselcol)
            else
              f_Get_SSV(gui.skol.lst_barhl)
            end
            gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

            c = gui.skol.lst_txthl
          else
            if f.targettype then

              c = gui.skol.lst_txthl
              f_Get_SSV(gui.skol.faderhighcol)

              gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
              --GUI_DrawBar(gui,'',xywh,skin.highlight,true,gui.color.black,nil,-2)

            else
              c = gui.skol.lst_txt
            end

          end
          local txt = 'FADER '..string.format('%i',i + fdlist_offset)
          --xywh.y = xywh.y -1
          --GUI_textsm_LJ(gui, xywh, txt, c, -4 + gui.fontsz.lst, plist_w)
          --GUI_textC_LIM(gui, xywh, txt, c, -4 + gui.fontsz.lst, '', nil, gui.fontnm.lst,4)
          xywh.x=xywh.x+2
          GUI_Str(gui, xywh, txt, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        end
      end
    end

    local xywh = {x = obj.sections[15].x,
                  y = obj.sections[15].y,
                  w = obj.sections[15].w,
                  h = obj.sections[15].h}
    local txt = 'GLOBAL'
    if settings_localfaders == true or lvar.livemode == 2 then
      txt = 'TRACK'
    end
    GUI_DrawBar(gui,txt,xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    local xywh = {x = obj.sections[500].x,
                  y = obj.sections[500].y+butt_h+2,
                  w = obj.sections[500].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h-2)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

  end

  function PopModAssObj()

    local modass = {}
    local modasssort = {}
    local trhi = -2
    local fxhi = {}
    lvar.modass = {}

    local butt_h = math.floor(butt_h*pnl_scale)+2
    local but_cy = math.max(math.floor(obj.sections[1127].h / butt_h),1)

    local strip = tracks[track_select].strip

    if strips[strip] then
      for c = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[c]
        if ctl.ctlcat == ctlcats.fxparam then
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if not modass[trn] then
            modass[trn] = {}
          end
          if not modass[trn][ctl.fxnum] then
            modass[trn][ctl.fxnum] = {}
          end
          local p = #modass[trn][ctl.fxnum]
          local track = GetTrack(trn)
          local fxn, trnm
          if track then
            _, fxn = reaper.TrackFX_GetFXName(track,ctl.fxnum,'')
          end
          modass[trn][ctl.fxnum][p+1] = {c = c,
                                         trn = trn,
                                         trnm = trnm,
                                         fxnum = ctl.fxnum,
                                         fxname = CropFXName(fxn) or CropFXName(ctl.fxname),
                                         param = ctl.param}
          trhi = math.max(trhi, trn)
          fxhi[trn] = math.max(fxhi[trn] or 0,ctl.fxnum)

        elseif ctl.ctlcat == ctlcats.trackparam then
          local fxnum = -3
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if not modass[trn] then
            modass[trn] = {}
          end
          if not modass[trn][fxnum] then
            modass[trn][fxnum] = {}
          end
          local p = #modass[trn][fxnum]
          modass[trn][fxnum][p+1] = {c = c,
                                     trn = trn,
                                     fxnum = fxnum,
                                     fxname = ctl.fxname,
                                     param = ctl.param}
          trhi = math.max(trhi, trn)
          fxhi[trn] = math.max(fxhi[trn] or 0,fxnum)

        elseif ctl.ctlcat == ctlcats.tracksend then
          local fxnum = -2
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if not modass[trn] then
            modass[trn] = {}
          end
          if not modass[trn][fxnum] then
            modass[trn][fxnum] = {}
          end
          local p = #modass[trn][fxnum]
          modass[trn][fxnum][p+1] = {c = c,
                                     trn = trn,
                                     fxnum = fxnum,
                                     fxname = ctl.fxname,
                                     param = ctl.param}
          trhi = math.max(trhi, trn)
          fxhi[trn] = math.max(fxhi[trn] or 0,fxnum)

        elseif ctl.ctlcat == ctlcats.takeswitcher then
          local fxnum = -1
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if not modass[trn] then
            modass[trn] = {}
          end
          if not modass[trn][fxnum] then
            modass[trn][fxnum] = {}
          end
          local p = #modass[trn][fxnum]
          modass[trn][fxnum][p+1] = {c = c,
                                     trn = trn,
                                     fxnum = fxnum,
                                     fxname = ctl.fxname,
                                     param = ctl.param}
          trhi = math.max(trhi, trn)
          fxhi[trn] = math.max(fxhi[trn] or 0,fxnum)

        end
      end

      local mof = 1
      for t = -1, trhi do
        if modass[t] then
          local skip = 0
          if t > -1 then
            skip = (but_cy - ((mof) % (but_cy))+1) % but_cy
           -- skip = skip % but_cy
          end
          mof = mof + skip
          if t == -1 then
            modasssort[mof] = {dispt = 'TRACK MASTER'}
          else

            local track = GetTrack(t)
            local trnm
            if track then
              trnm = reaper.GetTrackState(track)
            end

            modasssort[mof] = {dispt = trnm or ('TRACK '..t+1)}
          end
          mof = mof + 2
          for f = -3, fxhi[t] do
            if modass[t][f] then
              if f >= 0 then
                modasssort[mof] = {dispf = modass[t][f][1].fxname}
                mof = mof + 1
              end
              for p = 1, #modass[t][f] do
                modasssort[mof] = modass[t][f][p]
                strips[strip][page].controls[modasssort[mof].c].modassc = mof
                mof = mof + 1
              end
            end
          end

        end
      end
      modasssort.count = mof
      modasssort.rows = but_cy
      return modasssort
    end
  end

  function GUI_DrawModAssign(obj, gui)

    gfx.dest = 983

    gfx.setimgdim(983,-1,-1)
    gfx.setimgdim(983,obj.sections[1125].w,obj.sections[1125].h)
    GUI_DrawPanel(obj.sections[1125], nil, 'ASSIGN MODULATOR '..mod_select)

    local butt_h = math.floor(butt_h*pnl_scale)+2

    local bw = 150
    local bwc = math.max(math.floor(obj.sections[1127].w / bw),1)
    local but_cx = math.floor(obj.sections[1127].w / bwc)
    local but_cy = math.max(math.floor(obj.sections[1127].h / butt_h),1)

    local tscale = (pnl_scale-1)*fontscale
    local fs = -4 + gui.fontsz.butt +tscale

    if lvar.modass then
      local offs = lvar.modass.offset
      if but_cy ~= lvar.modass.rows then
        lvar.modass = PopModAssObj()
        lvar.modass.offset = offs
      end
      local modass = lvar.modass

      local c_tr, c_fx
      local strip = tracks[track_select].strip

      if not strips[strip] then
        gfx.dest = 1
        return
      end

      local pp = math.max(but_cy,1)*math.max(bwc,1)

      for p = 1, pp do

        if modass[p+offs] then
          local x = math.floor((p-1) / but_cy)
          local y = (p-1) % but_cy

          local xywh = {x = obj.sections[1127].x + x*but_cx,
                        y = obj.sections[1127].y + y*butt_h,
                        w = but_cx-2,
                        h = butt_h-2}
          if modass[p+offs].dispt then
            GUI_DrawButton(gui, modass[p+offs].dispt, xywh, -1, gui.color.white, true, '', false, gui.fontsz.butt)
          elseif modass[p+offs].dispf then
            GUI_DrawButton(gui, modass[p+offs].dispf, xywh, -3, gui.color.white, true, '', false, gui.fontsz.butt)
          elseif modass[p+offs].c then
            local ctl = strips[strip][page].controls[modass[p+offs].c]
            if ctl then
              local bc = '48 48 48'
              local c = gui.skol.lst_txt
              if ctl.mod then
                if ctl.mod == mod_select then
                  --bc = -4
                  bc = gui.skol.modselcol
                else
                  --bc = -2
                  bc = gui.skol.modhighcol
                end
                c = gui.skol.lst_txthl
              end
              --GUI_DrawButton(gui, ctl.param_info.paramname, xywh, bc, gui.color.white, true, '', false, gui.fontsz.butt)
              f_Get_SSV(bc)

              gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
              GUI_Str(gui, xywh, ctl.param_info.paramname, 5, c, fs, 1, nil, gui.fontnm.butt,gui.fontflag.butt)

            end
          end
        end
      end

      --[[gfx.rect(obj.sections[1127].x,
               obj.sections[1127].y,
               obj.sections[1127].w,
               obj.sections[1127].h,0)]]
    end
    gfx.dest = 1

  end

  function GUI_DrawMods(obj, gui)

    gfx.dest = 1001

    local butt_h = tb_butt_h

    if MD_butt_cnt == nil then
      MD_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
      mdlist_offset = 0
    else
      MD_butt_cnt = math.floor(obj.sections[500].h / butt_h) - 1
    end

    for i = 1, MD_butt_cnt-1 do
      local m = modulators[i+mdlist_offset]

      if m and i+mdlist_offset <= #modulators then
        local xywh = {x = obj.sections[500].x+2,
                      y = obj.sections[500].y + butt_h + 2 + butt_h*(i)+3,
                      w = obj.sections[500].w-6,
                      h = butt_h-2}
        local c = gui.skol.lst_txt
        if mod_select == i + mdlist_offset then
          if modulators[mod_select] and #modulators[mod_select].targets > 0 then
            f_Get_SSV(gui.skol.modselcol)
          else
            f_Get_SSV(gui.skol.lst_barhl)
          end
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

          c = gui.skol.lst_txthl
        else
          if #m.targets > 0 then

            c = gui.skol.lst_txthl
            f_Get_SSV(gui.skol.modhighcol)

            gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

          else
            c = gui.skol.lst_txt
          end

        end
        local txt = 'MOD '..string.format('%i',i + mdlist_offset)
        --xywh.y = xywh.y -1
        --GUI_textsm_LJ(gui, xywh, txt, c, -4 + gui.fontsz.lst, plist_w)
        --GUI_textC_LIM(gui, xywh, txt, c, -4 + gui.fontsz.lst, '', nil, gui.fontnm.lst,4)
        xywh.x=xywh.x+2
        GUI_Str(gui, xywh, txt, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst,gui.fontflag.lst)
      end
    end

    local xywh = {x = obj.sections[15].x,
                  y = obj.sections[15].y,
                  w = math.floor(obj.sections[15].w/2)-1,
                  h = obj.sections[15].h}
    local txt
    if show_lfoedit == true then
      txt = 'CLOSE'
    else
      txt = 'OPEN'
    end
    GUI_DrawBar(gui,txt..' EDITOR',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
    local xywh = {x = obj.sections[15].x+math.floor(obj.sections[15].w/2)+1,
                  y = obj.sections[15].y,
                  w = math.floor(obj.sections[15].w/2)-1,
                  h = obj.sections[15].h}
    GUI_DrawBar(gui,'ASSIGN',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    local xywh = {x = obj.sections[500].x,
                  y = obj.sections[500].y+butt_h+2,
                  w = obj.sections[500].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h-2)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

  end

  ------------------------------------------------------------

  function GetFXEnabled(tracknum, fxnum)

    local enb = true
    local tr = GetTrack(tracknum)
    if tr then
      enb = reaper.TrackFX_GetEnabled(tr, fxnum)
      if enb then
        --check global track bypass
        local _, flags = reaper.GetTrackState(tr)
        if flags then
          enb = flags&4==4
        end
      end
    end
    return enb

  end

  ------------------------------------------------------------

  function GUI_DrawBar(gui, t, b, png, v, fg1, fg2, ts, limit, shad, fontnm, fontflags, noscale)

    local c = fg1
    if v == false then
      c = fg2
    end

    local sl, sr, sm, wl ,hl, wr, hr, wm, hm, w, h
    w, h = gfx.getimgdim(png)
    sl = png

    local corner = 6
    local corner2 = 12
    --TL
    gfx.blit(sl, 1, 0, 0, 0, corner, corner, b.x, b.y)
    --TR
    gfx.blit(sl, 1, 0, w-corner, 0, corner, corner, b.x+b.w-corner, b.y)
    --BL
    gfx.blit(sl, 1, 0, 0, h-corner, corner, corner, b.x, b.y+b.h-corner)
    --BR
    gfx.blit(sl, 1, 0, w-corner, h-corner, corner, corner, b.x+b.w-corner, b.y+b.h-corner)
    --T
    gfx.blit(sl, 1, 0, corner, 0, w-corner2, corner, b.x+corner, b.y, b.w-corner2, corner)
    --B
    gfx.blit(sl, 1, 0, corner, h-corner, w-corner2, corner, b.x+corner, b.y+b.h-corner, b.w-corner2, corner)
    --L
    gfx.blit(sl, 1, 0, 0, corner, corner, h-corner2, b.x, b.y+corner, corner, b.h-corner2)
    --R
    gfx.blit(sl, 1, 0, w-corner, corner, corner, h-corner2, b.x+b.w-corner, b.y+corner, corner, b.h-corner2)
    --M
    gfx.blit(sl, 1, 0, corner, corner, w-corner2, h-corner2, b.x+corner, b.y+corner, b.w-corner2, b.h-corner2)

    local tscale = 0
    if noscale ~= true then
      tscale = tb_fontscale
    end
    GUI_Str(gui,b,t,5,c,ts+tscale,1,shad,fontnm,fontflags or 0)
    --local xywh = {x=b.x,y=b.y,w=b.w,h=b.h}
    --[[if limit~=nil and limit==true then
      GUI_textsm_LJ(gui,xywh,t,c,ts,b.w)
    else]]
      --[[if shad == nil then shad = '' end
      GUI_textC_shadow(gui,xywh,t,c,ts,1,0,shad,98,fontnm)]]
    --end

  end

  function GUI_DrawSidebar(obj, gui)

    gfx.dest = 1001

    if resize_display then
      gfx.setimgdim(1001,obj.sections[43].w+2, obj.sections[43].h)
    end

    local xywh = {x = obj.sections[43].x,
                  y = obj.sections[43].y,
                  w = obj.sections[43].w,
                  h = obj.sections[43].h}
    f_Get_SSV(gui.skol.lst_bg)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )

    local tscale = 0
    if noscale ~= true then
      tscale = tb_fontscale
    end

    if mode == 0 and plist_w >= 160 then
      local w = math.floor(obj.sections[13].w / 3)
      local xywh = {x = obj.sections[11].x,
                    y = obj.sections[11].y,
                    w = obj.sections[11].w,
                    h = obj.sections[11].h}
      if lvar.livemode == 0 then
        if lvar.dm_editmode_data then
          GUI_DrawBar(gui,'TEST MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        else
          GUI_DrawBar(gui,'LIVE MODE',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        end
      elseif lvar.livemode == 1 then
        GUI_DrawBar(gui,'MIX MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      elseif lvar.livemode == 2 then
        GUI_DrawBar(gui,'DYNAMIC MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      end

      if skin.panela_cnrbl ~= -1 then
        local xywh = obj.sections[11]
        local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
        gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y)
        if topbarheight == 0 then
          gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w-1,xywh.y)
        end
      end

      xywh = {x = obj.sections[13].x,
              y = obj.sections[13].y,
              w = w,
              h = obj.sections[13].h}
      if mode0_submode == 0 then
        GUI_DrawBar(gui,'TRACKS',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,math.min(-3 + gui.fontsz.sb+tscale,1),nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb,true)
      else
        GUI_Str(gui,xywh,'TRACKS',5,gui.skol.sb_txt_off,math.min(-3 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
      end
      xywh.x = xywh.x + w
      if mode0_submode == 1 then
        GUI_DrawBar(gui,'FADERS',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,math.min(-3 + gui.fontsz.sb+tscale,1),nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb,true)
      else
        GUI_Str(gui,xywh,'FADERS',5,gui.skol.sb_txt_off,math.min(-3 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
      end
      xywh.x = xywh.x + w
      if mode0_submode == 2 then
        GUI_DrawBar(gui,'MODS',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,math.min(-3 + gui.fontsz.sb+tscale,1),nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb,true)
      else
        GUI_Str(gui,xywh,'MODS',5,gui.skol.sb_txt_off,math.min(-3 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
      end

      if mode0_submode == 0 then
        if not lvar.dm_editmode_data then
          GUI_DrawTracks(obj, gui)
        end
      elseif mode0_submode == 1 then
        GUI_DrawFaders(obj, gui)
      elseif mode0_submode == 2 then
        GUI_DrawMods(obj, gui)
      end

    elseif mode == 0 then --and mode0_submode == 0 then
      local xywh = {x = obj.sections[11].x,
                    y = obj.sections[11].y,
                    w = obj.sections[11].w,
                    h = obj.sections[11].h}
      if lvar.livemode == 0 then
        if lvar.dm_editmode_data then
          GUI_DrawBar(gui,'TEST MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        else
          GUI_DrawBar(gui,'LIVE MODE',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        end
      elseif lvar.livemode == 1 then
        GUI_DrawBar(gui,'MIX MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      elseif lvar.livemode == 2 then
        GUI_DrawBar(gui,'DYNAMIC MODE',xywh,skin.barB,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      end

      if skin.panela_cnrbl ~= -1 then
        local xywh = obj.sections[11]
        local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
        gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y)
        if topbarheight == 0 then
          gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w-1,xywh.y)
        end
      end

      if mode0_submode == 0 then
        GUI_DrawBar(gui,'TRACKS',obj.sections[13],skin.bar,true,gui.skol.sb_txt_on,nil,-3 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        GUI_DrawTracks(obj, gui)
      elseif mode0_submode == 1 then
        GUI_DrawBar(gui,'FADERS',obj.sections[13],skin.bar,true,gui.skol.sb_txt_on,nil,-3 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        GUI_DrawFaders(obj, gui)
      elseif mode0_submode == 2 then
        GUI_DrawBar(gui,'MODS',obj.sections[13],skin.bar,true,gui.skol.sb_txt_on,nil,-3 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        GUI_DrawMods(obj, gui)
      end
    else

      GUI_DrawBar(gui,'EDIT MODE',obj.sections[11],skin.barR,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      gfx.a=1
      if skin.panela_cnrbl ~= -1 then
        local xywh = obj.sections[11]
        local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
        gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y)
        if topbarheight == 0 then
          gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w-1,xywh.y)
        end
      end

      if plist_w < 160 then
        GUI_DrawBar(gui,'',obj.sections[13],skin.bar,true,gui.skol.sb_txt_on,nil,-2)
        if mode == 1 and submode == 0 then
          local xywh = {x = obj.sections[13].x,
                        y = obj.sections[13].y,
                        w = obj.sections[13].x+obj.sections[13].w-30,
                        h = obj.sections[13].h}
          if fxmode == 0 then
            GUI_Str(gui,xywh,lvar.submode_table[submode+1],5,gui.skol.sb_txt_on,math.min(-2 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
          elseif fxmode == 1 then
            GUI_Str(gui,xywh,'TR PARAMS',5,gui.skol.sb_txt_on,math.min(-2 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
          end
        else
          GUI_Str(gui,obj.sections[13],lvar.submode_table[submode+1],5,gui.skol.sb_txt_on,math.min(-2 + gui.fontsz.sb+tscale,1),1,nil,gui.fontnm.sb,gui.fontflag.sb)
        end
        if submode == 0 then
          f_Get_SSV(gui.color.black)
          local xywh = {x = obj.sections[13].x+obj.sections[13].w - 30,
                        y = obj.sections[13].y,
                        w = 30,
                        h = obj.sections[13].h}
          gfx.rect(xywh.x,
                   xywh.y,
                   1,
                   xywh.h, 1, 1)
          GUI_Str(gui,xywh,'*',5,gui.skol.sb_txt_on,-2 + gui.fontsz.sb+tscale,1,nil,gui.fontnm.sb,gui.fontflag.sb)

        end
      else
        local sm
        if submode == 0 then
          if fxmode == 0 then
            sm = 1
          else
            sm = 2
          end
        elseif submode == 1 then
          sm = 3
        else
          sm = 0
        end
        local w = math.floor(plist_w/4)
        local x = math.floor(obj.sections[13].x+sm*w)
        local xywh
        xywh = {x = x, y = obj.sections[13].y, w = w, h = obj.sections[13].h}
        GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2)
        for i = 1, lvar.maxpage do
          local x = obj.sections[13].x+(i-1)*w
          local xywh = {x = x, y = obj.sections[13].y, w = w, h = obj.sections[13].h}
          local c = gui.skol.sb_txt_on
          if i-1 ~= sm then
            c = gui.skol.sb_txt_off
          end
          local txt = lvar.submode_table2[i]
          GUI_Str(gui,xywh,txt,5,c,math.min(-3 + gui.fontsz.sb+tscale,1),1,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        end
      end
    end

    if mode == 1 then
      if submode == 0 then

        GUI_DrawFXParams(obj, gui)

      elseif submode == 1 then

        GUI_DrawGraphicsChooser(obj, gui)

      elseif submode == 2 then

        GUI_DrawStripChooser(obj, gui)

      end
    end

    --[[if skin.panela_cnrbl ~= -1 then
      local xywh = obj.sections[43]
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y+xywh.h-pnlcnr_h-1)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w-1,xywh.y+xywh.h-pnlcnr_h-1)
    end]]

    gfx.dest = 1

  end

  ------------------------------------------------------------

  function GUI_DrawFXParams(obj, gui)
    if track_select == nil then return end
    if tracks[trackedit_select] == nil then ChangeTrack(-1) end

    local butt_h = tb_butt_h

    gfx.dest = 1001

    F_butt_cnt = math.floor(obj.sections[520].h / butt_h)
    local sbobj = obj.sections[525]

    if knob_select then

      local iidx = 1023

      if knob_select > -1 then
        if ctl_files[knob_select].imageidx ~= nil then
          iidx = ctl_files[knob_select].imageidx
        else
          gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
        end
        local w, _ = gfx.getimgdim(iidx)
        local h = ctl_files[knob_select].cellh
        local frames = ctl_files[knob_select].frames-1
        local frame = math.floor(frames*0.56)
        local xywh = {x = obj.sections[520].x,
                      y = obj.sections[520].y + tb_butt_h + 1,
                      w = obj.sections[520].w,
                      h = obj.sections[520].h - tb_butt_h - 1}

        local scale = xywh.w / w
        scale = math.min(scale, xywh.h / h, 1)
        gfx.a = 0.2
        gfx.blit(iidx,scale,0,0,frame*h,w,h,xywh.x + math.floor((xywh.w/2) - (w*scale)/2), xywh.y + math.floor((xywh.h/2) - (h*scale)/2))
        gfx.a = 1
      end

    end

    if fxmode == 0 then

      local xywh = {x = obj.sections[520].x +2,
                    w = obj.sections[520].w -6,
                    h = butt_h-2}
      if F_butt_cnt-1 < #trackfx+1 then
        xywh.w = xywh.w - sbobj.w+2
      end


      for i = 0, F_butt_cnt-1 do
        --DBG(#trackfx)
        if trackfx[i + flist_offset] then
          xywh.y = obj.sections[520].y +2+ (i+1) * butt_h +1
          local c

          local bypassed = not GetFXEnabled(tracks[trackedit_select].tracknum, trackfx[i+ flist_offset].fxnum)
          if bypassed == false then
            c = gui.skol.lst_txt
          else
            c = gui.skol.fx_byp
          end
          if trackfx_select == i + flist_offset then
            f_Get_SSV(gui.skol.lst_barhl)
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1, 1)

            if bypassed == false then
              c = gui.skol.lst_txthl
            end
          end
          local xywh2 = {x = xywh.x + 2, y = xywh.y, w = xywh.w - 4, h = xywh.h}
          GUI_Str(gui, xywh2, CropFXName(trackfx[i + flist_offset].name), 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        else
          break
        end

      end
      if F_butt_cnt-1 < #trackfx+1 then
        local msbh = sbobj.h
        local p1 = 1 / (#trackfx+1)
        local sbh = math.ceil(F_limit(p1*(F_butt_cnt-1) * msbh,20,msbh))
        local p2 = p1*msbh
        local sby = math.floor(flist_offset * p2)
        GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
        if mouse.context == contexts.scrollfx then
          GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
        end
      end

    elseif fxmode == 1 then

      local xywh = {x = obj.sections[520].x +2,
                    w = obj.sections[520].w -6,
                    h = butt_h-2}
      if F_butt_cnt-1 < #lvar.trctltype_table then
        xywh.w = xywh.w - sbobj.w+2
      end
      for i = 0, F_butt_cnt-1 do

        if lvar.trctltype_table[i + trctltypelist_offset + 1] then
          xywh.y = obj.sections[520].y +2+ (i+1) * butt_h +1
          local c = gui.skol.lst_txt
          if trctltype_select == i + trctltypelist_offset then
            f_Get_SSV(gui.skol.lst_barhl)
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1, 1)

            c = gui.skol.lst_txthl
          end
          local xywh2 = {x = xywh.x + 2, y = xywh.y, w = xywh.w - 4, h = xywh.h}
          GUI_Str(gui, xywh2, lvar.trctltype_table[i + trctltypelist_offset + 1], 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        else
          break
        end

      end
      if F_butt_cnt-1 < #lvar.trctltype_table then
        local msbh = sbobj.h
        local p1 = 1 / (#lvar.trctltype_table)
        local sbh = math.ceil(F_limit(p1*(F_butt_cnt-1) * msbh,20,msbh))
        local p2 = p1*msbh
        local sby = math.floor(trctltypelist_offset * p2)
        GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
        if mouse.context == contexts.scrollfx then
          GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
        end
      end
    end

    local xywh = {x = obj.sections[520].x,
                  y = obj.sections[520].y,
                  w = obj.sections[520].w,
                  h = butt_h}
    if fxmode == 0 then
      xywh.w = math.floor(xywh.w / 2)
    end
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    --gfx.line(xywh.x+xywh.w/4,xywh.y,xywh.x+xywh.w/4,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)
    
    if fxmode == 0 then
      xywh.x = xywh.x + xywh.w + 2    
      local c = skin.bar
      if lvar.tfx_type == lvar.trackfxtype_input then
        c = skin.barR
      end
      GUI_DrawBar(gui,'',xywh,c,true,gui.skol.sb_txt_on,nil,-2)
      GUI_Str(gui, xywh, 'REC FX', 5, gui.skol.sb_txt_on, -2 + gui.fontsz.sb, 1, nil, gui.fontnm.sb, gui.fontflag.sb)
      if lvar.tfx_type == lvar.trackfxtype_input then
        GUI_Str(gui, xywh, 'REC FX', 5, gui.skol.sb_txt_on, -2 + gui.fontsz.sb, 1, gui.skol.sb_shad, gui.fontnm.sb, gui.fontflag.sb)      
      end
    end

    f_Get_SSV(gui.color.black)
    gfx.rect(obj.sections[523].x,obj.sections[523].y-2,obj.sections[523].w,obj.sections[523].h+4,1)
    GUI_DrawBar(gui,'',obj.sections[523],skin.barUD,true,gui.skol.sb_txt_on,nil,-2)

    --Params
    P_butt_cnt = math.floor(obj.sections[522].h / butt_h)
    local sbobj = obj.sections[524]

    if fxmode == 0 then
      local xywh = {x = obj.sections[522].x +2,
                    w = obj.sections[522].w -6,
                    h = butt_h-2}
      if P_butt_cnt-1 < #trackfxparams+1 then
        xywh.w = xywh.w - sbobj.w+2
      end
      for i = 0, P_butt_cnt do

        if trackfxparams[i + plist_offset] then
          local c = gui.skol.lst_txt
          xywh.y = obj.sections[522].y +2 + (i+1) * butt_h +1
          if tfxp_sel and tfxp_sel[i + plist_offset] then
            f_Get_SSV(gui.skol.lst_barhl)
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1, 1)

            c = gui.skol.lst_txthl
          end
          local xywh2 = {x = xywh.x + 2, y = xywh.y, w = xywh.w - 4, h = xywh.h}
          GUI_Str(gui, xywh2, trackfxparams[i + plist_offset].paramname, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        else
          break
        end

      end

      if P_butt_cnt-1 < #trackfxparams+1 then
        local msbh = sbobj.h
        local p1 = 1 / (#trackfxparams+1)
        local sbh = math.ceil(F_limit(p1*(P_butt_cnt-1) * msbh,20,msbh))
        local p2 = p1*msbh
        local sby = math.floor(plist_offset * p2)
        GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
        if mouse.context == contexts.scrollfxparams then
          GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
        end
      end

    elseif fxmode == 1 then
      local tbl = {}
      if trctltype_select == 0 then
        --track controls
        tbl = trctls_table
      elseif trctltype_select == 1 then
        --track sends
        tbl = trsends_table
      elseif trctltype_select == 2 then
        --track meters
        tbl = lvar.special_table
      elseif trctltype_select == 3 then
        --other controls
        tbl = lvar.otherctl_table
      end

      local tblcnt = 0
      local xywh = {x = obj.sections[522].x+2,
                    w = obj.sections[522].w-6,
                    h = butt_h-2}
      if trctltype_select == 0 then
        tblcnt = #tbl
        if P_butt_cnt-1 < tblcnt then
          xywh.w = xywh.w - sbobj.w + 2
        end

        for i = 0, #tbl-1 do
          if tbl[i + trctlslist_offset+1] then
            local c = gui.skol.lst_txt
            xywh.y = obj.sections[522].y +2 + (i+1) * butt_h+1
            if trctl_select-1 == i + trctlslist_offset then
              f_Get_SSV(gui.skol.lst_barhl)
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1, 1)
              c = gui.skol.lst_txthl
            end
            local xywh2 = {x = xywh.x+2, y = xywh.y, w = xywh.w-4, h = xywh.h}
            GUI_Str(gui, xywh2, tbl[i + trctlslist_offset+1].name, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          else
            break
          end
        end

      elseif trctltype_select == 1 then
        tblcnt = (#tbl)*3+2+1
        if P_butt_cnt-1 < tblcnt then
          xywh.w = xywh.w - sbobj.w + 2
        end

        for i = 0, (#tbl)*3+2 do
          local ii = i + trctlslist_offset
          local sidx = math.floor(ii / 3)
          local pidx = ii % 3 + 1
          if tbl[sidx] and tbl[sidx][pidx] then
            xywh.y = obj.sections[522].y +2 + (i+1) * butt_h+1
            local c = gui.skol.lst_txt
            if trctl_select-1 == i + trctlslist_offset then
              f_Get_SSV(gui.skol.lst_barhl)
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1, 1)
              c = gui.skol.lst_txthl
            end
            local xywh2 = {x = xywh.x+2, y = xywh.y, w = xywh.w-4, h = xywh.h}
            GUI_Str(gui, xywh2, tbl[sidx][pidx].name, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          else
            break
          end
        end
      elseif trctltype_select == 2 or trctltype_select == 3 then
        if trctltype_select == 2 then
          tblcnt = #tbl
        else
          tblcnt = #tbl
        end
        if P_butt_cnt-1 < tblcnt then
          xywh.w = xywh.w - sbobj.w + 2
        end

        for i = 1, #tbl do
          --local ii = i-1 + trctlslist_offset
          if tbl[i + trctlslist_offset] then
            xywh.y = obj.sections[522].y +2 + (i) * butt_h+1
            local c = gui.skol.lst_txt
            if trctl_select == i + trctlslist_offset then
              f_Get_SSV(gui.skol.lst_barhl)
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1, 1)
              c = gui.skol.lst_txthl
            end
            local xywh2 = {x = xywh.x+2, y = xywh.y, w = xywh.w-4, h = xywh.h}
            GUI_Str(gui, xywh2, tbl[i + trctlslist_offset], 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          else
            break
          end
        end
      end

      if P_butt_cnt-1 < tblcnt then
        local msbh = sbobj.h
        local p1 = 1 / tblcnt
        local sbh = math.ceil(F_limit(p1*(P_butt_cnt-1) * msbh,20,msbh))
        local p2 = p1*msbh
        local sby = math.floor(trctlslist_offset * p2)
        GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
        if mouse.context == contexts.scrollfxparams then
          GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
        end
      end

    end

    local xywh = {x = obj.sections[522].x,
                  y = obj.sections[522].y,
                  w = obj.sections[522].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

    --[[f_Get_SSV(gui.color.white)
    gfx.a = 1
    gfx.rect(obj.sections[521].x,
             obj.sections[521].y,
             obj.sections[521].w,
             obj.sections[521].h, 1)]]

    f_Get_SSV(gui.color.black)
    local xywh = {x = obj.sections[521].x+obj.sections[521].w - 40,
                  y = obj.sections[521].y,
                  w = 40,
                  h = obj.sections[521].h}
    GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2)

    --[[gfx.rect(xywh.x,
             xywh.y,
             2,
             xywh.h, 1)]]
    if fxmode == 0 then
      --GUI_textC(gui,xywh,'LRN',gui.skol.sb_txt_on,-2 + gui.fontsz.sb)
      GUI_Str(gui, xywh, 'LRN', 5, gui.skol.sb_txt_on, -2 + gui.fontsz.sb, 1, nil, gui.fontnm.sb, gui.fontflag.sb)
    end

    local xywh = {x = obj.sections[521].x,
                  y = obj.sections[521].y,
                  w = obj.sections[521].w-41,
                  h = obj.sections[521].h}
    local sb = skin.bar
    if trackedit_select ~= track_select then
      sb = skin.barR
    end
    GUI_DrawBar(gui,'',xywh,sb,true,gui.skol.sb_txt_on,nil,-2)
    f_Get_SSV(gui.color.black)
    if trackedit_select >= 0 and tracks[trackedit_select] then
      --GUI_textsm_CJ(gui,xywh,'TR'..trackedit_select+1 ..':'..tracks[trackedit_select].name,gui.skol.sb_txt_on,-2 + gui.fontsz.sb,xywh.w)
      GUI_Str(gui, xywh, 'TR'..string.format('%i',trackedit_select+1) ..':'..tracks[trackedit_select].name, 5, gui.skol.sb_txt_on, -2 + gui.fontsz.sb, 1, gui.skol.sb_shad, gui.fontnm.sb, gui.fontflag.sb)
    else
      --GUI_textsm_CJ(gui,xywh,'TR: Master',gui.skol.sb_txt_on,-2 + gui.fontsz.sb,xywh.w)
      GUI_Str(gui, xywh, 'TR: Master', 5, gui.skol.sb_txt_on, -2 + gui.fontsz.sb, 1, gui.skol.sb_shad, gui.fontnm.sb, gui.fontflag.sb)
    end

  end

  ------------------------------------------------------------

  function GUI_DrawGFXPreview(obj, gui)

    gfx.dest = 1

    gfx.a = 1
    f_Get_SSV(gui.color.black)
    local w,h = gfx.getimgdim(lvar.gfxpreview_img)
    local scale = obj.sections[531].w / w
    scale = math.min(scale, (obj.sections[531].h-1) / h,1)
    local scw = math.floor(w*scale)
    local sch = math.floor(h*scale)
    xywh = {x = obj.sections[531].x+math.floor(obj.sections[531].w/2 - scw/2),
            y = obj.sections[531].y+math.floor(obj.sections[531].h/2 - sch/2)+1,
            w = scw,
            h = sch}
    gfx.rect(obj.sections[531].x,
             obj.sections[531].y+1,
             obj.sections[531].w,
             obj.sections[531].h-1,1)
    gfx.blit(lvar.gfxpreview_img,scale,0,0,0,w,h,xywh.x,xywh.y)

  end

  function GUI_DrawCtlPreview(obj, gui, c, fxn, prm)

    gfx.dest = 1

    local butt_h = math.floor(butt_h * pnl_scale)

    local ctl
    if c and strips[tracks[track_select].strip] then
      ctl = strips[tracks[track_select].strip][page].controls[c]
    end

    local iidx
    local ks = knob_select
    if ctl == nil and ks then

      iidx = 1023
      if ks > -1 then
        if ctl_files[ks].imageidx ~= nil then
          iidx = ctl_files[ks].imageidx
        elseif ksel_loaded == false then
          gfx.loadimg(1023, paths.controls_path..ctl_files[ks].fn)
        end
      end
    elseif ctl and ctl_files[ctl.knob_select] then
      ks = ctl.knob_select
      iidx = ctl_files[ks].imageidx
    end

    if iidx --[[and ctl_files[ks] ]]then
      local w, _ = gfx.getimgdim(iidx)
      local h = ctl_files[ks].cellh
      local frames = ctl_files[ks].frames-1
      local frame = math.floor(frames*0.56)
      local xywh = {x = obj.sections[520].x,
                    y = obj.sections[520].y + 1,
                    w = obj.sections[520].w,
                    h = obj.sections[520].h - 1}
      f_Get_SSV(gui.skol.lst_bg)
      gfx.rect(obj.sections[520].x,
               obj.sections[520].y+1,
               obj.sections[520].w,
               obj.sections[520].h-1,1)

      xywh = {x = obj.sections[520].x,
              y = obj.sections[520].y + butt_h + 1,
              w = obj.sections[520].w,
              h = obj.sections[520].h - butt_h - 1}
      local scale = xywh.w / w
      scale = math.min(scale, xywh.h / h, 1)
      gfx.a = 1
      gfx.blit(iidx,scale,0,0,frame*h,w,h,xywh.x + math.floor((xywh.w/2) - (w*scale)/2), xywh.y + math.floor((xywh.h/2) - (h*scale)/2))
    end

    if c then
      if ctl then

        local fxname = ctl.fxname
        local pname = ctl.param_info.paramname

        local xywh = {x = obj.sections[520].x,
                       y = obj.sections[520].y+1,
                       w = obj.sections[520].w,
                       h = butt_h*2+6}
        gfx.a = 0.2
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1)
        gfx.a = 1
        xywh = {x = obj.sections[520].x,
               y = obj.sections[520].y+1,
               w = obj.sections[520].w,
               h = butt_h}

        local col = gui.skol.lst_txt
        GUI_Str(gui, xywh, CropFXName(fxname), 5, col, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        xywh.y = xywh.y + butt_h
        GUI_Str(gui, xywh, pname, 5, col, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end
    elseif fxn then

      local fxname = fxn
      local pname = prm

      local xywh = {x = obj.sections[520].x,
                     y = obj.sections[520].y+1,
                     w = obj.sections[520].w,
                     h = butt_h}
      gfx.a = 1
      f_Get_SSV(gui.skol.lst_barhl)
      gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1)
      xywh.y = xywh.y + butt_h
      xywh.h = xywh.h + 6
      gfx.a = 0.2
      f_Get_SSV(gui.skol.lst_bg)
      gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1)

      gfx.a = 1
      xywh = {x = obj.sections[520].x,
             y = obj.sections[520].y+1,
             w = obj.sections[520].w,
             h = butt_h}

      local col = gui.skol.lst_txthl
      GUI_Str(gui, xywh, fxname, 5, col, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
      xywh.y = xywh.y + butt_h
      col = gui.skol.lst_txt
      GUI_Str(gui, xywh, pname, 5, col, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

    end

  end

  function GUI_DrawGraphicsChooser(obj, gui)

    gfx.dest = 1001

    local butt_h = tb_butt_h

    --[[if resize_display then
      gfx.setimgdim(1001,obj.sections[43].w+2, obj.sections[43].h)
    end]]

    --PopGfxFolder(gfxfol_select) --MOVE TO WHEN FOLDER CHANGED

    local butt_cnt = math.floor((obj.sections[530].h) / butt_h)
    GF_butt_cnt = math.floor(obj.sections[531].h / butt_h)
    local sbobj = obj.sections[535]
    local xywh = {x = obj.sections[531].x,
                  w = obj.sections[531].w,
                  h = butt_h}
    if GF_butt_cnt+1 < #graphics_folders+1 then
      xywh.w = xywh.w - sbobj.w+2
    end

    for i = 0, GF_butt_cnt-1 do

      if graphics_folders[i + gflist_offset] then
        xywh.y = obj.sections[531].y +2+ (i+1) * butt_h
        local c = gui.skol.lst_txt
        if gfxfol_select == i + gflist_offset then
          f_Get_SSV(gui.skol.lst_barhl)
          gfx.rect(xywh.x+2,
                   xywh.y+1,
                   xywh.w-6,
                   xywh.h-2, 1, 1)

          c = gui.skol.lst_txthl
        end
        if gfx_dropfolder == i + gflist_offset then
          f_Get_SSV(gui.color.red)
          gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   xywh.h, 0, 1)
        end
        xywh2 = {x = xywh.x+4, y = xywh.y, w = xywh.w-10, h = xywh.h}
        GUI_Str(gui, xywh2, graphics_folders[i + gflist_offset], 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
      else
        break
      end

    end
    if GF_butt_cnt-1 < #graphics_folders+1 then
      local msbh = sbobj.h
      local p1 = 1 / (#graphics_folders+1)
      local sbh = math.ceil(F_limit(p1*(GF_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(gflist_offset * p2)
      GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
      if mouse.context == contexts.scrollgfxfols then
        GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
      end
    end

    local xywh = {x = obj.sections[531].x,
                  y = obj.sections[531].y,
                  w = obj.sections[531].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

    f_Get_SSV(gui.color.black)
    gfx.rect(obj.sections[533].x,obj.sections[533].y-2,obj.sections[533].w,obj.sections[533].h+4,1)
    GUI_DrawBar(gui,'',obj.sections[533],skin.barUD,true,gui.skol.sb_txt_on,nil,-2,gui.fontflag.sb)

    G_butt_cnt = math.floor(obj.sections[530].h / butt_h) - 2
    local sbobj = obj.sections[534]
    local xywh = {x = obj.sections[530].x,
                  w = obj.sections[530].w,
                  h = butt_h}
    if G_butt_cnt+1 < #graphics_folder_files+1 then
      xywh.w = xywh.w - sbobj.w+2
    end

    for i = 0, G_butt_cnt+1 do

      if graphics_files[graphics_folder_files[i + glist_offset]] then
        local c = gui.skol.lst_txt
        xywh.y = obj.sections[530].y+2 + (i+1) * butt_h

        if gfx_select == i + glist_offset then
          f_Get_SSV(gui.skol.lst_barhl)
          gfx.rect(xywh.x+2,
                   xywh.y+1,
                   xywh.w-6,
                   xywh.h-2, 1, 1)

          c = gui.skol.lst_txthl
        end

        xywh2 = {x = xywh.x+4, y = xywh.y, w = xywh.w-10, h = xywh.h}
        GUI_Str(gui, xywh2, graphics_files[graphics_folder_files[i + glist_offset]].fn, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end
    end

    if G_butt_cnt+1 < #graphics_folder_files+1 then
      local msbh = sbobj.h
      local p1 = 1 / (#graphics_folder_files+1)
      local sbh = math.ceil(F_limit(p1*(G_butt_cnt+1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(glist_offset * p2)
      GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
      if mouse.context == contexts.scrollgfxfiles then
        GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
      end
    end

    local xywh = {x = obj.sections[530].x,
                  y = obj.sections[530].y,
                  w = obj.sections[530].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

  end

  function GUI_DrawSB(sbobj, sby, msbh, sbh, col, fill, clear)

    lvar.scrollbar_clear = clear
    f_Get_SSV(col)
    gfx.rect(sbobj.x,
             math.min(sbobj.y+1+sby,sbobj.y+msbh-sbh-1),
             sbobj.w-2,
             sbh-1, fill)
  end

  ------------------------------------------------------------

  function RemoveFav(fn)

    local ret
    local cnt = #strip_favs
    for i = 1, cnt do
      if strip_favs[i] == fn then
        strip_favs[i] = nil
        ret = true
        break
      end
    end
    if ret then
      strip_favs = Table_RemoveNils(strip_favs, cnt)
    end

  end

  function InFavs(fn)

    local ret
    for i = 1, #strip_favs do
      if strip_favs[i] == fn then
        ret = true
        break
      end
    end
    return ret

  end

  function CheckFavs()

    local cnt = #strip_favs
    for i = 1, cnt do
      local fn = paths.strips_path..strip_favs[i]
      if reaper.file_exists(fn) == false then
        strip_favs[i] = nil
        ret = true
      end
    end
    if ret then
      strip_favs = Table_RemoveNils(strip_favs, cnt)
    end

  end

  function GUI_DrawStripChooser(obj, gui)

    gfx.dest = 1001

    local butt_h = tb_butt_h

    GUI_DrawBar(gui,'SAVE STRIP',obj.sections[511],skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil, gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    SF_butt_cnt = math.floor(obj.sections[510].h / butt_h)
    local sbobj = obj.sections[515]
    local xywh = {x = obj.sections[510].x,
                  w = obj.sections[510].w,
                  h = butt_h}
    if SF_butt_cnt-1 < #strip_folders+1 then
      xywh.w = xywh.w - sbobj.w + 2
    end
    for i = 0, SF_butt_cnt-1 do

      if strip_folders[i + sflist_offset] then
        xywh.y = obj.sections[510].y+2 + (i+1) * butt_h
        local c = gui.skol.lst_txt
        if stripfol_select == i + sflist_offset then
          f_Get_SSV(gui.skol.lst_barhl)
          gfx.rect(xywh.x+2,
                   xywh.y+1,
                   xywh.w-6,
                   xywh.h-2, 1, 1)

          c = gui.skol.lst_txthl
        end

        xywh2 = {x = xywh.x+4, y = xywh.y, w = xywh.w-10, h = xywh.h}
        GUI_Str(gui, xywh2, strip_folders[i + sflist_offset].fn, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end
    end
    if SF_butt_cnt-1 < #strip_folders+1 then
      local msbh = sbobj.h
      local p1 = 1 / (#strip_folders+1)
      local sbh = math.ceil(F_limit(p1*(SF_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(sflist_offset * p2)
      GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
      if mouse.context == contexts.scrollstripfols then
        GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
      end
    end

    gfx.a = 1
    local xywh = {x = obj.sections[510].x,
                  y = obj.sections[510].y,
                  w = obj.sections[510].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

    f_Get_SSV(gui.color.black)
    gfx.rect(obj.sections[513].x,obj.sections[513].y-2,obj.sections[513].w,obj.sections[513].h+4,1)
    GUI_DrawBar(gui,'',obj.sections[513],skin.barUD,true,gui.skol.sb_txt_on,nil,-2)

    S_butt_cnt = math.floor(obj.sections[512].h / butt_h)
    local sbobj = obj.sections[514]
    local w, h = gfx.getimgdim(skin.star)
    local xywh = {x = obj.sections[512].x,
                  w = obj.sections[512].w,
                  h = butt_h}
    if S_butt_cnt-1 < #strip_files+1 then
      xywh.w = xywh.w - sbobj.w + 2
    end
    for i = 0, S_butt_cnt-1 do

      if strip_files[i + slist_offset] then
        local c = gui.skol.lst_txt
        xywh.y = obj.sections[512].y+2 + (i+1) * butt_h
        if strip_select == i + slist_offset then
          f_Get_SSV(gui.skol.lst_barhl)
          gfx.rect(xywh.x+2,
                   xywh.y+1,
                   xywh.w-6,
                   xywh.h-2, 1, 1)

          c = gui.skol.lst_txthl
        end

        if InFavs(strip_folders[stripfol_select].fn..'/'..strip_files[i + slist_offset].fn) then
          gfx.blit(skin.star,1,0,0,0,w,h,xywh.x+xywh.w-w,xywh.y+xywh.h/2-h/2)
        else
          gfx.blit(skin.starout,1,0,0,0,w,h,xywh.x+xywh.w-w,xywh.y+xywh.h/2-h/2)
        end
        xywh2 = {x = xywh.x+4, y = xywh.y, w = xywh.w-24, h = xywh.h}
        GUI_Str(gui, xywh2, strip_files[i + slist_offset].fn, 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end
    end

    if S_butt_cnt-1 < #strip_files+1 then
      local msbh = sbobj.h
      local p1 = 1 / (#strip_files+1)
      local sbh = math.ceil(F_limit(p1*(S_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(slist_offset * p2)
      GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
      if mouse.context == contexts.scrollstripfiles then
        GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
      end
    end

    local xywh = {x = obj.sections[512].x,
                  y = obj.sections[512].y,
                  w = obj.sections[512].w,
                  h = butt_h}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

  end

  ------------------------------------------------------------

  function OpenDropDown(idx, ddtab, variwidth, expandonly)

    if reaper.time_precise() > lvar.dropenabled_timer then
      ddlist = ddtab
      ddlist.idx = idx
      ddlist.offset = 0
      ddlist.size = #ddtab.items
      ddlist.textsize = -5

      if variwidth == true then
        local text_len = 0
        --gfx.setfont(1, gui.fontname, gui.fontsz_knob + ddlist.textsize)
        gfx.setfont(1, gui.fontnm.lst, gui.fontsz_knob -4 + gui.fontsz.lst + lst_fontscale)
        for i = 1, #ddlist.items do
          local w, h = gfx.measurestr(ddlist.items[i])
          text_len = math.max(w,text_len)
        end
        if expandonly == true then
          ddlist.w = math.max(text_len + ddlist.wpad,ddlist.w)
        else
          ddlist.w = text_len + ddlist.wpad
        end
      end

      gfx.setimgdim(996,-1,-1)

      show_dd = true
      lupd.update_dd = true
      lupd.update_surface = true
      mouse.context = contexts.dd
      
      RedrawGUIBitmap()
    end

  end

  function GUI_DrawDropdown(gui, obj)

    gfx.dest = 996
    if ddlist and ddlist.items then
      local butt_h = tb_butt_h*lvar.zoom

      local size = #ddlist.items
      if size > 0 then
        local maxh = gfx1.main_h
        local h = size*butt_h --math.min(size*butt_h,maxh)
        if h > maxh then
          h = maxh
          size = math.floor(h / butt_h)
          h = size*butt_h
        end
        ddlist.size = size
        ddlist.h = h

        if ddlist.bottom then
          ddlist.y = math.max(ddlist.y - ddlist.h,0)
          ddlist.bottom = nil
        end

        local w = math.max(ddlist.w,100)
        ddlist.w = w

        if ddlist.hcentre then
          ddlist.x = ddlist.x - math.floor(ddlist.w/2)
          ddlist.hcentre = nil
        end

        gfx.setimgdim(996,w+6,h+6)
        --local x, y = ddlist.x, ddlist.y
        if ddlist.y + ddlist.h > gfx1.main_h then
          ddlist.y = gfx1.main_h - ddlist.h-1
        end
        if ddlist.x + ddlist.w > gfx1.main_w then
          ddlist.x = gfx1.main_w - ddlist.w -1
        end

        --[[gfx.a = 0.2
        f_Get_SSV(gui.color.black)
        gfx.rect(4,4,w+2,h+2,1)]]

        gfx.a = 1
        f_Get_SSV(gui.skol.lst_bg)
        gfx.rect(0,0,w+2,h+2,1)
        f_Get_SSV(gui.skol.lst_barhl)
        gfx.rect(1,1,w,h,0)

        local xywh = {x = 1, y = 0, w = w, h = butt_h}
        local indw = 6
        for i = 1, size do

          xywh.y = (i-1)*butt_h +2
          if ddlist.indcol and ddlist.indcol[i+ddlist.offset] then
            f_Get_SSV(ddlist.indcol[i+ddlist.offset])
            gfx.rect(xywh.x+2,xywh.y+1,indw,xywh.h-2,1)
            gfx.rect(xywh.x+xywh.w-2-indw,xywh.y+1,indw,xywh.h-2,1)
          end
          if ddlist.over == i and (not ddlist.itemdisabled or not ddlist.itemdisabled[i+ddlist.offset]) then
            f_Get_SSV(gui.skol.lst_barhl)
            gfx.rect(xywh.x+2,xywh.y+1,xywh.w-4,xywh.h-2,1)

            GUI_Str(gui, xywh, ddlist.items[i+ddlist.offset] or '', 5, gui.skol.lst_txthl, -4 + gui.fontsz.lst + lst_fontscale + (8*lvar.zoom)-8, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          else
            if (not ddlist.itemdisabled or not ddlist.itemdisabled[i+ddlist.offset]) then
              if ddlist.itemcol then
                GUI_Str(gui, xywh, ddlist.items[i+ddlist.offset] or '', 5, ddlist.itemcol[i+ddlist.offset] or gui.skol.lst_txt, -4 + gui.fontsz.lst + lst_fontscale + (8*lvar.zoom)-8, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
              else
                GUI_Str(gui, xywh, ddlist.items[i+ddlist.offset] or '', 5, gui.skol.lst_txt, -4 + gui.fontsz.lst + lst_fontscale + (8*lvar.zoom)-8, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
              end
            else
              GUI_Str(gui, xywh, ddlist.items[i+ddlist.offset] or '', 5, '128 128 128', -4 + gui.fontsz.lst + lst_fontscale + (8*lvar.zoom)-8, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
            end
          end
        end

      end
    end
    gfx.dest = 1

  end

  function GUI_DrawMIDILrn(gui, obj)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[lbx_midilrnctl]
    GUI_DrawPanel(obj.sections[980],true,'FADERBOX LEARN - '..ctl.param_info.paramname)

    if lbx_midilrnval then
      local c = gui.skol.butt1_txt
      if lbx_midilrnval and faders[lbx_midilrnval] and faders[lbx_midilrnval].targettype then
        if (faders[lbx_midilrnval].targettype == 4 or faders[lbx_midilrnval].targettype == 7) and faders[lbx_midilrnval].strip == strip and
           faders[lbx_midilrnval].page == page and faders[lbx_midilrnval].ctl == lbx_midilrnctl then
          c = '0 128 0'
        else
          c = gui.color.red
        end
      end
      GUI_DrawButton(gui, 'FADER '..string.format('%i',lbx_midilrnval), obj.sections[981], gui.color.white, c, true, 'FADER', false, gui.fontsz.butt)
    else
      GUI_DrawButton(gui, 'NONE', obj.sections[981], -3, gui.skol.butt1_txt, false, 'FADER', false, gui.fontsz.butt)
    end

    if ctl.ctlcat == ctlcats.snapshot then
      local vv = nz(lbx_midilrnoff,0)
      local v = string.format('%i',vv)..'  -  '..num2note(vv)
      GUI_DrawButton(gui, v, obj.sections[983], gui.color.white, c, true, 'Fader Value Offset', false, gui.fontsz.butt)
    end

    GUI_DrawButton(gui, "OK", obj.sections[982], gui.color.white, gui.skol.butt1_txt, true,'',false, gui.fontsz.butt)

  end

  function GUI_DrawMIDIOut(gui, obj)

    local tscale = (pnl_scale-1)*fontscale

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[midioutedit_select]
    GUI_DrawPanel(obj.sections[950],true,'MIDI OUT - '..ctl.param_info.paramname)

    local xywh = {x = obj.sections[950].x, y = obj.sections[951].y-math.floor((butt_h*1.5)*pnl_scale), w = obj.sections[950].w, h = obj.sections[951].h}
    --GUI_textC_LIM(gui, xywh, 'TRANSMIT MIDI MESSAGE', gui.color.white, -2,4)
    GUI_Str(gui,xywh,'TRANSMIT MIDI MESSAGE',5,c,2 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    GUI_DrawButton(gui, nz(midiout_select.output,'--- [None] ---'), obj.sections[951], gui.color.white, gui.skol.butt1_txt, true, 'MIDI OUTPUT',false,gui.fontsz.butt)
    GUI_DrawButton(gui, midiout_select.mchan, obj.sections[952], gui.color.white, gui.skol.butt1_txt, true, 'MIDI CHANNEL',false,gui.fontsz.butt)
    local msglab = ''
    if midiout_select.msgtype then
      if midiout_select.msgtype >= 1 and midiout_select.msgtype <= 3 then
        msglab = 'KEY'
      elseif midiout_select.msgtype == 4 then
        msglab = 'MIDI CC#'
      elseif midiout_select.msgtype >= 5 and midiout_select.msgtype <= 7 then
        msglab = 'N/A'
      end
    end
    GUI_DrawButton(gui, midiout_select.msg3, obj.sections[953], gui.color.white, gui.skol.butt1_txt, true, msglab,false,gui.fontsz.butt)
    GUI_DrawButton(gui, nz(lvar.midimsgtype_table[nz(midiout_select.msgtype,-1)],'NONE'), obj.sections[954], gui.color.white, gui.skol.butt1_txt, true, 'MESSAGE TYPE',false,gui.fontsz.butt)

    local xywh = {x = obj.sections[950].x, y = obj.sections[955].y-math.floor((butt_h*1.5)*pnl_scale), w = obj.sections[950].w, h = obj.sections[955].h}
    --GUI_textC_LIM(gui, xywh, 'TRANSMIT OSC MESSAGE', gui.color.white, -2)
    GUI_Str(gui,xywh,'TRANSMIT OSC MESSAGE',5,c,2 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
    GUI_DrawButton(gui, nz(midiout_select.osc,'none'), obj.sections[955], gui.color.white, gui.skol.butt1_txt, true, 'OSC MESSAGE',false,gui.fontsz.butt)

    local xywh = {x = obj.sections[950].x, y = obj.sections[956].y-math.floor((butt_h*1.5)*pnl_scale), w = obj.sections[950].w, h = obj.sections[956].h}
    --GUI_textC_LIM(gui, xywh, 'CONTROL PARAMETERS', gui.color.white, -2)
    GUI_Str(gui,xywh,'CONTROL PARAMETERS',5,c,2 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
    GUI_DrawButton(gui, midiout_select.vmin, obj.sections[956], gui.color.white, gui.skol.butt1_txt, true, 'VALUE RANGE',false,gui.fontsz.butt)
    GUI_DrawButton(gui, midiout_select.vmax, obj.sections[957], gui.color.white, gui.skol.butt1_txt, true, 'TO',false,gui.fontsz.butt)

    GUI_DrawButton(gui, lvar.focus_table[nz(midiout_select.focus, 1)], obj.sections[958], gui.color.white, gui.skol.butt1_txt, true, 'FOCUS WINDOW',false,gui.fontsz.butt)
    if midiout_select.focus == 4 and reaper.JS_Window_Find then --custom
      GUI_DrawButton(gui, midiout_select.focus_wintit or '[Enter window title]', obj.sections[963], gui.color.white, gui.skol.butt1_txt, true, 'FOCUS WIN. TITLE',false,gui.fontsz.butt)
      GUI_DrawTick(gui, 'EXACT', obj.sections[964], gui.skol.pnl_txt, nz(midiout_select.focus_winexact, false),gui.fontsz.butt)
    end

    GUI_DrawTick(gui, 'UPDATE DISPLAY BEFORE SENDING MSG', obj.sections[959], gui.skol.pnl_txt, nz(midiout_select.updategfx, false),gui.fontsz.butt)
    GUI_DrawTick(gui, 'SEND MIDI ON MOUSE UP', obj.sections[961], gui.skol.pnl_txt, nz(midiout_select.onmu, false),gui.fontsz.butt)

  end

  function GetTFXOButtCnt()
    local tfxo_butth = 30*pnl_scale+math.floor((pnl_scale-1)*10)
    return math.floor((obj.sections[900].h-30*pnl_scale)/tfxo_butth), tfxo_butth
  end

  function GUI_DrawTrackFXOrder(gui, obj)

    gfx.dest = 978

    local fxcnt
    if lvar.livemode > 0 then
      fxcnt = #tfxreorder
    else
      local tr = GetTrack(tracks[track_select].tracknum)
      fxcnt = reaper.TrackFX_GetCount(tr)
    end
    local gah = math.max(200, gfx1.main_h-obj.sections[10].y-40)
    local tfxo_butth = 30*pnl_scale+math.floor((pnl_scale-1)*10)
    obj.sections[900].h = math.min(gah, 34*pnl_scale + tfxo_butth * fxcnt)
    obj.sections[901] = {x = obj.sections[900].x, y = obj.sections[900].y, w = obj.sections[900].w, h = math.max(obj.sections[900].h,250)}

    gfx.setimgdim(978, -1, -1)
    gfx.setimgdim(978, obj.sections[901].w, obj.sections[901].h)

    --obj.sections[900].y = math.max(gfx1.main_h/2 - obj.sections[900].h/2,obj.sections[10].y)
    if lvar.livemode > 0 then
      GUI_DrawPanel(obj.sections[901],false,'STRIP ORDER')
    else
      GUI_DrawPanel(obj.sections[901],false,'TRACK FX ORDER')
    end
    if tfxreorder then

      local butt_cnt, butt_h = GetTFXOButtCnt()
      local offs = 0

      for i = 1, butt_cnt do

        if tfxreorder[i+tfxo_listpos] then
          local xywh = {x = 40,
                        y = 30*pnl_scale + ((i-1) * (butt_h)),
                        w = obj.sections[900].w-60,
                        h = butt_h-1}
          local tc = gui.skol.butt1_txt
          if tostring(tfxreorder[i+tfxo_listpos].offline) == '1' then
            tc = '128 128 128'
          elseif tostring(tfxreorder[i+tfxo_listpos].bypass) == '1' then
            tc = gui.color.red
          end
          if i+tfxo_listpos == tfxo_pos then
            GUI_DrawButton(gui, CropFXName(tfxreorder[i+tfxo_listpos].name), xywh, -4, tc, true, string.format('%i',i+tfxo_listpos),true,2)
          elseif tostring(tfxreorder[i+tfxo_listpos].offline) == '1' then
            GUI_DrawButton(gui, CropFXName(tfxreorder[i+tfxo_listpos].name), xywh, -1, tc, true, string.format('%i',i+tfxo_listpos),true,2)
          else
            GUI_DrawButton(gui, CropFXName(tfxreorder[i+tfxo_listpos].name), xywh, gui.color.white, tc, true, string.format('%i',i+tfxo_listpos),true,2)
          end
        end
      end

    end

  end

  function GUI_DrawGaugeEdit()

    if ctl_select ~= nil then
      GUI_DrawPanel(obj.sections[800],true,'GAUGE EDIT')

      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[ctl_select[1].ctl]
      if ctl then

        local iidx = ctl.ctl_info.imageidx
        local ctlw, _ = ctl.wsc
        local ctlh = ctl.hsc
        local ctlx, ctly = obj.sections[800].x+obj.sections[800].w/2 - ctlw/2, obj.sections[800].y+120*pnl_scale - ctlh/2

        GUI_DrawGauge2(gauge_select, ctlx+ctlw/2, ctly+ctlh/2, ctl, true)

        local v2 = nz(frameScale(ctl.framemode, gauge_select.val),0)
        local frame = F_limit(round(ctl.ctl_info.frames*v2),0,ctl.ctl_info.frames-1)

        gfx.blit(iidx,ctl.scale,0,0,frame*ctl.ctl_info.cellh,ctl.w,ctl.ctl_info.cellh,ctlx,ctly)

        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[815].x,obj.sections[815].y+1,obj.sections[815].w,obj.sections[815].h,0)

        GUI_textC(gui,obj.sections[815],gauge_select.dval,gui.color.white,0)

        GUI_DrawButton(gui, lvar.gaugetype_table[gauge_select.type], obj.sections[801], gui.color.white, gui.skol.butt1_txt, true, 'TYPE',false,gui.fontsz.butt)
        if gauge_select.type == 1 then
          GUI_DrawSliderH(gui, 'RADIUS', obj.sections[802], gui.color.black, gui.color.white, F_limit(((gauge_select.radius-10)/110),0,1),gui.fontsz.butt)
          GUI_DrawSliderH(gui, 'ROTATE', obj.sections[804], gui.color.black, gui.color.white, F_limit(((gauge_select.rotation)),0,1),gui.fontsz.butt)
        end
        GUI_DrawSliderH(gui, 'LENGTH', obj.sections[803], gui.color.black, gui.color.white, F_limit(((gauge_select.arclen)),0,1))

        GUI_DrawButton(gui, gauge_select.ticks, obj.sections[805], gui.color.white, gui.skol.butt1_txt, true, 'TICKS (AUTO)',false,gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'TICK SIZE', obj.sections[807], gui.color.black, gui.color.white, F_limit(((gauge_select.tick_size-2)/10),0,1),gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'OFFSET', obj.sections[808], gui.color.black, gui.color.white, F_limit(((gauge_select.tick_offs)/12),0,1),gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'X OFFSET', obj.sections[809], gui.color.black, gui.color.white, F_limit(((gauge_select.x_offs+30)/60),0,1),gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'Y OFFSET', obj.sections[810], gui.color.black, gui.color.white, F_limit(((gauge_select.y_offs+30)/60),0,1),gui.fontsz.butt)
        GUI_DrawButton(gui, gauge_select.font, obj.sections[831], gui.color.white, gui.skol.butt1_txt, true, 'FONT',false,gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'FONT SIZE', obj.sections[814], gui.color.black, gui.color.white, F_limit(((gauge_select.fontsz+8)/8),0,1),gui.fontsz.butt)
        GUI_DrawSliderH(gui, 'VAL FREQ', obj.sections[825], gui.color.black, gui.color.white, F_limit(((gauge_select.val_freq-1)/23),0,1),gui.fontsz.butt)

        local mdptxt = gauge_select.val_dp
        if gauge_select.val_dp < 0 then
          mdptxt = 'OFF'
        end
        GUI_DrawButton(gui, mdptxt, obj.sections[817], gui.color.white, gui.skol.butt1_txt, true, 'MAX DP',false,gui.fontsz.butt)
        GUI_DrawTick(gui, 'NUMERIC ONLY', obj.sections[827], gui.color.white, nz(gauge_select.numonly, false))
        local xywh = {x = obj.sections[832].x,
                      y = obj.sections[832].y-butt_h,
                      w = 1,
                      h = butt_h}
        GUI_textC(gui,xywh,'1000 = 1k',gui.color.white,-5)
        GUI_DrawTick(gui, '', obj.sections[832], gui.color.white, nz(gauge_select.abbrev, false))

        if ctl.ctltype == 4 then
          GUI_DrawButton(gui, 'COPY CYCLE DATA', obj.sections[818], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
        end
        GUI_DrawButton(gui, 'EDIT SEL', obj.sections[833], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, 'DEL SEL', obj.sections[826], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, '<<', obj.sections[828], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, '>>', obj.sections[829], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        if gauge_ticksel and gauge_select.vals and gauge_select.vals[gauge_ticksel] then
          GUI_DrawSliderH(gui, '', obj.sections[830], gui.color.black, gui.color.white, F_limit(((nz(gauge_select.vals[gauge_ticksel].nudge,0)+10)/20),0,1),gui.fontsz.butt)
        end

        local txt = 'ARC'
        if gauge_select.type > 1 then
          txt = 'LINE'
        end
        GUI_DrawButton(gui, txt, obj.sections[811], gui.color.white, gui.skol.butt1_txt, gauge_select.show_arc,'',false,gui.fontsz.butt)

        local ticklbl
        if gauge_select.tick_shape == 2 then
          ticklbl = 'TICKS C'
        elseif gauge_select.tick_shape == 1 then
          ticklbl = 'TICKS L'
        else
          ticklbl = 'TICKS'        
        end
        GUI_DrawButton(gui, ticklbl, obj.sections[812], gui.color.white, gui.skol.butt1_txt, gauge_select.show_tick,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, 'VALS', obj.sections[813], gui.color.white, gui.skol.butt1_txt, gauge_select.show_val,'',false,gui.fontsz.butt)
        GUI_DrawColorBox(gui, '', obj.sections[820], gui.color.white, gauge_select.col_arc)
        GUI_DrawColorBox(gui, '', obj.sections[821], gui.color.white, gauge_select.col_tick)
        GUI_DrawColorBox(gui, '', obj.sections[822], gui.color.white, gauge_select.col_val)
        GUI_DrawSliderH(gui, '', obj.sections[816], gui.color.black, gui.color.white, F_limit(auto_delay/10,0,1),gui.fontsz.butt)
        GUI_textC(gui,obj.sections[816],auto_delay,gui.color.red,-2)
        xywh = {x = obj.sections[816].x+obj.sections[816].w+5,
                y = obj.sections[816].y,
                w = 30, h = obj.sections[816].h}
        GUI_textC(gui,xywh,'SENS',gui.color.white,-5)

        GUI_DrawButton(gui, 'REMOVE', obj.sections[823], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, 'RESET', obj.sections[824], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
        GUI_DrawButton(gui, 'SAVE', obj.sections[819], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)

      end

    else
      show_gaugeedit = false
    end

  end

  function GUI_DrawGauge2(gtab, cx, cy, ctl, edit, preview)

    if gtab then

      local strip = tracks[track_select].strip

      if edit then
        gfx.dest = 1
      elseif not preview then
        gfx.dest = bg_image + (ctl.gfxpage or 0)
      end

      cx = cx + gtab.x_offs
      cy = cy + gtab.y_offs

      if gtab.type == 1 then
        if gtab.show_arc == true then
          f_Get_SSV(gtab.col_arc)
          gfx.arc(cx,cy,gtab.radius,-pi*gtab.arclen +(gtab.rotation*(2*pi)),pi*gtab.arclen +(gtab.rotation*(2*pi)),1)
        end

        local len = pi*(gtab.arclen*2)
        local steps = gtab.ticks
        local ticksize = gtab.tick_size
        local toffx = 4
        local toffy = 1
        local fs = gtab.fontsz
        r=gtab.radius+gtab.tick_offs

        if gtab.show_tick == true or gtab.show_val == true then
          gfx.setfont(1, nz(gtab.font,fontname_def), gui.fontsz_knob+fs)

          local vals = gtab.vals
          if vals and #vals > 0 then
            for i = 0, #vals-1 do

              local nudge = 0
              if gtab.vals[i+1].nudge then
                nudge = gtab.vals[i+1].nudge * 0.002
              end

              local theta
              if gtab.mapptof and gtab.spread then
                if ctl.ctltype == 11 then
                  theta = pi*gtab.arclen -(pi*0.5) +(gtab.rotation*(2*pi)) - (i/(#vals-1) + nudge) * len
                else
                  theta = -pi*gtab.arclen -(pi*0.5) +(gtab.rotation*(2*pi)) + (i/(#vals-1) + nudge) * len
                end
              else

                if ctl.ctltype == 11 then
                  theta = frameScale(ctl.framemode, vals[i+1].val+nudge) * (-2*pi*gtab.arclen) + pi*gtab.arclen -(pi*0.5) +(gtab.rotation*(2*pi))
                else
                  theta = frameScale(ctl.framemode, vals[i+1].val+nudge) * (2*pi*gtab.arclen) - pi*gtab.arclen -(pi*0.5) +(gtab.rotation*(2*pi))
                end
              end

              local showv
              if (i) % gtab.val_freq == 0 then
                showv = true
              end

              local x1, y1 = math.floor(cx + r * math.cos(theta)), math.floor(cy + r * math.sin(theta))
              local x2, y2
              if showv then
                x2, y2 = math.floor(cx + (r+ticksize) * math.cos(theta)), math.floor(cy + (r+ticksize) * math.sin(theta))
              else
                x2, y2 = math.floor(cx + (r+ticksize/3) * math.cos(theta)), math.floor(cy + (r+ticksize/3) * math.sin(theta))
              end

              if gtab.show_tick == true then
                if edit and gauge_ticksel and gauge_ticksel == i+1 then
                  f_Get_SSV('255 0 0')
                else
                  f_Get_SSV(gtab.col_tick)
                end
                if gtab.tick_shape == 2 then
                  gfx.circle(x1,y1,ticksize-2,1,1)
                else
                  gfx.line(x1,y1,x2,y2)
                end  
              end
              if gtab.show_val == true and gtab.vals[i+1] then
                if showv then
                  local dv = gtab.vals[i+1].dval
                  if gtab.val_dp > -1 or gtab.vals[i+1].dover then
                    dv = gtab.vals[i+1].dover
                  end
                  local text_len, th = gfx.measurestr(dv)
                  local chkx = math.floor(x2)-math.floor(cx)
                  local chky = math.floor(y2)-math.floor(cy)
                  if chkx < -10 then
                    tx = x2-text_len - toffx
                  elseif chkx > 10 then
                    tx = x2 + toffx
                  else
                    tx = x2-text_len/2
                  end
                  if chky < -10 then
                    ty = y2-th -toffy
                  elseif chky > 10 then
                    ty = y2 +toffy
                  else
                    ty = y2-th/2
                  end
                  local col = gtab.col_val
                  if edit and gauge_ticksel and gauge_ticksel == i+1 then
                    col = '255 0 0'
                  end
                  GUI_textXY(gui,tx,ty,dv,col,0)
                end
              end
            end
          end

        end

      elseif gtab.type == 2 then

        local lx = cx+gtab.x_offs
        local ly1 = cy+gtab.y_offs-(gtab.arclen/2 * ctl.hsc)
        local ly2 = cy+gtab.y_offs+(gtab.arclen/2 * ctl.hsc)
        if gtab.show_arc == true then
          f_Get_SSV(gtab.col_arc)
          gfx.line(lx,ly1,lx,ly2,1)
        end

        local len = gtab.arclen*ctl.hsc
        local steps = gtab.ticks
        local ticksize = gtab.tick_size
        local toffx = 4
        local toffy = 1
        local fs = gtab.fontsz

        if gtab.show_tick == true or gtab.show_val == true then
          gfx.setfont(1, nz(gtab.font,fontname_def), gui.fontsz_knob+fs)

          local vals = gtab.vals
          if vals and #vals > 0 then
            for i = 0, #vals-1 do

              local nudge = 0
              if gtab.vals[i+1].nudge then
                nudge = gtab.vals[i+1].nudge * 0.002
              end

              local theta
              if gtab.mapptof and gtab.spread then
                theta = (i/(#vals-1) +nudge) * len
              else
                if ctl.ctltype == 11 then
                  theta = len - (frameScale(ctl.framemode, vals[i+1].val)+nudge) * len
                else
                  theta = (frameScale(ctl.framemode, vals[i+1].val)+nudge) * len
                end
              end

              local showv
              if (i) % gtab.val_freq == 0 then
                showv = true
              end

              local x1, y1
              local x2
              if lx <= cx then
                x1, y1 = lx-gtab.tick_offs, ly2-theta
                if showv then
                  x2 = lx-gtab.tick_offs-gtab.tick_size
                else
                  x2 = lx-gtab.tick_offs-(gtab.tick_size/3)
                end
              else
                x1, y1 = lx+gtab.tick_offs, ly2-theta
                if showv then
                  x2 = lx+gtab.tick_offs+gtab.tick_size
                else
                  x2 = lx+gtab.tick_offs+(gtab.tick_size/3)
                end
              end

              if gtab.show_tick == true then
                if edit and gauge_ticksel and gauge_ticksel == i+1 then
                  f_Get_SSV('255 0 0')
                else
                  f_Get_SSV(gtab.col_tick)
                end
                gfx.line(x1,y1,x2,y1)
              end

              if gtab.show_val == true and gtab.vals[i+1] then
                if showv then
                  local dv = gtab.vals[i+1].dval
                  if gtab.val_dp > -1 then
                    dv = gtab.vals[i+1].dover
                  end
                  local text_len, th = gfx.measurestr(dv)
                  if lx <= cx then
                    tx = x2-text_len - toffx
                  else
                    tx = x2 + toffx
                  end
                  ty = y1-th/2
                  local col = gtab.col_val
                  if edit and gauge_ticksel and gauge_ticksel == i+1 then
                    col = '255 0 0'
                  end
                  GUI_textXY(gui,tx,ty,dv,col,0)
                end
              end
            end
          end
        end
      elseif gtab.type == 3 then

        local ly = cy+gtab.y_offs
        local lx1 = cx+gtab.x_offs-(gtab.arclen/2 * ctl.wsc)
        local lx2 = cx+gtab.x_offs+(gtab.arclen/2 * ctl.wsc)
        if gtab.show_arc == true then
          f_Get_SSV(gtab.col_arc)
          gfx.line(lx1,ly,lx2,ly,1)
        end

        local len = gtab.arclen*ctl.wsc
        local steps = gtab.ticks
        local ticksize = gtab.tick_size
        local toffx = 1
        local toffy = 4
        local fs = gtab.fontsz

        if gtab.show_tick == true or gtab.show_val == true then
          gfx.setfont(1, nz(gtab.font,fontname_def), gui.fontsz_knob+fs)

          local vals = gtab.vals
          if vals and #vals > 0 then
            for i = 0, #vals-1 do

              local nudge = 0
              if gtab.vals[i+1].nudge then
                nudge = gtab.vals[i+1].nudge * 0.002
              end

              local theta
              if gtab.mapptof and gtab.spread then
                theta = (i/(#vals-1) +nudge) * len
              else
                if ctl.ctltype == 11 then
                  theta = len - (frameScale(ctl.framemode, vals[i+1].val)+nudge) * len
                else
                  theta = (frameScale(ctl.framemode, vals[i+1].val)+nudge) * len
                end
              end

              local showv
              if (i) % gtab.val_freq == 0 then
                showv = true
              end

              local x1, y1
              local y2
              if ly <= cy then
                y1, x1 = ly-gtab.tick_offs, lx1+theta
                if showv then
                  y2 = ly-gtab.tick_offs-gtab.tick_size
                else
                  y2 = ly-gtab.tick_offs-(gtab.tick_size/3)
                end
              else
                y1, x1 = ly+gtab.tick_offs, lx1+theta
                if showv then
                  y2 = ly+gtab.tick_offs+gtab.tick_size
                else
                  y2 = ly+gtab.tick_offs+(gtab.tick_size/3)
                end
              end

              if gtab.show_tick == true then
                if edit and gauge_ticksel and gauge_ticksel == i+1 then
                  f_Get_SSV('255 0 0')
                else
                  f_Get_SSV(gtab.col_tick)
                end
                gfx.line(x1,y1,x1,y2)
              end

              if gtab.show_val == true and gtab.vals[i+1] then
                if showv then
                  local dv = gtab.vals[i+1].dval
                  if gtab.val_dp > -1 then
                    dv = gtab.vals[i+1].dover
                  end
                  local text_len, th = gfx.measurestr(dv)
                  if ly <= cy then
                    ty = y2-th - toffy
                  else
                    ty = y2 + toffy
                  end
                  tx = x1-text_len/2
                  local col = gtab.col_val
                  if edit and gauge_ticksel and gauge_ticksel == i+1 then
                    col = '255 0 0'
                  end
                  GUI_textXY(gui,tx,ty,dv,col,0)
                end
              end
            end
          end
        end
      end
    end
  end

  function Gauge_CalcTickVals()

    local gtab = gauge_select
    local steps = gtab.ticks
    local c = ctl_select[1].ctl

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    if ctl then

      if steps > 0 then
        --if not gtab.vals then gtab.vals = {} end
        for i = 0, steps-1 do

          if steps-1 <= 0 then
            val = 0
          else
            val = i/(steps-1)
          end
          local dval = nz(GetParamDisp_Val(c, val, true),val)

          gtab.vals[i+1] = {val = val, dval = dval, dover = nil}
          local nonly
          if gtab.numonly then
            nonly = ''
          end
          if gtab.val_dp > -1 then
            gtab.vals[i+1].dover = roundX(dval, gtab.val_dp, nonly)
          end
        end
      else
        gtab.vals = {}
      end
    end

  end

  function Gauge_SortVals()

    local vals = table_slowsort_val(gauge_select.vals)
    if vals then
      gauge_select.vals = vals
    end

  end

  function Gauge_RecalcTickVals()

    local gtab = gauge_select
    local c = ctl_select[1].ctl

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    if ctl then

      if gtab.vals and #gtab.vals > 0 then

        for i = 1, #gtab.vals do

          local dval = gtab.vals[i].dval --GetParamDisp_Val(c, gtab.vals[i].val, true)
          if dval then
            local nonly
            if gtab.numonly then
              nonly = ''
            end
            gtab.vals[i].dover = roundX(dval, gtab.val_dp, nonly, gtab.abbrev)
          end
        end

        --Gauge_SortVals()
      end
    end

  end

  function Gauge_CopySelect(gt)

    --local gt = gauge_select
    local gtab
    if gt then
      gtab = {type = gt.type,
              x_offs = gt.x_offs,
              y_offs = gt.y_offs,
              radius = gt.radius,
              arclen = gt.arclen,
              rotation = gt.rotation,
              ticks = gt.ticks,
              tick_size = gt.tick_size,
              tick_offs = gt.tick_offs,
              val_freq = gt.val_freq,
              col_tick = gt.col_tick,
              col_arc = gt.col_arc,
              col_val = gt.col_val,
              show_arc = gt.show_arc,
              show_tick = gt.show_tick,
              tick_shape = gt.tick_shape,
              show_val = gt.show_val,
              vals = {},
              val_dp = gt.val_dp,
              font = gt.font,
              fontsz = gt.fontsz,
              spread = gt.spread,
              mapptof = gt.mapptof,
              numonly = gt.numonly,
              abbrev = gt.abbrev,
              val = 0}

      if gt.vals and #gt.vals > 0 then

        for i = 1, #gt.vals do

          gtab.vals[i] = {val = gt.vals[i].val,
                          dval = gt.vals[i].dval,
                          dover = gt.vals[i].dover,
                          nudge = gt.vals[i].nudge}

        end
      end
    end

    return gtab

  end

  function Gauge_CopyCycleData()

    local gtab = gauge_select
    local c = ctl_select[1].ctl

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    if ctl then

      if ctl.ctltype == 4 then
        local cycdata = ctl.cycledata
        if cycdata and cycdata.statecnt > 0 then

          gtab.spread = cycdata.spread
          gtab.mapptof = cycdata.mapptof

          gtab.vals = {}
          for i = 1, cycdata.statecnt do

            local gcnt = #gtab.vals+1
            --DBG(gcnt..'  '..cycdata[i].val..'  '..tostring(cycdata[i].dv))
            gtab.vals[gcnt] = {val = cycdata[i].val,
                               dval = cycdata[i].dispval,
                               dover = cycdata[i].dv} 
            local nonly
            if gtab.numonly then
              nonly = ''
            end
            if gtab.val_dp > -1 then
              gtab.vals[gcnt].dover = roundX(gtab.vals[gcnt].dval,gtab.val_dp,nonly)
            end
          end
        end
      end

    end

  end

  function GUI_DrawGauge()

    if tracks[track_select] then
      f_Get_SSV(gui.color.white)
      local strip = tracks[track_select].strip

      --local x,y = 500,500
      if strips and strips[strip] and strips[strip][page].controls[1] then
        for z = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[z]
          if ctl.gauge then
            local hidden = Switcher_CtlsHidden(ctl.switcher, ctl.grpid)
            if ctl.hidden ~= true and hidden ~= true and ctl.hide ~= true then

              local x = math.floor(ctl.xsc + ctl.wsc/2)
              local y = math.floor(ctl.ysc + ctl.hsc/2)
              GUI_DrawGauge2(ctl.gauge,x,y,ctl)

            end
          end
        end
      end
    end

  end

  function GUI_DrawControlBackG(obj, gui)
    --gfx.dest = strip_image+1
    --gfx.clear=256
    if resize_display then
      if surface_size.w == -1 then
        for i = 0, lvar.gfxpages do
          Img_SetDim(strip_image+i,obj.sections[10].w, obj.sections[10].h, true)
          Img_SetDim(bg_image+i,obj.sections[10].w, obj.sections[10].h, true)
        end
      end
    end

    gfx.a = 1

    backcol2 = nil
    if lvar.bgmatchestrackcolour > 0 then
      local col
      if lvar.livemode == 2 then
        local tr = GetTrack(lvar.dynamicmode_trn)
        if tr then
          col = reaper.GetMediaTrackInfo_Value(tr, 'I_CUSTOMCOLOR')
        end
      else
        col = reaper.GetMediaTrackInfo_Value(GetTrack(track_select), 'I_CUSTOMCOLOR')
      end
      if col and (col & 0x1000000 == 0x1000000) then

        local r,g,b = reaper.ColorFromNative(col)
        local m = 1
        if lvar.bgmatchestrackcolour > 1 then
          m = 1/lvar.bgmatchestrackcolour
        end
        backcol2 = tostring(math.floor(r*m))..' '..tostring(math.floor(g*m))..' '..tostring(math.floor(b*m))
        f_Get_SSV(backcol2)
        lvar.backcol = backcol2
      else
        f_Get_SSV(backcol)
        lvar.backcol = backcol
      end
    else
      f_Get_SSV(backcol)
      lvar.backcol = backcol
    end
    if lvar.livemode == 0 or mode > 0 or snaplrn_mode or macro_lrn_mode then
      for i = 0, lvar.gfxpages do
        gfx.dest = bg_image+i
        if lvar.bgloaded > 0 and lvar.livebg then
          gfx.blit(lvar.bgloaded,1,0,0,0,surface_size.w, surface_size.h,0,0)
        else
          gfx.rect(0,
                   0,
                   surface_size.w,
                   surface_size.h, 1, 1)
        end
      end
    else
      for i = 0, lvar.gfxpages do
        --if surface_size.w == -1 then
          --gfx.setimgdim(strip_image+i,-1,-1)
          --gfx.setimgdim(bg_image+i,-1,-1)
          Img_SetDim(strip_image+i,surface_size.w, surface_size.h)
          Img_SetDim(bg_image+i,surface_size.w, surface_size.h)
        --end
      end
    end

    if tracks and tracks[track_select] and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page] then

      if #strips[tracks[track_select].strip][page].graphics > 0 then

        local loop = 1
        if settings_drawbglabelsontop then
          loop = 2
        end

        for lp = 1, loop do
          for i = 1, #strips[tracks[track_select].strip][page].graphics do

            gfx.a = 1

            local gfxx = strips[tracks[track_select].strip][page].graphics[i]
            local hidden = Switcher_CtlsHidden(gfxx.switcher, gfxx.grpid)

            if gfxx.hide == nil and hidden == false then

              local dest = bg_image + (gfxx.gfxpage or 0)
              gfx.dest = dest

              local gtype = gfxx.gfxtype
              local x = gfxx.x
              local y = gfxx.y
              --[[if not surface_size.limit then
                x = x + surface_offset.x
                y = y + surface_offset.y
              end]]

              if gtype == lvar.gfxtype.img and lp == 1 then

                local w = gfxx.w
                local h = gfxx.h
                local sw = gfxx.stretchw
                local sh = gfxx.stretchh
                local imageidx = gfxx.imageidx

                local yoff = 0
                local xoff = 0

                if (gfxx.bright and gfxx.bright ~= 0.5) or (gfxx.contr and gfxx.contr ~= 0.5)
                   or (gfxx.rmult and gfxx.rmult ~= 0.5) or (gfxx.gmult and gfxx.gmult ~= 0.5) or (gfxx.bmult and gfxx.bmult ~= 0.5)
                   or (gfxx.alpha and gfxx.alpha ~= 1) or (lvar.enablegfxshadows and gfxx.shadow) then
                  iidx = 899
                  local ba = -F_limit((0.5-gfxx.bright)*2,-1,1)
                  local bc = gfxx.contr

                  if bc > 0.5 then
                    bc = 1+(bc-0.5)*10
                  else
                    bc = bc*2
                  end

                  local mr = gfxx.rmult
                  local mg = gfxx.gmult
                  local mb = gfxx.bmult
                  if mr > 0.5 then
                    mr = 1+(mr-0.5)*10
                  else
                    mr = mr*2
                  end
                  if mg > 0.5 then
                    mg = 1+(mg-0.5)*10
                  else
                    mg = mg*2
                  end
                  if mb > 0.5 then
                    mb = 1+(mb-0.5)*10
                  else
                    mb = mb*2
                  end

                  local ma = gfxx.alpha

                  gfx.setimgdim(iidx, -1, -1)
                  gfx.setimgdim(iidx, sw, sh)
                  gfx.dest = iidx
                  if gfxx.stretchmode == 1 then
                    gfx.blit(imageidx,1,0, xoff, yoff, w, h-yoff, 0, 0, sw, sh)
                  else
                    local edge = gfxx.edgesz
                    --corners
                    gfx.blit(imageidx,1,0, 0, 0, edge, edge, 0, 0)
                    gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, sw-edge, 0)
                    gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, sw-edge, sh-edge)
                    gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, 0, sh-edge)
                    --sides
                    gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, edge, 0, sw-edge-edge, edge)
                    gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, sw-edge, edge, edge, sh-edge-edge)
                    gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, edge, sh-edge, sw-edge-edge, edge)
                    gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, 0, edge, edge, sh-edge-edge)
                    --middle
                    gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, edge, edge, sw-edge-edge, sh-edge-edge)
                  end
                  gfx.muladdrect(0,0,sw,sh,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)

                  if lvar.enablegfxshadows and gfxx.shadow then
                    local iidx2 = 903
                    gfx.setimgdim(iidx2, -1, -1)
                    gfx.setimgdim(iidx2, sw, sh)
                    gfx.dest = iidx2

                    --
                    local p = lvar.shadow_offsx
                    local shad_w, shad_h = gfx.getimgdim(skin.shadow)
                    local shadedge = 50

                    gfx.a = 1

                    local edge = 50
                    local nedge_h = math.min(math.floor(lvar.shadow_feather), math.floor(sh/2))
                    local nedge_w = math.min(math.floor(lvar.shadow_feather), math.floor(sw/2))

                    --corners
                    gfx.blit(skin.shadow,1,0, 0, 0, edge, edge, 0, 0, nedge_w, nedge_h)
                    gfx.blit(skin.shadow,1,0, shad_w-edge, 0, edge, edge, sw-nedge_w, 0, nedge_w, nedge_h)
                    gfx.blit(skin.shadow,1,0, shad_w-edge, shad_h-edge, edge, edge, sw-nedge_w, sh-nedge_h, nedge_w, nedge_h)
                    gfx.blit(skin.shadow,1,0, 0, shad_h-edge, edge, edge, 0, sh-nedge_h, nedge_w, nedge_h)
                    --sides
                    gfx.blit(skin.shadow,1,0, edge, 0, shad_w-edge-edge, edge, nedge_w, 0, sw-nedge_w-nedge_w, nedge_h)
                    gfx.blit(skin.shadow,1,0, shad_w-edge, edge, edge, shad_h-edge-edge, sw-nedge_w, nedge_h, nedge_w, sh-nedge_h-nedge_h)

                    gfx.blit(skin.shadow,1,0, edge, shad_h-edge, shad_w-edge-edge, edge, nedge_w, sh-nedge_h, sw-nedge_w-nedge_w, nedge_h)
                    gfx.blit(skin.shadow,1,0, 0, edge, edge, shad_h-edge-edge, 0, nedge_h, nedge_w, sh-nedge_h-nedge_h)
                    --middle
                    gfx.blit(skin.shadow,1,0, edge, edge, shad_w-edge-edge, shad_h-edge-edge, nedge_w, nedge_h, sw-nedge_w-nedge_w, sh-nedge_h-nedge_h)




                    gfx.dest = dest
                    gfx.a = lvar.shadow_alpha
                    --p = lvar.shadow_offsx
                    gfx.blit(iidx2,1,0, 0, 0, sw, sh, x+xoff+p, y+yoff+p)
                  end

                  gfx.a = ma
                  gfx.dest = dest

                  gfx.blit(iidx,1,0, 0, 0, sw, sh, x+xoff, y+yoff)
                  --gfx.blit(skin.shadow,1,0, 0, 0, sw, sh, x+xoff, y+yoff)
                else
                  --gfx.blit(imageidx,1,0, xoff, yoff, w, h-yoff, x+xoff, y+yoff, sw, sh)
                  if gfxx.stretchmode == 1 then
                    gfx.blit(imageidx,1,0, xoff, yoff, w, h-yoff, x+xoff, y+yoff, sw, sh)
                  else
                    local edge = gfxx.edgesz

                    --cornersh
                    gfx.blit(imageidx,1,0, 0, 0, edge, edge, x+0, y+0)
                    gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, x+sw-edge, y+0)
                    gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, x+sw-edge, y+sh-edge)
                    gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, x+0, y+sh-edge)
                    --sides
                    gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, x+edge, y+0, sw-edge-edge, edge)
                    gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, x+sw-edge, y+edge, edge, sh-edge-edge)
                    gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, x+edge, y+sh-edge, sw-edge-edge, edge)
                    gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, x+0, y+edge, edge, sh-edge-edge)
                    --middle
                    gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, x+edge, y+edge, sw-edge-edge, sh-edge-edge)
                  end
                end

              elseif gtype == lvar.gfxtype.txt and (loop == 1 or lp == 2) then

                --local w = gfxx.w
                --local h = gfxx.h
                local text = gfxx.text
                local textcol = gfxx.text_col

                local flagb,flagi,flagu, flagv = 0,0,0,0
                if gfxx.font.bold then
                  flagb = 98
                end
                if gfxx.font.italics then
                  flagi = 105
                end
                if gfxx.font.underline then
                  flagu = 117
                end
                if gfxx.font.vertical then
                  flagv = 122
                end
                local flags = flagb + (flagi*256) + (flagu*(256^2))
                gfx.setfont(1,gfxx.font.name,
                              gfxx.font.size,flags)
                local w, h = gfx.measurestr(text)
                if gfxx.font.vertical then
                  w, h = h, w
                  flags = flags + (flagv*(256^3))
                  gfx.setfont(1,gfxx.font.name,
                                gfxx.font.size,flags)
                end
                gfxx.w = w
                gfxx.h = h
                gfxx.stretchw = w
                gfxx.stretchh = h
                if gfxx.font.shadow then

                  local shada = gfxx.font.shadow_a or 0.6
                  local shadx = gfxx.font.shadow_x or 1
                  local shady = gfxx.font.shadow_y or 1
                  --local shadoff = F_limit(math.ceil((gfxx.font.size/250)*10),1,15)

                  f_Get_SSV(gui.color.black)
                  --gfx.a = math.max(shada-(1-backalpha),0)
                  gfx.a = shada
                  gfx.x, gfx.y = x+shadx,y+shady
                  gfx.drawstr(text)
                end

                gfx.a = 1
                --gfx.a = backalpha
                gfx.x, gfx.y = x,y
                f_Get_SSV(textcol)

                gfx.drawstr(text)

              end
            end
          end
        end

      end
    end

    if settings_showgrid and mode ~= 0 and settings_gridsize >= 4 then
      local gs = settings_gridsize
      if gs == 1 then gs = ogrid end
      if lvar.gridimgsz ~= gs then
        DrawGrid(gs,lvar.gridstyle)
      end
      --f_Get_SSV(lvar.gridcolor)
      gfx.a = lvar.gridalpha
      --[[for i = 0, surface_size.w, gs do
        gfx.line(i,0,i,surface_size.h)
      end
      for i = 0, surface_size.h, gs do
        gfx.line(0,i,surface_size.h,i)
      end]]
      local sqw = math.floor(500 / gs)*gs
      local tx = math.floor(surface_size.w / sqw)
      local ty = math.floor(surface_size.h / sqw)
      gfx.dest = bg_image --edit mode only works on first gfxpage currently
      for i = 0, tx do
        for j = 0, ty do
          gfx.blit(982,1,0,0,0,sqw,sqw,i*sqw,j*sqw)
        end
      end
    end
    local ba = math.max(backalpha - backalpha2,0)
    if ba ~= 1 then
      gfx.muladdrect(0,0,surface_size.w,surface_size.h,ba,ba,ba)
    end
    --gfx.muladdrect(0,0,surface_size.w,surface_size.h,1,1,1,1,1,1,1,1)

    GUI_DrawGauge()

    gfx.dest = 1
  end

  function DrawGrid(gs, style)
    if gs == 1 then gs = ogrid end
    if not style then style = 0 end
    gfx.dest = 982
    local sqw = math.floor(500 / gs)*gs
    gfx.setimgdim(982,-1,-1)
    gfx.setimgdim(982,sqw,sqw)
    if style == 0 then

      f_Get_SSV(lvar.gridcolor)
      gfx.mode = 1
      for i = 0, math.floor(500 / gs) do
        gfx.line(0,i*gs,sqw,i*gs)
        gfx.line(i*gs,0,i*gs,sqw)
      end
      gfx.mode = 0

    elseif style == 1 then
      local r,g,b = string.match(lvar.gridcolor,'(%d+) (%d+) (%d+)')
      r = tonumber(r)/255
      g = tonumber(g)/255
      b = tonumber(b)/255
      gfx.mode = 1
      for x = 0, math.floor(500 / gs) do
        for y = 0, math.floor(500 / gs) do
          gfx.x = x*gs
          gfx.y = y*gs
          gfx.setpixel(r,g,b)
        end
      end
      gfx.mode = 0

    elseif style == 2 then

      gfx.mode = 1
      local len = 2
      f_Get_SSV(lvar.gridcolor)
      for x = 0, math.floor(500 / gs) do
        for y = 0, math.floor(500 / gs) do
          gfx.line(x*gs,y*gs-len,x*gs,y*gs+len)
          gfx.line(x*gs-len,y*gs,x*gs+len,y*gs)
        end
      end
      gfx.mode = 0

    end
    lvar.gridimgsz = gs
    gfx.dest = 1

  end

  ------------------------------------------------------------

  function GUI_DrawCycleOptions(obj, gui)

    gfx.dest = 1

    local xywh = {x = obj.sections[100].x,
                  y = obj.sections[100].y-butt_h,
                  w = obj.sections[100].w,
                  h = obj.sections[100].h+butt_h}
    GUI_DrawPanel(xywh,true,'CYCLE OPTS')

    f_Get_SSV('0 0 0')
    gfx.a = 1

    if not cycle_select.val then cycle_select.val = 0 end

    local p = F_limit(math.floor(cycle_select.val*(defctls[def_knob].frames-1)),0,defctls[def_knob].frames-1)
    local kw, _ = gfx.getimgdim(0)
    local kh = defctls[def_knob].cellh
    gfx.blit(def_knob,1,0,0,p*kh,kw,kh,obj.sections[101].x,obj.sections[101].y)

    GUI_DrawButton(gui, cycle_select.statecnt, obj.sections[102], gui.color.white, gui.skol.butt1_txt, true, 'STATES',false,gui.fontsz.butt)
    GUI_DrawButton(gui, 'AUTO', obj.sections[104], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
    GUI_DrawSliderH(gui, 'SENS', obj.sections[110], gui.color.black, gui.color.white, F_limit(auto_delay/10,0,1))
    GUI_textC(gui,obj.sections[110],auto_delay,gui.color.red,-2)

    GUI_DrawTick(gui, 'POS TO FRAME', obj.sections[107], gui.color.white, nz(cycle_select.mapptof, false),gui.fontsz.butt)
    GUI_DrawTick(gui, '', obj.sections[111], gui.color.white, nz(cycle_select.invert, false),gui.fontsz.butt)

    GUI_DrawTick(gui, 'DRAGGABLE', obj.sections[108], gui.color.white, nz(cycle_select.draggable, false),gui.fontsz.butt)
    GUI_DrawTick(gui, 'EVEN SPREAD', obj.sections[109], gui.color.white, nz(cycle_select.spread, false),gui.fontsz.butt)
    GUI_DrawButton(gui, 'SAVE', obj.sections[106], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)

    local c

    f_Get_SSV('16 16 16')
    gfx.rect(obj.sections[103].x-2,
             obj.sections[103].y-2-butt_h*pnl_scale,
             obj.sections[103].w+4,
             obj.sections[103].h+4+butt_h*pnl_scale, 1 )

    --[[f_Get_SSV('64 64 64')
    gfx.rect(obj.sections[105].x-2,
             obj.sections[105].y,
             obj.sections[105].w+4,
             obj.sections[105].h, 1 )]]

    f_Get_SSV('0 0 0')
    local xywh = {x = obj.sections[105].x,
                  y = obj.sections[105].y,
                  w = obj.sections[105].w,
                  h = butt_h*pnl_scale}
    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

    --[[f_Get_SSV('0 0 0')
    gfx.rect(obj.sections[105].x+obj.sections[105].w/2,
             obj.sections[105].y,
             2,
             obj.sections[105].h, 1 )]]

    if cycle_select.statecnt > 0 then

      local rows = math.floor(obj.sections[103].h / (butt_h*pnl_scale))

      f_Get_SSV('0 0 0')
      gfx.rect(obj.sections[103].x,
               obj.sections[103].y,
               obj.sections[103].w,
               math.floor((butt_h*pnl_scale)*F_limit(cycle_select.statecnt,0,rows), 1 ))
      if cycle_select.selected and cycle_select.selected-cyclist_offset <= rows and cycle_select.selected-cyclist_offset > 0 then
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[103].x,
                 math.floor(obj.sections[103].y+(cycle_select.selected-cyclist_offset-1)*(butt_h*pnl_scale)),
                 obj.sections[103].w,
                 math.floor(butt_h*pnl_scale), 1)
      end

      local tscale = (pnl_scale-1)*fontscale
      for i = 1, rows do

        xywh = {x = obj.sections[103].x,
                y = math.floor(obj.sections[103].y+(i-1)*(butt_h*pnl_scale)),
                w = obj.sections[103].w,
                h = math.floor(butt_h*pnl_scale)}
        if cycle_select[i+cyclist_offset] and i+cyclist_offset <= cycle_select.statecnt then
          c = gui.color.white
          if cycle_select.selected and cycle_select.selected == i+cyclist_offset then
            c = gui.color.black
          end

          GUI_textsm_LJ(gui,xywh,math.floor(i+cyclist_offset),c,-5+tscale)
          xywh.x = xywh.x + 20
          GUI_textsm_LJ(gui,xywh,cycle_select[i+cyclist_offset].dispval,c,-5+tscale,xywh.w-20)
        end

      end
    end
  end

  ------------------------------------------------------------

  function GUI_DrawLblOptions(obj, gui)

    gfx.dest = 1

    local xywh = {x = obj.sections[49].x,
                  y = obj.sections[49].y,
                  w = obj.sections[49].w,
                  h = obj.sections[49].h}

    GUI_DrawPanel(xywh, true, 'LABEL OPTS')

    xywh.h = butt_h
    f_Get_SSV(gui.color.white)
    gfx.a = 1

    GUI_DrawButton(gui, 'EDIT LABEL', obj.sections[140], gui.color.white, gui.skol.butt1_txt, true)
    GUI_DrawButton(gui, gfx_font_select.name, obj.sections[147], gui.color.white, gui.skol.butt1_txt, true)
    GUI_DrawSliderH(gui, 'F SIZE', obj.sections[141], gui.color.black, gui.color.white, F_limit(gfx_font_select.size/250,0,1))
    GUI_DrawColorBox(gui, 'LBL COL', obj.sections[142], gui.color.white, gfx_textcol_select)
    GUI_DrawTick(gui, 'BOLD', obj.sections[143], gui.color.white, gfx_font_select.bold)
    GUI_DrawTick(gui, 'ITALIC', obj.sections[144], gui.color.white, gfx_font_select.italics)
    GUI_DrawTick(gui, 'U/LINE', obj.sections[145], gui.color.white, gfx_font_select.underline)
    GUI_DrawTick(gui, 'VERTICAL', obj.sections[151], gui.color.white, gfx_font_select.vertical)
    GUI_DrawTick(gui, 'SHADOW', obj.sections[146], gui.color.white, gfx_font_select.shadow)
    GUI_DrawSliderH(gui, 'SHAD X', obj.sections[148], gui.color.black, gui.color.white, F_limit((gfx_font_select.shadow_x+15)/30,0,1))
    GUI_DrawSliderH(gui, 'SHAD Y', obj.sections[149], gui.color.black, gui.color.white, F_limit((gfx_font_select.shadow_y+15)/30,0,1))
    GUI_DrawSliderH(gui, 'SHAD A', obj.sections[150], gui.color.black, gui.color.white, F_limit(gfx_font_select.shadow_a,0,1))

  end

  ------------------------------------------------------------

  function GUI_DrawGFXOptions(obj, gui)

    gfx.dest = 1

    local xywh = {x = obj.sections[49].x,
                  y = obj.sections[49].y,
                  w = obj.sections[49].w,
                  h = obj.sections[49].h}

    GUI_DrawPanel(xywh, true, 'GRAPHICS OPTS')

    xywh.h = butt_h
    f_Get_SSV(gui.color.white)
    gfx.a = 1
    GUI_DrawSliderH(gui, 'BRIGHTNESS', obj.sections[910], gui.color.black, gui.color.white, F_limit(gfxbright_select,0,1))
    GUI_DrawSliderH(gui, 'CONTRAST', obj.sections[911], gui.color.black, gui.color.white, F_limit(gfxcontr_select,0,1))
    GUI_DrawSliderH(gui, 'R', obj.sections[913], gui.color.black, gui.color.white, F_limit(gfxr_select,0,1))
    GUI_DrawSliderH(gui, 'G', obj.sections[914], gui.color.black, gui.color.white, F_limit(gfxg_select,0,1))
    GUI_DrawSliderH(gui, 'B', obj.sections[915], gui.color.black, gui.color.white, F_limit(gfxb_select,0,1))
    GUI_DrawSliderH(gui, 'A', obj.sections[916], gui.color.black, gui.color.white, F_limit(gfxa_select,0,1))
    GUI_DrawButton(gui, 'RESET', obj.sections[912], gui.color.white, gui.skol.butt1_txt, true)

    GUI_DrawButton(gui, lvar.gfxstretch_table[gfxstretchmode_select], obj.sections[917], gui.color.white, gui.skol.butt1_txt, true, 'STRETCH')
    GUI_DrawButton(gui, gfxedgesz_select, obj.sections[918], gui.color.white, gui.skol.butt1_txt, true, 'EDGE SIZE')
    GUI_DrawTick(gui, 'SHADOW', obj.sections[919], gui.color.white, gfx_shadow_select)

  end

  ------------------------------------------------------------

  function GUI_DrawCtlOptions(obj, gui)

    gfx.dest = 1011

    local tscale = (pnl_scale-1)*fontscale

    GUI_DrawPanel(obj.sections[45],nil,'CTL OPTIONS                ')

    local xywh = {x = 0,
                  y = 2,
                  w = obj.sections[45].w,
                  h = obj.sections[45].h}

    xywh.h = math.floor(gui.winsz.pnltit*pnl_scale)
    --f_Get_SSV(gui.color.white)
    gfx.a = 1

    local w,h = gfx.getimgdim(skin.pnl_ledoff)
    local pw = math.floor(obj.sections[853].w/4)
    local l1,l2,l3,l4 = skin.pnl_ledoff,skin.pnl_ledoff,skin.pnl_ledoff,skin.pnl_ledoff
    if ctl_page == 0 then
      l1 = skin.pnl_ledon
    elseif ctl_page == 1 then
      l2 = skin.pnl_ledon
    elseif ctl_page == 2 then
      l3 = skin.pnl_ledon
    elseif ctl_page == 3 then
      l4 = skin.pnl_ledon
    end
    gfx.blit(l1,1,0,0,0,w,h,obj.sections[853].x,obj.sections[853].y)
    gfx.blit(l2,1,0,0,0,w,h,obj.sections[853].x+pw,obj.sections[853].y)
    gfx.blit(l3,1,0,0,0,w,h,obj.sections[853].x+pw*2,obj.sections[853].y)
    gfx.blit(l4,1,0,0,0,w,h,obj.sections[853].x+pw*3,obj.sections[853].y)

    --[[xywh.x = xywh.x+xywh.w-40
    xywh.w = 30

    f_Get_SSV(gui.color.black)
    gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0)
    GUI_textC(gui,xywh,ctl_page+1,gui.skol.pnl_tittxt,-2)]]

    if ctl_page == 0 then
      local coff = 150*pnl_scale+(gui.winsz.pnltit*pnl_scale-gui.winsz.pnltit)
      xywh = {x = 0,
              y = butt_h*pnl_scale,
              w = obj.sections[45].w,
              h = obj.sections[45].h}

      local iidx = 1023

      if knob_select > -1 then
        if ctl_files[knob_select].imageidx ~= nil then
          iidx = ctl_files[knob_select].imageidx
        else
          gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
        end
        local w, _ = gfx.getimgdim(iidx)
        local h = ctl_files[knob_select].cellh
        gfx.a = 1
        local scale_select = 1

        if w > h then
          if w > 125*pnl_scale then
            scale_select = (125*pnl_scale) / w
          end
        else
          if h > 125*pnl_scale then
            scale_select = (125*pnl_scale) / h
          end
        end

        local yp = math.floor(obj.sections[90].y+obj.sections[90].h/2)
        gfx.blit(iidx,scale_select,0, 0, h*math.ceil((ctl_files[knob_select].frames-1)*0.55), w, h, xywh.x + (xywh.w/2-(w*scale_select)/2), --[[xywh.y + ((62.5*pnl_scale)]] (yp - (h*scale_select)/2))
        xywh = {x = 0,
                y = (butt_h+4)*pnl_scale,
                w = obj.sections[45].w,
                h = butt_h*pnl_scale}
        gfx.a = 0.75

        --[[f_Get_SSV('0 0 0')
        gfx.rect(xywh.x,
                 xywh.y+4,
                 xywh.w,
                 xywh.h-3,1)]]
        xywh.x = xywh.x + 6
        xywh.w = xywh.w - 12
        GUI_textC_LIM(gui,xywh,ctl_files[knob_select].fn,gui.color.white,-5)

      end

      GUI_DrawButton(gui, '<', obj.sections[90], gui.color.white, gui.skol.butt1_txt, true)
      GUI_DrawButton(gui, '>', obj.sections[91], gui.color.white, gui.skol.butt1_txt, true)

      GUI_DrawSliderH(gui, 'SCALE', obj.sections[50], gui.color.black, gui.skol.pnl_txt, (scale_select-0.5)*1)
      GUI_textC_LIM(gui,obj.sections[50],'x'..scale_select,'64 64 64',-2, nil, nil, nil, 5)
      
      local xywh = {x = obj.sections[52].x-10*pnl_scale, y = obj.sections[52].y-butt_h*pnl_scale, w = obj.sections[52].w, h = obj.sections[52].h}
      GUI_textC(gui,xywh,'SHOW',gui.skol.pnl_txt,-5 +tscale)
      GUI_DrawTick(gui, 'NAME', obj.sections[52], gui.skol.pnl_txt, show_paramname)
      GUI_DrawTick(gui, 'VALUE', obj.sections[53], gui.skol.pnl_txt, show_paramval)
      local xywh = {x = obj.sections[54].x, y = obj.sections[54].y-butt_h*pnl_scale, w = obj.sections[54].w, h = obj.sections[54].h}
      GUI_textC(gui,xywh,'COL',gui.skol.pnl_txt,-5+tscale)
      GUI_DrawColorBox(gui, '', obj.sections[54], gui.skol.pnl_txt, textcol_select)
      GUI_DrawColorBox(gui, '', obj.sections[850], gui.skol.pnl_txt, textcolv_select)
      GUI_DrawButton(gui, lvar.ctltype_table[ctltype_select], obj.sections[55], gui.color.white, gui.skol.butt1_txt, true)
      GUI_DrawButton(gui, 'LINK', obj.sections[852], -4, gui.skol.butt4_txt, textoptlink_select)

      local off, valoff
      if toffY then
        off = textoff_select
        valoff = textoffval_select
      else
        off = textoff_selectx
        valoff = textoffval_selectx
      end
      GUI_DrawSliderH(gui, 'OFFSET', obj.sections[56], gui.color.black, gui.skol.pnl_txt, F_limit((off+150)/300,0,1))
      GUI_DrawSliderH(gui, 'VAL OFF', obj.sections[65], gui.color.black, gui.skol.pnl_txt, F_limit((valoff+150)/300,0,1))

      GUI_DrawButton(gui, ctlfont_select or '-', obj.sections[48], gui.color.white, gui.skol.butt1_txt, true, 'FONT', true)
      local xywh = {x = obj.sections[58].x-10*pnl_scale, y = obj.sections[58].y-butt_h*pnl_scale, w = obj.sections[58].w, h = obj.sections[52].h}
      GUI_textC(gui,xywh,'F SIZE',gui.skol.pnl_txt,-5+tscale)

      GUI_DrawSliderH(gui, '', obj.sections[58], gui.color.black, gui.skol.pnl_txt, (textsize_select+2)/35)
      GUI_DrawSliderH(gui, '', obj.sections[851], gui.color.black, gui.skol.pnl_txt, (textsizev_select+2)/35)
      GUI_DrawSliderH(gui, 'DEF VAL', obj.sections[57], gui.color.black, gui.skol.pnl_txt, F_limit(defval_select,0,1))
      GUI_DrawTick(gui, '', obj.sections[962], gui.skol.pnl_txt, enabledefval_select)

      GUI_DrawButton(gui, 'SET IMAGE', obj.sections[51], gui.color.white, gui.skol.butt1_txt, true)
      --GUI_DrawButton(gui, 'EDIT NAME', obj.sections[59], gui.color.white, gui.skol.butt1_txt, true)

      local editname = ''
      if ctl_select and ctl_select[1] and ctl_select[1].ctl and strips[tracks[track_select].strip] then
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
        if ctl then
          if ctl.ctlcat == ctlcats.midictl then
            local midiset = false
            if ctl.midiout then
              midiset = true
            end
            GUI_DrawButton(gui, 'SET MIDI', obj.sections[960], gui.color.blue, gui.skol.butt1_txt, midiset)
          end
          if (ctl.ctlname_override or '') ~= '' then
            editname = ctl.ctlname_override
          else
            editname = ctl.param_info.paramname
          end
        end
      end

      GUI_DrawButton(gui, editname, obj.sections[59], gui.color.white, gui.skol.butt1_txt, true, 'NAME')

      local dir
      if toffY then dir = 'Y' else dir = 'X' end
      GUI_DrawButton(gui, dir, obj.sections[68], gui.color.white, gui.skol.butt1_txt, true)

      if ctltype_select == 4 then
        if show_cycleoptions then
          GUI_DrawButton(gui, '>>', obj.sections[67], gui.color.white, gui.skol.butt1_txt, true)
        else
          GUI_DrawButton(gui, '<<', obj.sections[67], gui.color.white, gui.skol.butt1_txt, true)
        end
      end

      local mdptxt = maxdp_select
      if maxdp_select < 0 then
        mdptxt = 'OFF'
      end
      GUI_DrawButton(gui, mdptxt, obj.sections[66], gui.color.white, gui.skol.butt1_txt, true, 'MAX DP')

      local v = false
      if gauge_select then
        v = true
      end
      GUI_DrawButton(gui, 'GAUGE', obj.sections[99], gui.color.white, gui.skol.butt1_txt, v)

    elseif ctl_page == 1 then

      GUI_DrawButton(gui, dvaloff_select, obj.sections[125], gui.color.white, gui.skol.butt1_txt, true, 'VDISP OFF')

      local min, max = GetParamMinMax_ctlselect()
      if minov_select == nil then
        minov_select = min
      end
      if maxov_select == nil then
        maxov_select = max
      end
      GUI_DrawButton(gui, minov_select, obj.sections[126], gui.color.white, gui.skol.butt1_txt, true, 'MIN OV', true)
      GUI_DrawButton(gui, maxov_select, obj.sections[127], gui.color.white, gui.skol.butt1_txt, true, 'MAX OV', true)
      GUI_DrawButton(gui, nz(ov_disp,''), obj.sections[130], -3, gui.skol.butt1_txt, true, '')
      GUI_DrawButton(gui, lvar.scalemode_preset_table[knob_scalemode_select], obj.sections[131], gui.color.white, gui.skol.butt1_txt, true, 'SCALE PSET')
      GUI_DrawButton(gui, lvar.scalemode_dtable[scalemode_select], obj.sections[132], gui.color.white, gui.skol.butt1_txt, true, 'SCALE MOD')
      GUI_DrawButton(gui, lvar.framemode_table[framemode_select], obj.sections[133], gui.color.white, gui.skol.butt1_txt, true, 'FRAME MOD')
      GUI_DrawTick(gui, 'HORIZ SLIDER', obj.sections[134], gui.skol.pnl_txt, horiz_select)
      GUI_DrawTick(gui, 'PAGE SNAP EXCLUDE', obj.sections[139], gui.skol.pnl_txt, noss_select)

      xywh = {x = 0,
              y = obj.sections[135].y-butt_h-5,
              w = obj.sections[45].w,
              h = butt_h}
      GUI_textC(gui,xywh,'KNOB SENSITIVITY',gui.skol.pnl_txt,-2+tscale)
      GUI_DrawSliderH(gui, 'NORMAL', obj.sections[135], gui.color.black, gui.skol.pnl_txt, ((knobsens_select.norm)/20)*2)
      local txt = string.format('%i',round(knobsens_select.norm*2))
      if txt == '0' then 
        txt = 'GLOBAL' 
      elseif knobsens_select.m_norm ~= 1 then
        txt = txt..' (x'..knobsens_select.m_norm..')'
      end
      GUI_textC(gui,obj.sections[135],txt,gui.color.red,-2+tscale)
      GUI_DrawSliderH(gui, 'FINE', obj.sections[136], gui.color.black, gui.skol.pnl_txt, ((knobsens_select.fine)/20)*100)
      txt = string.format('%i',round(knobsens_select.fine*100))
      if txt == '0' then 
        txt = 'GLOBAL' 
      elseif knobsens_select.m_fine ~= 1 then
        txt = txt..' (x'..knobsens_select.m_fine..')'
      end
      GUI_textC(gui,obj.sections[136],txt,gui.color.red,-2+tscale)
      GUI_DrawSliderH(gui, 'WHEEL', obj.sections[137], gui.color.black, gui.skol.pnl_txt, ((knobsens_select.wheel)/20)*100)
      txt = string.format('%i',round(knobsens_select.wheel*100))
      if txt == '0' then 
        txt = 'GLOBAL' 
      elseif knobsens_select.m_wheel ~= 1 then
        txt = txt..' (x'..knobsens_select.m_wheel..')'
      end
      GUI_textC(gui,obj.sections[137],txt,gui.color.red,-2+tscale)
      GUI_DrawSliderH(gui, 'WHL FINE', obj.sections[138], gui.color.black, gui.skol.pnl_txt, ((knobsens_select.wheelfine)/20)*1000)
      txt = string.format('%i',round(knobsens_select.wheelfine*1000))
      if txt == '0' then 
        txt = 'GLOBAL' 
      elseif knobsens_select.m_wheelfine ~= 1 then
        txt = txt..' (x'..knobsens_select.m_wheelfine..')'
      end
      GUI_textC(gui,obj.sections[138],txt,gui.color.red,-2+tscale)

      local pmin, pmax = 0, 0
      if min and max then
        pmin = normalize(min, max, minov_select)
        pmax = normalize(min, max, maxov_select)
      end
      local w, _ = gfx.getimgdim(def_knobsm)
      gfx.blit(def_knobsm,1,0, 0, defctls[def_knobsm].cellh*math.floor((defctls[def_knobsm].frames-1)*pmin), w, defctls[def_knobsm].cellh, obj.sections[128].x, obj.sections[128].y)
      gfx.blit(def_knobsm,1,0, 0, defctls[def_knobsm].cellh*math.floor((defctls[def_knobsm].frames-1)*pmax), w, defctls[def_knobsm].cellh, obj.sections[129].x, obj.sections[129].y)

    elseif ctl_page == 2 then

      GUI_DrawTick(gui, 'BYPASS BG CTL', obj.sections[860], gui.skol.pnl_txt, bypass_bgdraw_c_select)
      GUI_DrawTick(gui, 'BYPASS BG NAME', obj.sections[861], gui.skol.pnl_txt, bypass_bgdraw_n_select)
      GUI_DrawTick(gui, 'BYPASS BG VAL', obj.sections[862], gui.skol.pnl_txt, bypass_bgdraw_v_select)

      GUI_DrawTick(gui, 'CLICK THROUGH', obj.sections[863], gui.skol.pnl_txt, clickthrough_select)
      GUI_DrawTick(gui, "AUTO MONITOR VALUE", obj.sections[864], gui.skol.pnl_txt, not dnu_select)
      GUI_DrawTick(gui, "OVERRIDE REFRESH RATE", obj.sections[869], gui.skol.pnl_txt, orr_select)

      GUI_DrawTick(gui, "TARGET SELECTED TRACK", obj.sections[865], gui.skol.pnl_txt, targetseltrack_select)
      GUI_DrawButton(gui, wwtext_select or '', obj.sections[868], gui.color.white, gui.skol.butt1_txt, true, 'WORD WRAP WIDTH')
      GUI_DrawButton(gui, limittext_select or '', obj.sections[866], gui.color.white, gui.skol.butt1_txt, true, 'LIMIT TEXT')
      GUI_DrawButton(gui, flags_select or '', obj.sections[867], gui.color.white, gui.skol.butt1_txt, true, 'TEXT FLAGS')

      GUI_DrawButton(gui, animatetime_select or 'Off', obj.sections[870], gui.color.white, gui.skol.butt1_txt, true, 'CLICK ANIMATE (ms)')
      GUI_DrawButton(gui, lvar.macroscale_sm_table[animateshape_select or 1], obj.sections[871], gui.color.white, gui.skol.butt1_txt, true, 'ANIMATE SHAPE')

    elseif ctl_page == 3 then

      local strip = tracks[track_select].strip
      if ctl_select and ctl_select[1] and ctl_select[1].ctl and strips[strip] then

        local ctl = strips[strip][page].controls[ctl_select[1].ctl]
        local ccat = ctl.ctlcat

        if lvar.CP4Funcs[ccat] then
          local CP4_func = lvar.CP4Funcs[ccat].draw
          if CP4_func then CP4_func(obj, gui, ctl) end
        end

        local c = 0.2
        if adjust_active_select == 1 then
          c = 1
        end
        GUI_DrawSliderH(gui, 'BRIGHTNESS', obj.sections[8050], gui.color.black, gui.color.white, F_limit(adjust_bright_select/512,0,1),nil,nil,c)
        GUI_DrawSliderH(gui, 'CONTRAST', obj.sections[8051], gui.color.black, gui.color.white, F_limit(adjust_contrast_select/512,0,1),nil,nil,c)
        GUI_DrawSliderH(gui, 'R', obj.sections[8052], gui.color.black, gui.color.white, F_limit(adjust_r_select/512,0,1),nil,nil,c)
        GUI_DrawSliderH(gui, 'G', obj.sections[8053], gui.color.black, gui.color.white, F_limit(adjust_g_select/512,0,1),nil,nil,c)
        GUI_DrawSliderH(gui, 'B', obj.sections[8054], gui.color.black, gui.color.white, F_limit(adjust_b_select/512,0,1),nil,nil,c)

      end

    end

    gfx.dest = 1
  end

  function CP4_Draw_InfoCtl(obj, gui, ctl)

    tscale = (pnl_scale-1)*fontscale

    GUI_DrawButton(gui, string.upper(lvar.ctlcats_nm[ctl.ctlcat+1]), obj.sections[8000], gui.color.white, gui.skol.butt1_txt, true, '')

    local str = ''
    if ctl.param == 2 then
      str = ' ' .. string.format('%i', ctl.param_info.paramidx + 1)
    end

    GUI_DrawButton(gui, lvar.infoctl_table[ctl.param] .. str, obj.sections[8020], gui.color.white, gui.skol.butt1_txt, true, '')
    if ctl.param == 2 then
      local cfx = false
      if ctl.infoctl and ctl.infoctl.closefx then
        cfx = true
      end
      local pfx = false
      if ctl.infoctl and ctl.infoctl.positionfx then
        pfx = true
      end

      GUI_DrawTick(gui, 'Close other fx windows', obj.sections[8021], gui.skol.pnl_txt, cfx, gui.fontsz.butt)
      GUI_DrawTick(gui, 'Reposition fx window', obj.sections[8022], gui.skol.pnl_txt, pfx, gui.fontsz.butt)

      GUI_DrawButton(gui, 'Set Boundary (GLOBAL)', obj.sections[8023], gui.color.white, gui.skol.butt1_txt, true, '')
      local xywh = {x = obj.sections[8024].x+100*pnl_scale,
                    y = obj.sections[8024].y,
                    w = obj.sections[8024].w-100*pnl_scale,
                    h = obj.sections[8024].h}
      local xywh2 = {x = xywh.x-100*pnl_scale,
                    y = obj.sections[8024].y,
                    w = (xywh.x-10*pnl_scale)-(xywh.x-100*pnl_scale),
                    h = obj.sections[8024].h}
      GUI_Str(gui,xywh,lvar.fxpos.l,4,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      GUI_Str(gui,xywh2,'Boundary left:',6,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      xywh.y = xywh.y + xywh.h
      xywh2.y = xywh2.y + xywh.h
      GUI_Str(gui,xywh,lvar.fxpos.t,4,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      GUI_Str(gui,xywh2,'Boundary top:',6,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      xywh.y = xywh.y + xywh.h
      xywh2.y = xywh2.y + xywh.h
      GUI_Str(gui,xywh,lvar.fxpos.w,4,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      GUI_Str(gui,xywh2,'Boundary width:',6,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      xywh.y = xywh.y + xywh.h
      xywh2.y = xywh2.y + xywh.h
      GUI_Str(gui,xywh,lvar.fxpos.h,4,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
      GUI_Str(gui,xywh2,'Boundary height:',6,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    end
  end

  function CP4_Draw_Action(obj, gui, ctl)

    tscale = (pnl_scale-1)*fontscale

    GUI_DrawButton(gui, string.upper(lvar.ctlcats_nm[ctl.ctlcat+1]), obj.sections[8000], gui.color.white, gui.skol.butt1_txt, true, '')

    GUI_DrawButton(gui, 'Assign From Action List', obj.sections[8004], gui.color.white, gui.skol.butt1_txt, true, '')
    local commid = ctl.param_info.paramname

    GUI_Str(gui,obj.sections[8005],commid,4,gui.color.white,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    local t = ''
    if ctl.monext == nil then
      t = 'Monitor Action State'
    else
      t = 'Monitor Ext State'
    end
    GUI_DrawButton(gui, t, obj.sections[8006], gui.color.white, gui.skol.butt1_txt, true, '')

    if ctl.monext then
      GUI_DrawButton(gui, ctl.monext.section, obj.sections[8007], gui.color.white, gui.skol.butt1_txt, true, 'SECTION')
      GUI_DrawButton(gui, ctl.monext.key, obj.sections[8008], gui.color.white, gui.skol.butt1_txt, true, 'KEY')
      GUI_DrawButton(gui, ctl.monext.range_start, obj.sections[8009], gui.color.white, gui.skol.butt1_txt, true, 'RANGE START')
      GUI_DrawButton(gui, ctl.monext.range_end, obj.sections[8010], gui.color.white, gui.skol.butt1_txt, true, 'END')
    end

  end

  function CP4_Draw_NaviCtl(obj, gui, ctl)

    GUI_DrawButton(gui, string.upper(lvar.ctlcats_nm[ctl.ctlcat+1]), obj.sections[8000], gui.color.white, gui.skol.butt1_txt, true, '')

    local typ = ''
    if ctl.param == 1 then
      typ = 'Strip/Page'
    elseif ctl.param == 2 then
      typ = 'Location'
    elseif ctl.param == 3 then
      typ = 'Edit Mode'
    end
    GUI_DrawButton(gui, typ, obj.sections[8001], gui.color.white, gui.skol.butt1_txt, true, 'TYPE')

    if ctl.param ~= 3 then
      local tn = ''

      if ctl.param_info.paramnum > -2 then
        local tr = GetTrack(ctl.param_info.paramnum)
        if tr then
          tn = ctl.param_info.paramnum..': '..reaper.GetTrackState(tr)
        end
      else
        if ctl.param_info.paramnum == -4 then
          tn = 'No Change'
        elseif ctl.param_info.paramnum == -3 then
          tn = 'Previous Strip'
        elseif ctl.param_info.paramnum == -2 then
          tn = 'Next Strip'
        end
      end

      local c = gui.skol.butt1_txt
      if tonumber(ctl.param_info.paramidx) == -1 then
        c = '128 128 128'
      end
      GUI_DrawButton(gui, tn, obj.sections[8002], gui.color.white, c, true, 'TRACK')

      local tp = ''
      if tonumber(ctl.param_info.paramidx) >= 0 then
        tp = 'Page '..string.format('%i',ctl.param_info.paramidx)
      else
        local pidx = tonumber(ctl.param_info.paramidx)
        if pidx == -4 then
          tp = 'No Change'
        elseif pidx == -3 then
          tp = 'Previous Page'
        elseif pidx == -2 then
          tp = 'Next Page'
        elseif pidx == -1 then
          tp = 'Global Page'
        end
      end
      GUI_DrawButton(gui, tp, obj.sections[8003], gui.color.white, gui.skol.butt1_txt, true, 'PAGE')
    end

  end

  function GUI_DrawSliderH(gui, t, b, colb, cols, v, t_sz, noscale, alpha)

    local tscale = 0
    if noscale ~= true then
      tscale = (pnl_scale-1)*fontscale
    end

    local xywh = {x=b.x-300,y=b.y-2,w=290,h=b.h}
    --GUI_textsm_RJ(gui,xywh,t,cols,-4+(t_sz or 0))
    cols = gui.skol.pnl_txt
    GUI_Str(gui,xywh,t,6,cols,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    local w, h = gfx.getimgdim(skin.slider_fg)
    --gfx.blit(skin.slider_bg, 1, 0, 0, 0, w, h, b.x, b.y, b.w, b.h)
    --gfx.blit(skin.slider_bg, 1, 0, w-1, 0, 1, h, b.x+b.w-1, b.y, 1, b.h)
    f_Get_SSV(cols)
    gfx.a = alpha or 1
    gfx.rect(b.x,
             b.y,
             b.w,
             b.h, 0)

    v = math.min(v,1)

    local iw = math.min(math.ceil(w * v),w)
    local vw = math.min(math.ceil((b.w-4) * v))
    gfx.blit(skin.slider_fg, 1, 0, 0, 0, iw, h, b.x+2, b.y+2, vw, b.h-4)


    --[[
    f_Get_SSV(colb)
    gfx.a = 1
    local w = math.floor((b.w-2) - (b.w-2) * v)
    if w > 0 then
      gfx.rect(b.x+1 + (b.w-2)-w,
               b.y+1,
               w,
               b.h-2, 1 )
    end]]

  end

  function GUI_DrawButton(gui, t, b, colb, colt, v, opttxt, pad, t_sz,noscale, butt_justify, opttxt_col)

    --if not b then return end

    local tscale = 0
    if noscale ~= true then
      tscale = round((pnl_scale-1)*fontscale)
    end

    b.x = math.floor(b.x)
    b.y = math.floor(b.y)


    if (opttxt or '') ~= '' then
      local xywh = {x=b.x-500,y=b.y-2,w=490,h=b.h+5}
      --local c = colb
      --if tonumber(c) ~= nil then
        c = opttxt_col or gui.skol.pnl_txt
      --end
      GUI_Str(gui,xywh,opttxt,6,c,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
    end

    local f = 1
    if v == nil or v == false then
      f = 0
      colb = -3
    end

    local sl, sr, sm, wl ,hl, wr, hr, wm, hm, w, h, fcol
    if (tonumber(colb) and (colb > -5 or colb <= -8)) or colb == gui.color.white then

      if colb == -1 then
        w, h = gfx.getimgdim(skin.butt18G)
        sl = skin.butt18G
        fcol = gui.skol.buttG_txt
      elseif colb == -2 then
        w, h = gfx.getimgdim(skin.butt18R)
        sl = skin.butt18R
        fcol = gui.skol.butt2_txt
      elseif colb == -3 then
        w, h = gfx.getimgdim(skin.butt18T)
        sl = skin.butt18T
        fcol = gui.skol.butt3_txt
      elseif colb == -4 then
        w, h = gfx.getimgdim(skin.butt18Y)
        sl = skin.butt18Y
        fcol = gui.skol.butt4_txt
      elseif colb == -8 then
        w, h = gfx.getimgdim(skin.butt18B)
        sl = skin.butt18B
        fcol = gui.skol.butt8_txt
      elseif colb == -9 then
        w, h = gfx.getimgdim(skin.butt18Gr)
        sl = skin.butt18Gr
        fcol = gui.skol.butt9_txt
      elseif colb == -10 then
        w, h = gfx.getimgdim(skin.butt18O)
        sl = skin.butt18O
        fcol = gui.skol.butt10_txt
      else
        w, h = gfx.getimgdim(skin.butt18)
        sl = skin.butt18
        fcol = gui.skol.butt1_txt
      end

      local corner = 6
      local corner2 = 12
      --TL
      gfx.blit(sl, 1, 0, 0, 0, corner, corner, b.x, b.y)
      --TR
      gfx.blit(sl, 1, 0, w-corner, 0, corner, corner, b.x+b.w-corner, b.y)
      --BL
      gfx.blit(sl, 1, 0, 0, h-corner, corner, corner, b.x, b.y+b.h-corner)
      --BR
      gfx.blit(sl, 1, 0, w-corner, h-corner, corner, corner, b.x+b.w-corner, b.y+b.h-corner)
      --T
      gfx.blit(sl, 1, 0, corner, 0, w-corner2, corner, b.x+corner, b.y, b.w-corner2, corner)
      --B
      gfx.blit(sl, 1, 0, corner, h-corner, w-corner2, corner, b.x+corner, b.y+b.h-corner, b.w-corner2, corner)
      --L
      gfx.blit(sl, 1, 0, 0, corner, corner, h-corner2, b.x, b.y+corner, corner, b.h-corner2)
      --R
      gfx.blit(sl, 1, 0, w-corner, corner, corner, h-corner2, b.x+b.w-corner, b.y+corner, corner, b.h-corner2)
      --M
      gfx.blit(sl, 1, 0, corner, corner, w-corner2, h-corner2, b.x+corner, b.y+corner, b.w-corner2, b.h-corner2)

    else
      --w, h = gfx.getimgdim(skin.butt18)
      --sl = skin.butt18
      if colb == -5 then
        fcol = gui.skol.butt1_txt
      elseif colb == -7 then
        f_Get_SSV(colt)
        gfx.roundrect(math.floor(b.x+3),math.floor(b.y+3),math.floor(b.w-6),math.floor(b.h-6),6,1)
        fcol = colt
      else
        fcol = colt
      end
    end

    if f == 0 or tonumber(colb) ~= nil then
      --[[if tonumber(colb) ~= nil and colb == -1 or colb == -3 then
        colt = fcol
      elseif tonumber(colb) ~= nil and colb == -2 or colb == -4 or colb == -5 or colb == -6 or colb == -7 then
        colt = fcol]]
      if tonumber(colb) ~= nil then
        colt = fcol
      else
        colt = colb
      end
    end
    local limit = tonumber(pad)
    local xywh
    if not limit then
      xywh = {x=b.x,y=b.y,w=b.w,h=b.h}
    else
      xywh = {x=b.x+limit,y=b.y,w=b.w-limit*2,h=b.h}
    end
    GUI_Str(gui,xywh,t,butt_justify or 5,colt,-4 + (t_sz or 0) + gui.fontsz.butt +tscale,1,gui.skol.butt_shad,gui.fontnm.butt,gui.fontflag.butt)

  end

  function GUI_DrawButtonWW(gui, t, th, maxrows, b, colb, colt, v, opttxt, limit, t_sz,noscale, butt_justify, opttxt_col, toptext, toptextsz, rgbadjust, ovcolt)

    local tscale = 0
    if noscale ~= true then
      tscale = round((pnl_scale-1)*fontscale)
    end
    --if t == 'FreqEcho' then
    --  DBG(b.x..  '  '..b.y)
    --end
    b.x = math.floor(b.x)
    b.y = math.floor(b.y)

    if (opttxt or '') ~= '' then
      local xywh = {x=b.x-300,y=b.y-2,w=290,h=b.h+5}
      --local c = colb
      --if tonumber(c) ~= nil then
        c = opttxt_col or gui.skol.pnl_txt
      --end
      GUI_Str(gui,xywh,opttxt,6,c,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)
    end

    local f = 1
    if v == nil or v == false then
      f = 0
      colb = -3
    end

    local sl, sr, sm, wl ,hl, wr, hr, wm, hm, w, h, fcol

    if colb ~= -5 and colb ~= -6 then

      if colb == -1 then
        w, h = gfx.getimgdim(skin.butt18G)
        sl = skin.butt18G
        fcol = gui.skol.buttG_txt
      elseif colb == -2 then
        w, h = gfx.getimgdim(skin.butt18R)
        sl = skin.butt18R
        fcol = gui.skol.butt2_txt
      elseif colb == -3 then
        w, h = gfx.getimgdim(skin.butt18T)
        sl = skin.butt18T
        fcol = gui.skol.butt3_txt
      elseif colb == -4 then
        w, h = gfx.getimgdim(skin.butt18Y)
        sl = skin.butt18Y
        fcol = gui.skol.butt4_txt
      elseif colb == -8 then
        w, h = gfx.getimgdim(skin.butt18B)
        sl = skin.butt18B
        fcol = gui.skol.butt8_txt
      elseif colb == -9 then
        w, h = gfx.getimgdim(skin.butt18Gr)
        sl = skin.butt18Gr
        fcol = gui.skol.butt9_txt
      elseif colb == -10 then
        w, h = gfx.getimgdim(skin.butt18O)
        sl = skin.butt18O
        fcol = gui.skol.butt10_txt

      elseif colb == -11 then
        w, h = gfx.getimgdim(skin.butt18W)
        sl = skin.butt18W
        fcol = gui.skol.butt10_txt
      else
        w, h = gfx.getimgdim(skin.butt18)
        sl = skin.butt18
        fcol = gui.skol.butt1_txt
      end

      local corner = 6
      local corner2 = 12
      --TL
      gfx.blit(sl, 1, 0, 0, 0, corner, corner, b.x, b.y)
      --TR
      gfx.blit(sl, 1, 0, w-corner, 0, corner, corner, b.x+b.w-corner, b.y)
      --BL
      gfx.blit(sl, 1, 0, 0, h-corner, corner, corner, b.x, b.y+b.h-corner)
      --BR
      gfx.blit(sl, 1, 0, w-corner, h-corner, corner, corner, b.x+b.w-corner, b.y+b.h-corner)
      --T
      gfx.blit(sl, 1, 0, corner, 0, w-corner2, corner, b.x+corner, b.y, b.w-corner2, corner)
      --B
      gfx.blit(sl, 1, 0, corner, h-corner, w-corner2, corner, b.x+corner, b.y+b.h-corner, b.w-corner2, corner)
      --L
      gfx.blit(sl, 1, 0, 0, corner, corner, h-corner2, b.x, b.y+corner, corner, b.h-corner2)
      --R
      gfx.blit(sl, 1, 0, w-corner, corner, corner, h-corner2, b.x+b.w-corner, b.y+corner, corner, b.h-corner2)
      --M
      gfx.blit(sl, 1, 0, corner, corner, w-corner2, h-corner2, b.x+corner, b.y+corner, b.w-corner2, b.h-corner2)

      if rgbadjust then
        local mr = ((rgbadjust & 255) / 255)
        local mg = (((rgbadjust >> 8) & 255) / 255)
        local mb = (((rgbadjust >> 16) & 255) / 255)
        gfx.muladdrect(b.x,b.y,b.w,b.h,mr,mg,mb)
      end
    else
      --w, h = gfx.getimgdim(skin.butt18)
      --sl = skin.butt18
      if colb == -5 then
        fcol = gui.skol.butt1_txt
      elseif colb == -7 then
        f_Get_SSV(colt)
        gfx.roundrect(math.floor(b.x+3),math.floor(b.y+3),math.floor(b.w-6),math.floor(b.h-6),6,1)
        fcol = colt
      else
        fcol = colt
      end
    end

    if f == 0 or tonumber(colb) ~= nil then
      --[[if tonumber(colb) ~= nil and colb == -1 or colb == -3 then
        colt = fcol
      elseif tonumber(colb) ~= nil and colb == -2 or colb == -4 or colb == -5 or colb == -6 then
        colt = fcol]]
      if tonumber(colb) ~= nil then
        colt = fcol
      else
        colt = colb
      end
    end

    --local th = 16
    local thh = math.min(#t,maxrows)*th
    local yy = math.floor(b.y+(b.h/2)-(thh/2))
    local xywh = {x=b.x+4,y=b.y+2,w=b.w-8,h=th}
    if toptext then
      local _, tthh = GUI_Str(gui,xywh,toptext,butt_justify or 5,colt,-4 + (toptextsz or 0) + gui.fontsz.butt +tscale,1,gui.skol.butt_shad,gui.fontnm.butt,gui.fontflag.butt)
      yy = math.max(yy, xywh.y + tthh)
    end
    xywh.y = yy
    for i = 1, math.min(#t, maxrows) do
      if t[i].t then
        if xywh.y-b.y+th < b.h then
          GUI_Str(gui,xywh,t[i].t,butt_justify or 5,ovcolt or colt,-4 + (t_sz or 0) + gui.fontsz.butt +tscale,1,gui.skol.butt_shad,gui.fontnm.butt,gui.fontflag.butt)
          xywh.y = xywh.y + th
        else
          break
        end
      end
    end

  end

  function GUI_DrawTick(gui, t, b, col, v, t_sz, noscale)

    --local xywh = {x=b.x-10,y=b.y-2,w=1,h=b.h}
    --GUI_textsm_RJ(gui,xywh,t,col,-4+(t_sz or 0))
    local xywh = {x=b.x-600,y=b.y-2,w=590,h=b.h+5}
    local tscale = 0
    if noscale ~= true then
      tscale = (pnl_scale-1)*fontscale
    end

    GUI_Str(gui,xywh,t,6,gui.skol.pnl_txt,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    local f = 1
    if v == nil or v == false then
      f = 0
    end
    f_Get_SSV(col)
    gfx.a = 1
    gfx.rect(b.x,
             b.y,
             b.w,
             b.h, f)
    if f == 1 then
      f_Get_SSV(gui.color.black)
      gfx.line(b.x,b.y,b.x+b.w,b.y+b.h)
      gfx.line(b.x,b.y+b.h,b.x+b.w,b.y)
    end

  end

  function GUI_DrawColorBox(gui, t, b, col, cols, t_sz, noscale)

    local xywh = {x=b.x-300,y=b.y-2,w=290,h=b.h+5}
    --GUI_textsm_RJ(gui,xywh,t,col,-4 + (t_sz or 0))
    local tscale = 0
    if noscale ~= true then
      tscale = (pnl_scale-1)*fontscale
    end
    col = gui.skol.pnl_txt
    GUI_Str(gui,xywh,t,6,col,-4 + (t_sz or 0) +tscale,1,nil,gui.fontnm.sb,98)

    local f = 1
    f_Get_SSV(cols)
    gfx.a = 1
    gfx.rect(b.x,
             b.y,
             b.w,
             b.h, f)
    f_Get_SSV(col)
    gfx.a = 1
    gfx.rect(b.x,
             b.y,
             b.w,
             b.h, 0)

  end

  ------------------------------------------------------------
  function round(num, idp)
    --num = tonumber(num)
    --if num then
      if tonumber(num) == nil then return num end

      local mult = 10^(idp or 0)
      return math.floor(num * mult + 0.5) / mult
    --else
    --  return nz(num,'')
    --end
  end

  function roundX(num, idp, suffix, abbrev)
    if num == nil then return end
    local s, e = string.find(num,'%d+.%d+')
    if s and e then
      local n = string.sub(num,s,e)
      if n and tonumber(n) then
        local mult = 10^(idp or 0)
        local res = math.floor(n * mult + 0.5) / mult
        if idp == 0 then
          res = string.match(tostring(res),'%d+')
          if abbrev == true then
            if tonumber(res) >= 1000 then
              res = string.gsub(tonumber(res)/1000,'%.','k')
              if tonumber(string.match(res, 'k(.*)')) == 0 then
                res = string.match(res, '(.-k).*')
              end
            end
          end
        end
        if suffix then
          local pfx = ''
          if string.sub(num,s-2,s-1) == '-' and tonumber(res) ~= 0 then
            pfx = '-'
          end
          return pfx..res..suffix
        else
          return string.sub(num,1,s-1) .. res .. string.sub(num,e+1)
        end
      else
        return num
      end
    else
      return num
    end
  end

  function GetNumericPart(num)
    local s, e = string.find(num,'%-%d+.%d+')
    if s == nil then
      s, e = string.find(num,'%d+.%d+')
    end
    if s and e then
      local n = string.sub(num,s,e)
      if n and tonumber(n) then
        res = tonumber(n)
        return res
      else
        return num
      end
    else
      local s, e = string.find(num,'%-%d+')
      if s == nil then
        s, e = string.find(num,'%d+')
      end
      if s and e then
        local n = string.sub(num,s,e)
        if n and tonumber(n) then
          res = tonumber(n)
          return res
        else
          return num
        end
      else
        return num
      end
    end
  end

  function dvaloffset(num, dvoff)
    dvoff = tonumber(dvoff)
    if dvoff ~= nil and dvoff ~= 0 then
      local s, e = string.find(num,'%-%d+.%d+')
      if s == nil then
        s, e = string.find(num,'%d+.%d+')
      end
      if s and e then
        local n = string.sub(num,s,e)
        if n and tonumber(n) then
          res = tonumber(n) + dvoff
          return string.sub(num,1,s-1) .. res .. string.sub(num,e+1)
        else
          return num
        end
      else
        local s, e = string.find(num,'%-%d+')
        if s == nil then
          s, e = string.find(num,'%d+')
        end
        if s and e then
          local n = string.sub(num,s,e)
          if n and tonumber(n) then
            res = tonumber(n) + dvoff
            return string.sub(num,1,s-1) .. res .. string.sub(num,e+1)
          else
            return num
          end
        else
          return num
        end
      end
    else
      return num
    end
  end

  function nz(val, d)
    if val == nil then return d else return val end
  end
  function zn(val, d)
    if val == '' or val == nil then return d else return val end
  end

  ------------------------------------------------------------

local function inQuart(t, b, c, d)
  t = t / d
  return c * t^4 + b
end

function outCubic(t, b, c, d)
  t = t / d - 1
  return c * ((t^3) + 1) + b
end

function outQuart(t, b, c, d)
  t = t / d - 1
  return -c * (t^4 - 1) + b
end

function outQuint(t, b, c, d)
  t = t / d - 1
  return c * ((t^5) + 1) + b
end

function inExpo(t, b, c, d)
  if t == 0 then
    return b
  else
    return c * 2^(10 * (t / d - 1)) + b - c * 0.001
  end
end

function outExpo(t, b, c, d)
  if t == d then
    return b + c
  else
    return c * 1.001 * -2^((-10 * t / d) + 1) + b
  end
end

function outCirc(t, b, c, d)
  if t < 0 then t = 0 end
  t = t - 1
  return(math.sqrt(1 - t^2))
end

  function SetColor2(c)
    local r = (c & 255)/255
    local g = (c >> 8 & 255)/255
    local b = (c >> 16 & 255)/255
    gfx.r, gfx.g, gfx.b = r, g, b
  end

  function GetColor(c)
    return gfx.r + (gfx.g << 8) + (gfx.b << 16)
  end

  function GUI_DrawCtlBitmap_Strips()

    local strip = tracks[track_select].strip
--DBG('-----------------------------------------GUI_DrawCtlBitmap_Strips')
    local stripdim = {}
    stripdim.idx = {}
    stripdim.data = {}
    stripdim.swidx = {}
    stripdim.swdata = {}
    stripdim.swidx2 = {}
    stripdim.swdata2 = {}
    stripdim.extposidx = {}
    stripdim.strip = strip
    stripdim.page = page
    stripdim.max = {w = 0, h = 0}
    stripdim.ctlfxidx = {}
    stripdim.dim = {l = math.huge, t = math.huge, r = 0, b = 0}
    
    if #strips[strip][page].graphics > 0 then
      local maxarea, maxarea_idx = {}, {}
      local checkshad = lvar.enablegfxshadows
      for i = 1, #strips[strip][page].graphics do

        local gfxx = strips[strip][page].graphics[i]
        local idx
        
        if gfxx.id ~= nil then
          if stripdim.idx[gfxx.id] then
            idx = stripdim.idx[gfxx.id]
          else
            idx = #stripdim.data + 1
            stripdim.idx[gfxx.id] = idx
            stripdim.data[idx] = {id = gfxx.id, l = surface_size.w, t = surface_size.h, r = 0, b = 0}
          end
          stripdim.data[idx].l = math.min(stripdim.data[idx].l, gfxx.x)
          stripdim.data[idx].t = math.min(stripdim.data[idx].t, gfxx.y)
          stripdim.data[idx].r = math.max(stripdim.data[idx].r, gfxx.x+gfxx.stretchw)
          stripdim.data[idx].b = math.max(stripdim.data[idx].b, gfxx.y+gfxx.stretchh)
          stripdim.data[idx].gfxpage = gfxx.gfxpage or 0
        end

        --need to check hidden flag?
        stripdim.dim.l = math.min(stripdim.dim.l, gfxx.x)
        stripdim.dim.t = math.min(stripdim.dim.t, gfxx.y)
        stripdim.dim.r = math.max(stripdim.dim.r, gfxx.x+gfxx.stretchw)
        stripdim.dim.b = math.max(stripdim.dim.b, gfxx.y+gfxx.stretchh)

        local swid = Switcher_GetTopLevelSwitcher(gfxx.switcher)
        --DBG('bitmap swid gfx'..i..'  '..tostring(swid)..'  '..tostring(gfxx.switcher))
        if swid and switchers[swid] and switchers[swid].switchmode == 1 and
           switchers[swid].extendmode == true --[[and (all == true or switchers[swid].extendid == extid)]] then
          if Switcher_CtlsHidden(swid, gfxx.grpid) == false then

            local extid = switchers[swid].extendid
            if not stripdim.extposidx[extid] then
              stripdim.extposidx[extid] = {}
            end
            if not stripdim.extposidx[extid][switchers[swid].extendpos] then
              stripdim.extposidx[extid][switchers[swid].extendpos] = swid
            end

            if not stripdim.swdata[swid] then
              stripdim.swdata[swid] = {l = lvar.maxdim, t = lvar.maxdim, r = 0, b = 0, stripidx = idx}
            end
            stripdim.swdata[swid].l = math.min(stripdim.swdata[swid].l, gfxx.x)
            stripdim.swdata[swid].t = math.min(stripdim.swdata[swid].t, gfxx.y)
            stripdim.swdata[swid].r = math.max(stripdim.swdata[swid].r, gfxx.x+gfxx.stretchw)
            stripdim.swdata[swid].b = math.max(stripdim.swdata[swid].b, gfxx.y+gfxx.stretchh)
            stripdim.swdata[swid].gfxpage = gfxx.gfxpage or 0
            stripdim.swdata[swid].stripl = math.max(math.min(stripdim.swdata[swid].stripl or lvar.maxdim, gfxx.x),0)
            stripdim.swdata[swid].stript = math.min(stripdim.swdata[swid].stript or lvar.maxdim, gfxx.y)
            stripdim.swdata[swid].stripr = math.max(stripdim.swdata[swid].stripr or 0, gfxx.x+gfxx.stretchw)
            stripdim.swdata[swid].stripb = math.max(stripdim.swdata[swid].stripb or 0, gfxx.y+gfxx.stretchh)

            if gfxx.id and not stripdim.swidx[gfxx.id] then
              stripdim.swidx[gfxx.id] = gfxx.switcher
            end

            local extid = switchers[swid].extendid

            if not stripdim.swdata2[extid] then
              stripdim.swdata2[extid] = {}
            end
            if not stripdim.swdata2[extid][swid] then
              stripdim.swdata2[extid][swid] = stripdim.swdata[swid]
            end

            if gfxx.id then
              if not stripdim.swidx2[extid] then
                stripdim.swidx2[extid] = {}
              end
              if not stripdim.swidx2[extid][gfxx.id] then
                --DBG(swid..'  '..gfxx.id)
                stripdim.swidx2[extid][gfxx.id] = stripdim.swidx[gfxx.id]
              end
            end
            
            if checkshad and gfxx.gfxtype == lvar.gfxtype.img and gfxx.hidden ~= true then
              local key = swid..'|'..gfxx.id
              local area = gfxx.stretchw * gfxx.stretchh
              if area > (maxarea[key] or 0) then
                maxarea[key] = area
                maxarea_idx[key] = i
              end
            end
            
          end
        end

      end
      for a,b in pairs(maxarea_idx) do
        --DBG(tostring(strips[strip][page].graphics[b].shadow)..'  '..b..'  '..a)
        strips[strip][page].graphics[b].shadow = true
      end
    end

    if #strips[strip][page].controls > 0 then
      for i = 1, #strips[strip][page].controls do

        local ctl = strips[strip][page].controls[i]
        local idx
        if ctl.id ~= nil then
          if stripdim.idx[ctl.id] then
            idx = stripdim.idx[ctl.id]
          else
            idx = #stripdim.data + 1
            stripdim.idx[ctl.id] = idx
            stripdim.data[idx] = {id = ctl.id, l = surface_size.w, t = surface_size.h, r = 0, b = 0}
          end

          stripdim.data[idx].l = math.min(stripdim.data[idx].l, ctl.xsc)
          stripdim.data[idx].t = math.min(stripdim.data[idx].t, ctl.ysc)
          stripdim.data[idx].r = math.max(stripdim.data[idx].r, ctl.xsc+ctl.wsc)
          stripdim.data[idx].b = math.max(stripdim.data[idx].b, ctl.ysc+ctl.hsc)
          stripdim.data[idx].gfxpage = ctl.gfxpage or 0

          --DBG(stripdim.data[idx].l..' '..stripdim.data[idx].t..' '..stripdim.data[idx].r..' '..stripdim.data[idx].b)

        end

        if ctl.ctlcat == ctlcats.fxparam then
          stripdim.ctlfxidx[(ctl.fxguid or '')..'|'..ctl.param_info.paramnum] = i
        end

        local swid = Switcher_GetTopLevelSwitcher(ctl.switcher or ctl.switcherid)
        if not ctl.switcher then
        --DBG('bitmap swid ctl'..i..'  '..tostring(swid))
        end
        if swid and switchers[swid] and switchers[swid].switchmode == 1 and
           switchers[swid].extendmode == true --[[and (all == true or switchers[swid].extendid == extid)]] then
          if swid == ctl.switcherid or Switcher_CtlsHidden(ctl.switcher, ctl.grpid) == false then
--DBG(i..'  '..#strips[strip][page].controls..'  '..switchers[swid].extendpos)

            local extid = switchers[swid].extendid
            if not stripdim.extposidx[extid] then
              stripdim.extposidx[extid] = {}
            end
            if not stripdim.extposidx[extid][switchers[swid].extendpos] then
              stripdim.extposidx[extid][switchers[swid].extendpos] = swid
            end

            if not stripdim.swdata[swid] then
              stripdim.swdata[swid] = {l = lvar.maxdim, t = lvar.maxdim, r = 0, b = 0, stripidx = idx}
            end
            stripdim.swdata[swid].l = math.min(stripdim.swdata[swid].l, ctl.xsc)
            stripdim.swdata[swid].t = math.min(stripdim.swdata[swid].t, ctl.ysc)
            stripdim.swdata[swid].r = math.max(stripdim.swdata[swid].r, ctl.xsc+ctl.wsc)
            stripdim.swdata[swid].b = math.max(stripdim.swdata[swid].b, ctl.ysc+ctl.hsc)
            stripdim.swdata[swid].gfxpage = ctl.gfxpage or 0
            if swid == ctl.switcherid then
              stripdim.swdata[swid].sl = ctl.xsc
              stripdim.swdata[swid].sr = ctl.xsc+ctl.wsc
              stripdim.swdata[swid].st = ctl.ysc
              stripdim.swdata[swid].sb = ctl.ysc+ctl.hsc
            else
              stripdim.swdata[swid].stripl = math.max(math.min(stripdim.swdata[swid].stripl or lvar.maxdim, ctl.xsc),0)
              stripdim.swdata[swid].stript = math.min(stripdim.swdata[swid].stript or lvar.maxdim, ctl.ysc)
              stripdim.swdata[swid].stripr = math.max(stripdim.swdata[swid].stripr or 0, ctl.xsc+ctl.wsc)
              stripdim.swdata[swid].stripb = math.max(stripdim.swdata[swid].stripb or 0, ctl.ysc+ctl.hsc)
            end

            if ctl.id and not stripdim.swidx[ctl.id] then
              stripdim.swidx[ctl.id] = ctl.switcher
            end

            --local extid = switchers[swid].extendid
              stripdim.swdata.extid = extid
              --DBG(extid)

            if not stripdim.swdata2[extid] then
              stripdim.swdata2[extid] = {}
            end
            if not stripdim.swdata2[extid][swid] then
              stripdim.swdata2[extid][swid] = stripdim.swdata[swid]
            end

            if ctl.id then
              if not stripdim.swidx2[extid] then
                stripdim.swidx2[extid] = {}
              end
              --DBG('dd'..ctl.id)
              if not stripdim.swidx2[extid][ctl.id] then
                --DBG(swid..'  '..ctl.id)
                stripdim.swidx2[extid][ctl.id] = stripdim.swidx[ctl.id]
              end
            end
          --else
            --DBG('hidden'..ctl.param_info.paramname)
          end
        end

        --[[if ctl.switcher and ctl.switcherid then
          local swid = ctl.switcherid
          if swid and switchers[swid].switchmode == 1 and
             switchers[swid].extendmode == true then
             DBG('tt')
            if not stripdim.swdata[swid] then
              stripdim.swdata[swid] = {l = 2048, t = 2048, r = 0, b = 0}
            end
            stripdim.swdata[swid].l = math.min(stripdim.swdata[swid].l, ctl.xsc)
            stripdim.swdata[swid].t = math.min(stripdim.swdata[swid].t, ctl.ysc)
            stripdim.swdata[swid].r = math.max(stripdim.swdata[swid].r, ctl.xsc+ctl.wsc)
            stripdim.swdata[swid].b = math.max(stripdim.swdata[swid].b, ctl.ysc+ctl.hsc)
            stripdim.swdata[swid].gfxpage = ctl.gfxpage or 0

            if ctl.id and not stripdim.swidx[ctl.id] then
              stripdim.swidx[ctl.id] = ctl.switcher
            end

            local extid = switchers[swid].extendid

            if not stripdim.swdata2[extid] then
              stripdim.swdata2[extid] = {}
            end
            if not stripdim.swdata2[extid][swid] then
              stripdim.swdata2[extid][swid] = stripdim.swdata[swid]
            end

            if ctl.id then
              if not stripdim.swidx2[extid] then
                stripdim.swidx2[extid] = {}
              end
              --DBG('dd'..ctl.id)
              if not stripdim.swidx2[extid][ctl.id] then
                stripdim.swidx2[extid][ctl.id] = stripdim.swidx[ctl.id]
              end
            end
          end
        end]]
      end
    end

    for a,b in pairs(stripdim.swdata) do
      if type(b) == 'table' then
        stripdim.max.w = math.max(stripdim.max.w, (b.r or b.sr)-(b.l or b.sl))
        stripdim.max.h = math.max(stripdim.max.h, (b.b or b.sb)-(b.t or b.st))
      end
    end
    --DBG('max w = '..stripdim.max.w)
    --DBG('max h = '..stripdim.max.h)

    lvar.stripdim = stripdim
    --[[for a, b in pairs(lvar.stripdim.swidx) do
      DBG('>> '..a..'  '..b)
    end]]

    gfx.a = 1
    --gfx.dest = ctl_bitmap
    if #stripdim.data > 0 then
      local coffset = 8388608
      for i = 1, #stripdim.data do
        local data = stripdim.data[i]

          gfx.dest = ctlbitmap_image + (data.gfxpage or 0)
        --if data.gfxpage == 0 then --change code to draw multiple bitmaps
          SetColor2(i+coffset)
          gfx.a = 1
          gfx.rect(data.l,data.t,data.r-data.l,data.b-data.t,1)
        --end
      end
    end

  end

  function GUI_InitGfxPages()
    --DBG('A'..lvar.gfxpages)
    --local t = reaper.time_precise()
    if tracks[track_select] and strips[tracks[track_select].strip] then
      local strip = tracks[track_select].strip
      lvar.gfxpages = 0
      for i = 1, #strips[strip][page].graphics do
        local ctl = strips[strip][page].graphics[i]
        lvar.gfxpages = math.max(lvar.gfxpages, (ctl.gfxpage or 0))
      end
      for i = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[i]
        lvar.gfxpages = math.max(lvar.gfxpages, (ctl.gfxpage or 0))
      end
    end
    --DBG('B'..lvar.gfxpages)
    for i = 0, lvar.gfxpagesmax do
      --gfx.setimgdim(ctlbitmap_image+i,-1,-1)
      if i <= (lvar.gfxpages or 0) then
        --gfx.setimgdim(strip_image+i,surface_size.w, surface_size.h)
        --gfx.setimgdim(bg_image+i,surface_size.w, surface_size.h)
        --gfx.setimgdim(ctlbitmap_image+i,surface_size.w, surface_size.h)
        --DBG(i..'  '..surface_size.w..'  '..surface_size.h)
        Img_SetDim(strip_image+i,surface_size.w, surface_size.h, true)
        Img_SetDim(bg_image+i,surface_size.w, surface_size.h, true)
        Img_SetDim(ctlbitmap_image+i,surface_size.w, surface_size.h)        
      end
    end
    --DBG(reaper.time_precise()-t)
  end

  function GUI_DrawCtlBitmap()

    if settings_usectlbitmap then

      --gfx.dest = ctl_bitmap

      GUI_InitGfxPages()

      if tracks[track_select] and strips[tracks[track_select].strip] then

        GUI_DrawCtlBitmap_Strips()

        local strip = tracks[track_select].strip

        if #strips[strip][page].controls > 0 then

          gfx.a = 1

          for i = 1, #strips[strip][page].controls do
            local ctl = strips[strip][page].controls[i]

            gfx.dest = ctlbitmap_image + (ctl.gfxpage or 0)
            --if (ctl.gfxpage or 0) == 0 then

              --local scale = ctl.scale
              local px = ctl.xsc
              local py = ctl.ysc
              local w = ctl.wsc
              local h = ctl.hsc

              local hidden = Switcher_CtlsHidden(ctl.switcher, ctl.grpid)

              SetColor2(i)
              if hidden == false then
                if (mode == 1 or (ctl.hidden ~= true and ctl.clickthrough ~= true)) then
                  gfx.rect(px,py,w,h,1)
                end
              end
            --end
          end

        end
      else
        lvar.stripdim = nil
      end

      if (lvar.livemode == 0 and stripgallery_view ~= 0) and (mode == 0 or (mode == 1 and submode == 2)) then

        GUI_DrawCtlBitmap2()

      elseif lvar.livemode == 1 or lvar.livemode == 2 then

        GUI_DrawCtlBitmap_Mix()

      end

      gfx.dest = 1
    end

  end


  function GUI_DrawCtlBitmap2()
    --gfx.setimgdim(ctl_bitmap2,-1,-1)
    --gfx.setimgdim(ctl_bitmap2,obj.sections[10].w, obj.sections[10].h)
    Img_SetDim(ctl_bitmap2,obj.sections[10].w, obj.sections[10].h)
    gfx.dest = ctl_bitmap2

    if stlay_data then
      local st,en = 1,1
      local px = stlay_data.xpos or 0
      while stlay_data.loc[st] and px > stlay_data.loc[st].runx_e do --+ gallery_itemgap do
        st=st+1
      end
      en = st
      while stlay_data.loc[en] and px+obj.sections[10].w > stlay_data.loc[en].runx_s do
        en=en+1
      end
      en=en-1
      local x = 0

      for i = st,en do
        local t = math.floor((obj.sections[10].h/2) - (stlay_data.loc[i].h/2))
        if i == st then
          local sx = (px-stlay_data.loc[i].runx_s)
          local sw = stlay_data.loc[i].w - sx
          if px < 0 then --eliminate width error
            sw = sw - 1
          end
          local dx = sw-stlay_data.reordered[i].w
          gfx.blit(ctl_bitmap,1,0,
                    stlay_data.loc[i].l,
                    stlay_data.loc[i].t,
                    stlay_data.loc[i].w,
                    stlay_data.loc[i].h,
                    math.floor(x) + dx,
                    math.floor(t))
          x=x+sw + gallery_itemgap
        elseif i == en then
          local sx = 0
          local sw = ((px+obj.sections[10].w)-stlay_data.loc[i].runx_s)
          gfx.blit(ctl_bitmap,1,0,
                    stlay_data.loc[i].l,
                    stlay_data.loc[i].t,
                    stlay_data.loc[i].w,
                    stlay_data.loc[i].h,
                    math.floor(x),
                    math.floor(t))
        else
          gfx.blit(ctl_bitmap,1,0,
                    stlay_data.loc[i].l,
                    stlay_data.loc[i].t,
                    stlay_data.loc[i].w,
                    stlay_data.loc[i].h,
                    math.floor(x),
                    math.floor(t))
          x=x+stlay_data.loc[i].w + gallery_itemgap
        end
      end
    end

    gfx.dest = 1
  end

  function GUI_DrawCtlBitmap_Mix()

    --if not obj then return end

    gfx.a = 1

    --Img_SetDim(ctl_bitmap2,-1,-1)

    local strip = tracks[track_select].strip
    if obj and lvar.stripdim and strips[strip] then
      local rect10 = obj.sections[10000]

      --gfx.setimgdim(ctl_bitmap2,rect10.w, rect10.h)
      Img_SetDim(ctl_bitmap2, rect10.w, rect10.h)
      
      gfx.dest = ctl_bitmap2

      local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      local extid = swdata.extid
      if extid then

        local coffset = 8388608

        if (not lvar.showpoponly or insertstrip) and (not lvar.showpop or not lvar.mm_disablenonpoppedctls or not strips[strip][page].pop or #strips[strip][page].pop == 0) then

          if (lvar.mm_fadepop > 0 or not lvar.showpop) or not strips[strip][page].pop or #strips[strip][page].pop == 0 then

            lvar.poponly = false

            if lvar.mixmodedir == 0 then
              local pos = surface_offset.mixy or 0 --0
              local padgap = lvar.dm_pady --lvar.mmpadgap
              local runpos = 0
              local gap = lvar.mmgap
              local winh = rect10.h

              local popidx = strips[strip][page].popidx or {}
              lvar.mixupdate = nil

              for p = 1, #posidx[extid] do
                local swid = posidx[extid][p]

                if switchers[swid] and swdata[swid] then
                  --padgap = switchers[swid].pady or padgap

                  local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
                  local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
                  local sh = swdata[swid].sb-swdata[swid].st
                  local ssh = h+sh+gap
                
                  local ty = - pos*lvar.zoom + runpos*lvar.zoom

                  if ty+ssh*lvar.zoom >= 0 then
                    if ty <= winh then
                      if lvar.mixupdate == nil then
                        lvar.mixupdate = {runpos = runpos, p = p}
                      end
                      if lvar.showpop ~= true or not popidx[swid] then
                        local x = swdata[swid].stripl or 0
                        local y = swdata[swid].stript or 0
                        local sx = swdata[swid].sl
                        local sy = swdata[swid].st
                        local sw = swdata[swid].sr-swdata[swid].sl
                        local gfxpage = swdata[swid].gfxpage

                        local tx, stx
                        if lvar.mixmodealign == 0 then
                          tx = math.floor(rect10.w/2) - math.floor(w/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                          stx = math.floor(rect10.w/2) - math.floor(sw/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                        else
                          local mxw = lvar.stripdim.max.w
                          tx = math.floor(rect10.w/2) - math.floor(mxw/2)*lvar.zoom --+lvar.mmov_offs --+lvar.mmov_pad
                          if lvar.mmov_show == true then
                            tx = math.max(tx+lvar.mmov_offs, lvar.mmov_vsize+lvar.mmov_pad+6)
                          else
                            tx = math.max(tx, 6)
                          end
                          stx = tx --math.floor(rect10.w/2) - math.floor(sw/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                        end
                        --gfx.blit(ctlbitmap_image + gfxpage, 1, 0, x, y, w, h, tx, ty)
                        if swdata[swid].stripidx then
                          SetColor2(swdata[swid].stripidx+coffset)
                          gfx.rect(0,ty,lvar.maxdim,h*lvar.zoom+(sh+gap)*lvar.zoom,1)
                        end

                        if w > 0 then
                          gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, x, y, w, h, tx, ty+(sh+gap)*lvar.zoom)
                        end
                        gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, stx, ty)
                      end
                    else
                      break
                    end
                  end
                  runpos = runpos + padgap + ssh --+ sh
                end
              end

            else

              local pos = surface_offset.mixx or 0 --0
              local padgap = lvar.dm_padx
              local runpos = 0
              local gap = lvar.mmgap
              local winw = rect10.w

              local popidx = strips[strip][page].popidx or {}
              lvar.mixupdate = nil

              for p = 1, #posidx[extid] do
                local swid = posidx[extid][p]

                if switchers[swid] and swdata[swid] then
                  --padgap = switchers[swid].padx or padgap
  
                  local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
                  local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
                  local sw = (swdata[swid].sr or 0)-(swdata[swid].sl or 0)
                  local sh = (swdata[swid].sb or 0)-(swdata[swid].st or 0)
                  local ssw = w --math.max(w,sw)
                  if ssw <= 0 or lvar.mixmodealign ~= 1 then
                    ssw = math.max(w,sw)
                  end
  
                  local tx = - pos*lvar.zoom + runpos*lvar.zoom
  
                  if tx+ssw*lvar.zoom >= 0 then
                    if tx <= winw then
                      if lvar.mixupdate == nil then
                        lvar.mixupdate = {runpos = runpos, p = p}
                      end
                      if lvar.showpop ~= true or not popidx[swid] then
                        local x = swdata[swid].stripl or 0
                        local y = swdata[swid].stript or 0
                        local sx = swdata[swid].sl or 0
                        local sy = swdata[swid].st or 0
                        local sw = (swdata[swid].sr or 0)-(swdata[swid].sl or 0)
                        local gfxpage = swdata[swid].gfxpage
  
                        local ty
                        if lvar.mixmodealign == 0 then
                          ty = math.floor(rect10.h/2) - math.floor((h+sh)/2)*lvar.zoom +lvar.mmov_offs
                        elseif lvar.mixmodealign == 1 then
                          local mxh = lvar.stripdim.max.h
                          ty = math.floor(rect10.h/2) - math.floor((mxh)/2)*lvar.zoom --+lvar.mmov_offs
                          if lvar.mmov_show == true then
                            ty = math.max(ty+lvar.mmov_offs, lvar.mmov_vsize+lvar.mmov_pad+6)
                          else
                            ty = math.max(ty, 6)
                          end
                        end
                        local stx = tx + math.floor(--[[math.max(w, sw)]]w/2)*lvar.zoom - math.floor(sw/2)*lvar.zoom
                        --gfx.blit(ctlbitmap_image + gfxpage, 1, 0, x, y, w, h, tx, ty)
  
                        if swdata[swid].stripidx then
                          SetColor2(swdata[swid].stripidx+coffset)
                          gfx.rect(tx,0,w*lvar.zoom,lvar.maxdim,1)
                        end
                        if w > 0 then
                          gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, x, y, w, h, tx, ty+(sh+gap)*lvar.zoom)
                        end
                        gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, stx, ty)
                      end
                    else
                      break
                    end
                  end
                  runpos = runpos + padgap + ssw --+ sh
                end
              end

            end
          else
            lvar.poponly = true
          end
        else
          lvar.poponly = true

        end
        --DBG(lvar.poponly)

        if lvar.showpop == true and strips[strip][page].pop then
          
          if lvar.popout_autoarrange then
            --DBG('b')
            PopOut_AutoArrange(true)
          else
            PopOut_GetBounds()
          end
          
          local pop = strips[strip][page].pop
          gfx.a = 1
          local pcnt = #pop
          if lvar.dm_singlepopup then
            pcnt = 1
          end

          local xoff, yoff = 0, 0
          --if lvar.popout_autoarrange then
            xoff = lvar.pop_xoff or 0
            yoff = lvar.pop_yoff or 0
          --end
          
          for i = 1, pcnt do

            if pop[i] then
              local swid = pop[i].swid
              if swdata[swid] then
                local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
                local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
                local sw = (swdata[swid].sr or 0)-(swdata[swid].sl or 0)
                local sh = (swdata[swid].sb or 0)-(swdata[swid].st or 0)
                local x = swdata[swid].stripl or 0
                local y = swdata[swid].stript or 0
                local sx = swdata[swid].sl or 0
                local sy = swdata[swid].st or 0
                local gfxpage = swdata[swid].gfxpage

                if lvar.popout_autoarrange and lvar.popout_autoarrange_hideswitchers then
                  sh = 0
                end

                local stx = pop[i].x + math.floor(w/2 - sw/2)*lvar.zoom
                
                if w > 0 then
                  gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, x, y, w, h, pop[i].x + xoff, pop[i].y + yoff +(sh+lvar.mmgap)*lvar.zoom)
                end
                if not lvar.popout_autoarrange or not lvar.popout_autoarrange_hideswitchers then
                  gfx.blit(ctlbitmap_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, stx + xoff, pop[i].y + yoff)
                end
              end
            end
          end
        end

      end
    end

  end

  function MixMode_FindClosestRow(h)

    if lvar.popswipe then return end
    
    --Get current row
    local strip = tracks[track_select].strip
    local poprows = strips[strip][page].poprows
    if poprows and poprows.type == 1 then
    
      local equals
      local offy = 0
      if lvar.mixmodedir == 1 then
        if lvar.mmov_show then
          offy = lvar.mmov_vsize+lvar.mmov_pad*2
        end
      end
    
      local pad = 20
      local pad2 = 20
      if dir == 1 then
        pad2=-20
      end
      
      local hh = (h-offy)/2
      local pop_yoff = lvar.pop_yoff - hh
      local sr = 1
      for r = 1, #poprows do
      
        if -pop_yoff > poprows[r].ypos and -pop_yoff < poprows[r].ypos + poprows[r].rowh then
          sr = math.max(r,1)
          break
        end
      
      end
      
      --[[local hh = (obj.sections[10].h-offy)/2
      local pop_yoff = lvar.pop_yoff + hh
      local sr = 1
      for r = 1, #poprows do
      
        if (pop_yoff)-pad2 > -poprows[r].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[r].rowh)/2)) +offy then
          sr = math.max(r,1)
          break
        end
      
      end]]
      
      return sr
    end
    
  end

  function MixMode_Swipe_Pop(dir, instant, row)
    
    if lvar.popswipe then return end
    
    --Get current row
    local strip = tracks[track_select].strip
    if strips[strip] then
      local poprows = strips[strip][page].poprows
      if poprows and poprows.type == 1 then
  
        local equals
        local offy = 0
        if lvar.mixmodedir == 1 then
          if lvar.mmov_show then
            offy = lvar.mmov_vsize+lvar.mmov_pad*2
          end
        end
  
        --DBG(dir..'  '..(lvar.prsr or -1))
        if not row and dir == 0 and (lvar.prsr or -1) >= #poprows then return end
  
        local pad = 20
        if lvar.popout_autoarrange and lvar.popout_autoarrange_hideswitchers then
          pad = 0
        end
        local pad2 = 20
        if dir == 1 then
          pad2=-20
        end
        
        local sr = 1
        if not row then
          for r = 1, #poprows do
          
            if (lvar.pop_yoff)-pad2 > -poprows[r].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[r].rowh)/2)) +offy then
              sr = math.max(r-1,1)
              break
            end
          
          end
        else
          sr = row
        end
  
        --instant = true
        if instant then
          if dir == 0 then --down
            sr = math.min(sr+1, #poprows)
            if poprows[sr] then
              lvar.prsr = sr
              --local setposy = -poprows[sr].ypos+offy+pad
              local setposy = -poprows[sr].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[sr].rowh)/2)) +offy
              Pop_SetPos(lvar.pop_xoff, setposy)
            end
          else
            if poprows[sr] then
              lvar.prsr = sr
              --local setposy = -poprows[sr].ypos+offy+pad
              local setposy = -poprows[sr].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[sr].rowh)/2)) +offy
              Pop_SetPos(lvar.pop_xoff, setposy)
            end
          end
        else
          local setposy 
          if dir == 0 then --down
            sr = math.min(sr+1, #poprows)
            if poprows[sr] then
              lvar.prsr = sr
              --setposy = -poprows[sr].ypos+offy+pad 
              setposy = -poprows[sr].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[sr].rowh)/2)) +offy
            end        
          else
            if poprows[sr] then
              lvar.prsr = sr
              --setposy = -poprows[sr].ypos+offy+pad
              setposy = -poprows[sr].ypos+math.floor(pad/2) +(math.floor(((obj.sections[10].h-offy) - poprows[sr].rowh)/2)) +offy
            end
          end
          lvar.popswipe = {st = reaper.time_precise(), et = reaper.time_precise()+0.1, sp = lvar.pop_yoff, ep = setposy}
        end
        
      end
    end
  end
  
  function MixMode_Swiping_Pop()
  
    local t = math.min((reaper.time_precise()-lvar.popswipe.st)/(lvar.popswipe.et-lvar.popswipe.st),1)
    if t < 1 then
      lvar.pop_yoff = lvar.popswipe.sp + (lvar.popswipe.ep-lvar.popswipe.sp)*t
      Pop_SetPos(lvar.pop_xoff, lvar.pop_yoff)
    else
      t = 1
      lvar.pop_yoff = lvar.popswipe.ep
      Pop_SetPos(lvar.pop_xoff, lvar.pop_yoff)
      lvar.popswipe = nil
      SetCtlBitmapRedraw_Mix(lvar.popswipe_redrawforce)
      if lvar.popswipe_redrawforce then
        --[[local d,wx,wy,ww,wh = gfx.dock(-1,-1,-1,-1,-1)
        reaper.JS_Mouse_SetPosition(mouse.smx, wy+math.floor(obj.sections[10].y+obj.sections[10].h/2))]]
        lvar.popswipe_redrawforce = nil
      end
    end
  end
  
  function MixMode_Swipe(srcpos, dstpos, instant)

    if lvar.livemode >= 1 and lvar.stripdim and (not surface_offset.targetmixy and not surface_offset.targetmixx) then

      lvar.mixupdate = nil

      local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      local extid = swdata.extid
      if extid then

        if lvar.mixmodedir == 0 then
          local padgap = lvar.dm_pady
          local gap = lvar.mmgap
          local runpos = 0
          local winh = obj.sections[10000].h

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].pady or padgap

            local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
            local sh = swdata[swid].sb-swdata[swid].st

            if p < dstpos then
              runpos = runpos + padgap + h + sh + gap
            else
              --lvar.centrepos = dstpos
              if instant then
                surface_offset.mixy = runpos - (math.floor(winh/2 - ((h+sh)/2)*lvar.zoom))/lvar.zoom
              else
                surface_offset.dstpos = dstpos
                surface_offset.startmixy = surface_offset.mixy or 0
                surface_offset.targetmixy = runpos - (math.floor(winh/2 - ((h+sh)/2)*lvar.zoom))/lvar.zoom
                surface_offset.st = reaper.time_precise()
                surface_offset.et = surface_offset.st + 0.1
              end
              break
            end

          end
        else
          local padgap = lvar.dm_padx
          local runpos = 0
          local winw = obj.sections[10000].w

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].padx or padgap

            local w = ((swdata[swid].stripr or 0) - (swdata[swid].stripl or 0))
            local sw = (swdata[swid].sr-swdata[swid].sl)
            if p < dstpos then
              local addw = w
              if addw <= 0 or lvar.mixmodealign ~= 1 then
                addw = math.max(w,sw)
              end
              runpos = runpos + (padgap + addw --[[math.max(w,sw)]])
            else
              --lvar.centrepos = dstpos
              if instant then
                surface_offset.mixx = (runpos - (math.floor((winw/2) - ((math.max(w,sw))/2)*lvar.zoom))/lvar.zoom )
              else
                surface_offset.dstpos = dstpos
                surface_offset.startmixx = (surface_offset.mixx or 0)
                surface_offset.targetmixx = (runpos - (math.floor((winw/2) - ((math.max(w,sw))/2)*lvar.zoom))/lvar.zoom )
                surface_offset.st = reaper.time_precise()
                surface_offset.et = surface_offset.st + 0.1
              end
              break
            end

          end

        end
        lupd.update_surface = true
        --GUI_DrawCtlBitmap_Mix()
      end
    end

  end

  function MixMode_GetLength()

    if lvar.livemode >= 1 and lvar.stripdim --[[and (not surface_offset.targetmixy and not surface_offset.targetmixx)]] then

      lvar.mixupdate = nil

      local runpos = 0
      local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      local extid = swdata.extid
      if extid then

        if lvar.mixmodedir == 0 then
          local padgap = lvar.dm_pady
          local gap = lvar.mmgap
          local winh = obj.sections[10000].h

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].pady or padgap
            if swdata[swid] then
              local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
              local sh = swdata[swid].sb-swdata[swid].st
              runpos = runpos + padgap + h + sh + gap
            end
            
          end
        else
          local padgap = lvar.dm_padx
          local winw = obj.sections[10000].w

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].padx or padgap
            if swdata[swid] then
              local w = ((swdata[swid].stripr or 0) - (swdata[swid].stripl or 0))
              local sw = (swdata[swid].sr-swdata[swid].sl)
              local addw = w
              if addw <= 0 or lvar.mixmodealign ~= 1 then
                addw = math.max(w,sw)
              end
              runpos = runpos + (padgap + addw --[[math.max(w,sw)]])
            end
          end

        end
        lupd.update_surface = true
        --GUI_DrawCtlBitmap_Mix()
      end

      return runpos - lvar.mmgap
    end

    return 0

  end

  function MixMode_Swiping()

    local t = math.min((reaper.time_precise()-surface_offset.st)/(surface_offset.et-surface_offset.st),1)

    if lvar.mixmodedir == 0 then
      local mixy = surface_offset.startmixy + ((surface_offset.targetmixy - surface_offset.startmixy)*outSine(t))
      surface_offset.mixy = math.floor(mixy)
      if lvar.mmov_show == true then
        if math.floor(surface_offset.mixy*lvar.mmov_scale) < lvar.mmov_pos then
          lvar.mmov_pos = math.max(math.floor((surface_offset.mixy*lvar.mmov_scale)),0)
        elseif math.floor(surface_offset.mixy*lvar.mmov_scale) > obj.sections[10000].h + lvar.mmov_pos - math.floor(obj.sections[10000].h*lvar.mmov_scale) then
          lvar.mmov_pos = math.min(math.floor(surface_offset.mixy*lvar.mmov_scale) - (obj.sections[10000].h - math.floor(obj.sections[10000].h*lvar.mmov_scale)),lvar.mmov_max-obj.sections[10000].h)
        end
      end
    else
      local mixx = surface_offset.startmixx + ((surface_offset.targetmixx - surface_offset.startmixx)*outSine(t))
      surface_offset.mixx = math.floor(mixx)
      if lvar.mmov_show == true then
        if math.floor(surface_offset.mixx*lvar.mmov_scale) < lvar.mmov_pos then
          lvar.mmov_pos = math.max(math.floor((surface_offset.mixx*lvar.mmov_scale)),0)
        elseif math.floor(surface_offset.mixx*lvar.mmov_scale) > obj.sections[10000].w + lvar.mmov_pos - math.floor(obj.sections[10000].w*lvar.mmov_scale) then
          lvar.mmov_pos = math.min(math.floor(surface_offset.mixx*lvar.mmov_scale) - (obj.sections[10000].w - math.floor(obj.sections[10000].w*lvar.mmov_scale)),lvar.mmov_max-obj.sections[10000].w)
        end
      end
    end
    lupd.update_surface = true

    if t == 1 then
      lvar.centrepos = surface_offset.dstpos
      surface_offset.targetmixy = nil
      surface_offset.targetmixx = nil
      SetCtlBitmapRedraw_Mix()
      --GUI_DrawCtlBitmap_Mix()
    end

  end

  function ShowPop(v, skipbitmapupdate, nofade)
    if not lvar.showpoponly or insertstrip then
      local a
      if v == true then
        a = 0
      end
      if lvar.showpop ~= v then
        lvar.showpop = v
        if not nofade then
          lvar.popalpha = {alpha = a or 1, showpop = v, st = reaper.time_precise(), et = reaper.time_precise()+lvar.anitime}
        end
      end
      if skipbitmapupdate ~= true then
        GUI_DrawCtlBitmap_Mix()
      end
    else
      lvar.showpop = true
      --if not v then
      --  PopOut_DeleteAll()
      --end
      GUI_DrawCtlBitmap_Mix()
      --maybe remove all open popup windows?

    end
    local strip = tracks[track_select].strip
    strips[strip][page].showpop = lvar.showpop

    lupd.update_surface = true
  end

  function GUI_DrawMixMode(obj, gui)

    --DBG(lvar.stripdim.swdata)
    local rect10 = obj.sections[10000]

    gfx.a = 1
    if lvar.bgloaded > 0 then
      if lvar.bgcentred then
        local w,h = gfx.getimgdim(978)
        lvar.bgoffx = math.floor(rect10.w/2 - w/2) + (lvar.bg_coffx or 0)
        lvar.bgoffy = math.floor(rect10.h/2 - h/2) + (lvar.bg_coffy or 0)
      else
        lvar.bgoffx = 0 + (lvar.bg_coffx or 0) -- (surface_offset.mixx/50)
        lvar.bgoffy = 0 + (lvar.bg_coffy or 0)
      end
      gfx.blit(lvar.bgloaded,1,0,-lvar.bgoffx,-lvar.bgoffy,rect10.w,rect10.h,rect10.x,rect10.y)
    else
      if lvar.bgmatchestrackcolour > 0 then
        local col = 0
        if lvar.livemode == 2 then
          local track = GetTrack(lvar.dynamicmode_trn)
          if track then
            col = reaper.GetMediaTrackInfo_Value(track, 'I_CUSTOMCOLOR')
          end
        else
          col = reaper.GetMediaTrackInfo_Value(GetTrack(track_select), 'I_CUSTOMCOLOR')
        end
        if (col & 0x1000000 == 0x1000000) then
          local r,g,b = reaper.ColorFromNative(col)
          local m = 1
          if lvar.bgmatchestrackcolour > 1 then
            m = 1/lvar.bgmatchestrackcolour
          end
          f_Get_SSV(tostring(math.floor(r*m))..' '..tostring(math.floor(g*m))..' '..tostring(math.floor(b*m)))
        else
          f_Get_SSV(backcol)
        end
        --DBG(r..'  '..g..'  '..b)
        --f_Get_SSV(tostring(r)..' '..tostring(g)..' '..tostring(b))
      else
        f_Get_SSV(backcol)
      end
      --f_Get_SSV(backcol)
      gfx.rect(rect10.x,
               rect10.y,
               rect10.w,
               rect10.h,
               1)
    end

    lvar.centrepos = -1

    local strip = tracks[track_select].strip
    if lvar.stripdim and strips[strip] then

      local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      local extid = swdata.extid
      if extid then

        if lvar.showpoponly and not insertstrip then
        else
          if lvar.mixmodedir == 0 then
            local pos = surface_offset.mixy or 0 --0

            local padgap = lvar.dm_pady
            local gap = lvar.mmgap
            local runpos = 0
            local pst = 1
            local pst_start = 1
            --if lvar.mixupdate then
              --runpos = lvar.mixupdate.runpos
              --pst = lvar.mixupdate.p
              --pst_start = lvar.mixupdate.p
            --end
            local winh = rect10.h

            local spos = {}
            local centrepos = -1

            local popidx = strips[strip][page].popidx or {}
            local pop = strips[strip][page].pop

            --local oob = false

            local offx = 0
            if lvar.mmov_show then
              offx = lvar.mmov_vsize+lvar.mmov_pad*2
            end

            for p = pst, #posidx[extid] do
              local swid = posidx[extid][p]

              --padgap = switchers[swid].pady or padgap

              local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
              local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
              local sw = swdata[swid].sr-swdata[swid].sl
              local sh = (swdata[swid].sb-swdata[swid].st)

              local ssh = (h+sh+gap)
              local ty = rect10.y - pos*lvar.zoom + runpos*lvar.zoom

              --if ty+ssh*lvar.zoom >= obj.sections[10].y then
                --if ty <= rect10.y+winh then

                  local x = swdata[swid].stripl or 0
                  local y = swdata[swid].stript or 0

                  local sx = swdata[swid].sl
                  local sy = swdata[swid].st
                  local gfxpage = swdata[swid].gfxpage

                  local tx, stx
                  if lvar.mixmodealign == 0 then
                    tx = rect10.x + math.floor(rect10.w/2) - math.floor(w/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                    stx = rect10.x + math.floor(rect10.w/2) - math.floor(sw/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                  else
                    local mxw = lvar.stripdim.max.w
                    tx = rect10.x + math.floor(rect10.w/2) - math.floor(mxw/2)*lvar.zoom --+lvar.mmov_offs --+lvar.mmov_pad
                    if lvar.mmov_show == true then
                      tx = math.max(tx+lvar.mmov_offs, rect10.x+lvar.mmov_vsize+lvar.mmov_pad+6)
                    else
                      tx = math.max(tx, rect10.x+6)
                    end
                    stx = tx --math.floor(rect10.w/2) - math.floor(sw/2)*lvar.zoom +lvar.mmov_offs --+lvar.mmov_pad
                  end

                  local xx = tx
                  local yy = ty+(sh+gap)*lvar.zoom
                  local cy = ty
                  if w > 0 then
                    w = w + lvar.shadowmax
                    h = h + lvar.shadowmax
                    xx,yy,w,h,x,y = CropToRect2(xx,yy,w,h,rect10.x+offx,rect10.y,rect10.x+rect10.w,rect10.y+rect10.h, x, y, lvar.zoom)                      
                  end
                  stx,ty,sw,sh,sx,sy = CropToRect2(stx,ty,sw,sh,rect10.x+offx,rect10.y,rect10.x+rect10.w,rect10.y+rect10.h, sx, sy, lvar.zoom)                  


                  if cy+ssh*lvar.zoom >= rect10.y and cy <= rect10.y+winh then
                  --if p >= pst_start and not oob then
                    if lvar.popalpha then
                      if popidx and popidx[swid] then
                        gfx.a = 1-(lvar.popalpha.alpha*(1-math.min(0.1,lvar.mm_fadepop)))
                      elseif pop and #pop > 0 then
                        gfx.a = 1-(lvar.popalpha.alpha*(1-lvar.mm_fadepop))
                      end
                    else
                      gfx.a = 1
                      if lvar.showpop == true then
                        if popidx[swid] then
                          gfx.a = math.min(0.1,lvar.mm_fadepop)
                        elseif pop and #pop > 0 then
                          gfx.a = lvar.mm_fadepop
                        end
                      end
                    end
  
                    if switchers[swid].dragging then
                      gfx.a = 0.1
                    end
  
                    --[[if w > 0 then
                      xx, yy, w, h, x, y = CropToRect2(xx, yy, w+lvar.shadowmax,h+lvar.shadowmax,
                                                       rect10.x,rect10.y,rect10.x+rect10.w,rect10.y+rect10.h,
                                                       x, y, lvar.zoom)
                    end]]

                    --if not switchers[swid].dragging then
                      if w > 0 then
                        --xx,yy,w,h,x,y = CropToRect2(xx,yy,w,h,rect10.x+offx,rect10.y,rect10.x+rect10.w,rect10.y+rect10.h, x, y, lvar.zoom)
                        --gfx.blit(strip_image + gfxpage, lvar.zoom, 0, x, y, w+lvar.shadowmax, h+lvar.shadowmax, xx, yy)
                        gfx.blit(strip_image + gfxpage, lvar.zoom, 0, x, y, w, h, xx, yy)
                      end
  
                      --stx,ty,sw,sh,sx,sy = CropToRect2(stx,ty,sw,sh,rect10.x+offx,rect10.y,rect10.x+rect10.w,rect10.y+rect10.h, sx, sy, lvar.zoom)
                      if not popout_autoarrange or not popout_autoarrange_hideswitchers then
                        gfx.blit(strip_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, stx, ty)
                      end
                    --end
                  end
                  
                  spos[swid] = {x = tx, y = cy, w = w, h = ssh, sw = sw, sh = sh, sx = stx, sy = ty, gap = padgap, rp = runpos}

                  if ty <= rect10.y + math.floor(winh/2) then
                    centrepos = p
                  end
                --else
                --  oob = true
                  --break
                --end
              --end
              --DBG('ssh'..ssh)
              runpos = runpos + padgap + ssh --+ h

            end
            lvar.spos = spos
            lvar.centrepos = centrepos

          else
            local pos = surface_offset.mixx or 0 --0
            --DBG(pos)

            local padgap = lvar.dm_padx
            local gap = lvar.mmgap
            local runpos = 0
            local pst = 1
            --local pst_start = 1
            --if lvar.mixupdate then
              --runpos = lvar.mixupdate.runpos
              --pst = lvar.mixupdate.p
              --pst_start = lvar.mixupdate.p
            --end
            local winw = rect10.w

            local spos = {}
            local centrepos = -1

            local popidx = strips[strip][page].popidx or {}
            local pop = strips[strip][page].pop

            --local oob = false

            for p = pst, #posidx[extid] do
              local swid = posidx[extid][p]

              --padgap = switchers[swid].padx or padgap

              local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
              local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
              local sw = swdata[swid].sr-swdata[swid].sl
              local sh = swdata[swid].sb-swdata[swid].st

              local ssw = w --math.max(w,sw)
              if ssw <= 0 or lvar.mixmodealign ~= 1 then
                ssw = math.max(w,sw)
              end
              local tx = rect10.x - pos*lvar.zoom + runpos*lvar.zoom

              --if tx+ssw*lvar.zoom >= rect10.x then
                --if tx <= rect10.x+winw then

                  local x = swdata[swid].stripl or 0
                  local y = swdata[swid].stript or 0

                  local sx = swdata[swid].sl
                  local sy = swdata[swid].st
                  local gfxpage = swdata[swid].gfxpage

                  --local ty = rect10.y + math.floor(rect10.h/2) - math.floor((h+sh)/2)*lvar.zoom +lvar.mmov_offs
                  local ty
                  if lvar.mixmodealign == 0 then
                    ty = rect10.y + math.floor(rect10.h/2) - math.floor((h+sh)/2)*lvar.zoom +lvar.mmov_offs
                  elseif lvar.mixmodealign == 1 then
                    local mxh = lvar.stripdim.max.h

                    ty = rect10.y + math.floor(rect10.h/2) - math.floor((mxh)/2)*lvar.zoom --+lvar.mmov_offs
                    if lvar.mmov_show == true then
                      --ty = math.max(ty+math.floor((lvar.mmov_vsize+lvar.mmov_pad)/2), rect10.y+lvar.mmov_vsize+lvar.mmov_pad+6)
                      ty = math.max(ty+lvar.mmov_offs, rect10.y+lvar.mmov_vsize+lvar.mmov_pad+6)
                    else
                      ty = math.max(ty, rect10.y+6)
                    end
                  end
                  local stx = tx + math.floor(w--[[math.max(w, sw)]]/2)*lvar.zoom - math.floor(sw/2)*lvar.zoom
                  
                  if tx+ssw*lvar.zoom >= rect10.x and tx <= rect10.x+winw then
                    --if p >= pst_start and not oob then
                      if lvar.popalpha then
                        if popidx and popidx[swid] then
                          gfx.a = 1-(lvar.popalpha.alpha*(1-math.min(0.1,lvar.mm_fadepop)))
                        elseif pop and #pop > 0 then
                          gfx.a = 1-(lvar.popalpha.alpha*(1-lvar.mm_fadepop))
                        end
                      else
                        gfx.a = 1
                        if lvar.showpop == true then
                          if popidx[swid] then
                            gfx.a = math.min(0.1,lvar.mm_fadepop)
                          elseif pop and #pop > 0 then
                            gfx.a = lvar.mm_fadepop
                          end
                        end
                      end
    
                      if switchers[swid].dragging then
                        gfx.a = 0.1
                      end

                      --if not switchers[swid].dragging then
                        if w > 0 then
                          gfx.blit(strip_image + gfxpage, lvar.zoom, 0, x, y, w+lvar.shadowmax, h+lvar.shadowmax, tx, ty+(sh+gap)*lvar.zoom)
                        end
                        if not popout_autoarrange or not popout_autoarrange_hideswitchers then
                          gfx.blit(strip_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, stx, ty)
                        end
                      --end
                    --end
                  end
                  
                  --DBG('spos '..swid)
                  spos[swid] = {x = tx, y = ty, w = ssw, h = h, sw = sw, sh = sh, sx = stx, sy = ty, gap = padgap, rp = runpos}
                  if tx <= rect10.x + math.floor(winw/2) then
                    centrepos = p
                  end
                --else
                  --break
                --end
              --end
              --DBG('ssh'..ssh)
              runpos = runpos + padgap + ssw --+ h

            end
            lvar.spos = spos
            lvar.centrepos = centrepos
            
            --DBG('Updating mmode '..pos..'  '..runpos)
          end
        end

        if lvar.mmov_show == true then
          if lupd.update_gfx or lupd.update_mmov or not lvar.mmov_scale then
            GUI_DrawMMOV(obj, gui)
          end
          --GUI_BlitMMOV(obj, gui)
          lvar.blitmmov = true
        end

      else
        lvar.blitmmov = true
        lvar.mmov_rows = nil
      end
    end
  end

  function GUI_DrawMixModePopUp(obj, gui)

    local strip = tracks[track_select].strip
    if lvar.stripdim and strips[strip] then

      local swdata = lvar.stripdim.swdata
      if (lvar.showpop == true or lvar.popalpha) and strips[strip][page].pop then

        local blittbl = lvar.blittbl

        local rect10 = obj.sections[10000]

        local gap = lvar.mmgap
        local pop = strips[strip][page].pop
        local popidx = strips[strip][page].popidx

        if lvar.popalpha then
          gfx.a = lvar.popalpha.alpha
        else
          gfx.a = 1
        end
        local pcnt = #pop
        if lvar.dm_singlepopup then
          pcnt = 1
        end
        for i = 1, pcnt do

          if pop[i] then
            local swid = pop[i].swid
            if swdata[swid] then

              local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
              local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
              local sw = swdata[swid].sr-swdata[swid].sl
              local sh = swdata[swid].sb-swdata[swid].st
              local x = (swdata[swid].stripl or 0)
              local y = (swdata[swid].stript or 0)
              local sx = swdata[swid].sl
              local sy = swdata[swid].st
              local gfxpage = swdata[swid].gfxpage

              if lvar.popout_autoarrange and lvar.popout_autoarrange_hideswitchers then
                sh = 0
                gap = 0
              end
              
              local stx = pop[i].x + math.floor(w/2 - sw/2)*lvar.zoom
              
              local ow, oh = w, h
              if lvar.enablegfxshadows then
                w = w + lvar.shadowmax
                h = h + lvar.shadowmax
              end

              local o10x = rect10.x
              local o10y = rect10.y
              local o10r = rect10.x + rect10.w
              local o10b = rect10.y + rect10.h -1

              if lvar.mmov_show then
                if lvar.mixmodedir == 0 then
                  o10x = o10x + lvar.mmov_vsize+lvar.mmov_pad*2 + 1
                else
                  o10y = o10y + lvar.mmov_vsize+lvar.mmov_pad*2 + 1
                end
              end

              local xoff, yoff = 0, 0
              --if lvar.popout_autoarrange then
                xoff = lvar.pop_xoff or 0
                yoff = lvar.pop_yoff or 0
              --end

              local xx = rect10.x + pop[i].x + xoff
              local yy = rect10.y + pop[i].y+(sh+gap)*lvar.zoom + yoff
              
              local _,_,ow,oh,_,_ = CropToRect2(xx,yy,ow,oh,o10x,o10y,o10r,o10b, x, y, lvar.zoom)
              local xx,yy,w,h,x,y = CropToRect2(xx,yy,w,h,o10x,o10y,o10r,o10b, x, y, lvar.zoom)
              local sxx = rect10.x + stx + xoff
              local syy = rect10.y + pop[i].y + yoff
              local sxx,syy,sw,sh,sx,sy = CropToRect2(sxx,syy,sw,sh,o10x,o10y,o10r,o10b, sx, sy, lvar.zoom)

              local alp
              if lvar.dragswitcher and lvar.showpop and lvar.popout_autoarrange then
                if popidx[lvar.dragswitcher.selected] == i then
                  alp = 0.3
                end
              end

              if w > 0 then
                --gfx.blit(strip_image + gfxpage, lvar.zoom, 0, x, y, w, h, rect10.x + pop[i].x, rect10.y + pop[i].y+(sh+gap)*lvar.zoom)
                blittbl[lvar.blittbl_cnt] = {strip_image + gfxpage, lvar.zoom, 0, x, y, w, h, xx, yy, ow, oh, swid}
                blittbl[lvar.blittbl_cnt][0] = alp or gfx.a
                lvar.blittbl_cnt = lvar.blittbl_cnt + 1
              end

              --gfx.blit(strip_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, rect10.x + stx, rect10.y + pop[i].y)
              if not lvar.popout_autoarrange or not lvar.popout_autoarrange_hideswitchers then
                blittbl[lvar.blittbl_cnt] = {strip_image + gfxpage, lvar.zoom, 0, sx, sy, sw, sh, sxx, syy}
                blittbl[lvar.blittbl_cnt][0] = alp or gfx.a
                lvar.blittbl_cnt = lvar.blittbl_cnt + 1
              end
              
              --f_Get_SSV(gui.color.black)
              --gfx.rect(math.min(stx, pop[i].x),pop[i].y,math.max(w,sw),sh+h,0)
              --gfx.rect(rect10.x + pop[i].x,rect10.y + pop[i].y+(sh+gap)*lvar.zoom,w*lvar.zoom,h*lvar.zoom,0)
            end
          end
        end
      end

      --[[if lvar.mmov_show == true then
        if lupd.update_gfx or lupd.update_mmov or not lvar.mmov_scale then
          GUI_DrawMMOV(obj, gui)
        end
        --GUI_BlitMMOV(obj, gui)
        lvar.blitmmov = true
      end]]
    end
    lvar.redrawpopup = nil

  end

  function GUI_BlitMMOV(obj, gui)

    if not lvar.mmov_scale or not lvar.mmov_rows then

      if lvar.mmov_show then
        if lvar.mixmodedir == 0 then
          local ww = lvar.mmov_vsize+lvar.mmov_pad*2
          if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
            gfx.blit(lvar.bgloaded,1,0,-lvar.bgoffx,-lvar.bgoffy,ww,obj.sections[10000].h+1,obj.sections[10000].x,obj.sections[10000].y-1)
          else
            f_Get_SSV(backcol2 or backcol)
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,ww,obj.sections[10000].h+1,1)
          end
          gfx.a = lvar.mmov_tint
          f_Get_SSV(gui.color.black)
          gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,ww,obj.sections[10000].h+1,1)
          gfx.a = 1
          gfx.rect(obj.sections[10000].x+ww,obj.sections[10000].y-1,1,obj.sections[10000].h+1,1)
        else
          local hh = lvar.mmov_vsize+lvar.mmov_pad*2
          if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
            gfx.blit(lvar.bgloaded,1,0,-lvar.bgoffx,-lvar.bgoffy,obj.sections[10000].w,hh,obj.sections[10000].x,obj.sections[10000].y-1)
          else
            f_Get_SSV(backcol2 or backcol)
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,hh,1)
          end
          gfx.a = lvar.mmov_tint
          f_Get_SSV(gui.color.black)
          gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,hh,1)
          gfx.a = 1
          gfx.rect(obj.sections[10000].x,obj.sections[10000].y+hh-1,obj.sections[10000].w,1,0)
        end
      end
      return
    end

    --if not lvar.mmov_rows then lvar.mmov_rows = {} end

    if lvar.mixmodedir == 0 then
      lvar.mmov_offset = 0
      if lvar.mmov_max < obj.sections[10000].h then
        lvar.mmov_offset = math.floor((obj.sections[10000].h/2) - (lvar.mmov_max/2))
      end

      gfx.a = 1
      local mpad = lvar.mmov_pad
      if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
        gfx.blit(lvar.bgloaded,1,0,-lvar.bgoffx,-lvar.bgoffy,ww,obj.sections[10000].h+1,obj.sections[10000].x,obj.sections[10000].y-1)
      else
        f_Get_SSV(backcol2 or backcol)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,lvar.mmov_vsize+mpad*2,obj.sections[10000].h+1,1)
      end

      --[[if not lvar.poponly or (lvar.mm_fadepop > 0 and not lvar.showpoponly) then
      else
        gfx.a = lvar.mmov_tint
        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,lvar.mmov_vsize+mpad*2,obj.sections[10000].h+1,1)
      end]]

      local scale = lvar.mmov_scale
      local y = math.floor((surface_offset.mixy or 0)*scale) - lvar.mmov_pos
      local h = math.floor(obj.sections[10000].h*scale/lvar.zoom)

      if not lvar.poponly or (lvar.mm_fadepop > 0 and not lvar.showpoponly) then
        gfx.a = 0.2
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y+mpad+y+lvar.mmov_offset,lvar.mmov_vsize+mpad*2,h,1)
      end

      gfx.a = 1
      local mp = lvar.mmov_pos
      local yp = -mp
      local mpadd = 0

      for r = 0, #lvar.mmov_rows do
        local yh = lvar.mmov_rows[r]
        if yh then
          mpadd = mpadd + lvar.mmov_rows[r]
  --add boundary checks
            mp = 0
            gfx.blit(950,1,0,r*(lvar.mmov_vsize*2)--[[+lvar.mmov_vsize]],mp, lvar.mmov_vsize, yh, obj.sections[10000].x+mpad, obj.sections[10000].y+mpad+yp+lvar.mmov_offset)

          yp = yp + yh
        end
      end

      --gfx.blit(950,1,0,0,lvar.mmov_pos, lvar.mmov_vsize, obj.sections[10].h-mpad*2, obj.sections[10].x+mpad, obj.sections[10].y+mpad)

      if not lvar.poponly or (lvar.mm_fadepop > 0 and not lvar.showpoponly) then
        gfx.a = lvar.mmov_tint
        f_Get_SSV(gui.color.black)
        local mmovx, mmovy, mmovw, mmovh = obj.sections[10000].x, obj.sections[10000].y+mpad+y+h, lvar.mmov_vsize+mpad*2, obj.sections[10].h-mpad-y-h
        gfx.rect(mmovx,obj.sections[10000].y,mmovw,mpad+y+lvar.mmov_offset,1)
        gfx.rect(mmovx,mmovy+lvar.mmov_offset,mmovw,mmovh,1)
        gfx.a = 1
        gfx.rect(mmovx+mmovw,obj.sections[10000].y,1,obj.sections[10000].h,1)

        gfx.rect(obj.sections[10000].x,obj.sections[10000].y+mpad+y+lvar.mmov_offset,lvar.mmov_vsize+mpad*2,h,0)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y+mpad+y-1+lvar.mmov_offset,lvar.mmov_vsize+mpad*2,h+2,0)
      else
        gfx.a = lvar.mmov_tint
        f_Get_SSV(gui.color.black)
        --gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,lvar.mmov_vsize+mpad*2,obj.sections[10000].h+1,1)
      end

    else
      lvar.mmov_offset = 0
      if lvar.mmov_max < obj.sections[10].w then
        lvar.mmov_offset = math.floor((obj.sections[10].w/2) - (lvar.mmov_max/2))
      end

      gfx.a = 1
      local mpad = lvar.mmov_pad
      if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
        gfx.blit(lvar.bgloaded,1,0,-lvar.bgoffx,-lvar.bgoffy,obj.sections[10000].w,lvar.mmov_vsize+mpad*2,obj.sections[10000].x,obj.sections[10000].y-1)
      else
        f_Get_SSV(backcol2 or backcol)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,lvar.mmov_vsize+mpad*2,1)
      end
      local scale = lvar.mmov_scale
      local x = math.floor((surface_offset.mixx or 0)*scale) - lvar.mmov_pos
      local w = math.floor(obj.sections[10000].w*scale/lvar.zoom)

      if not lvar.poponly or (lvar.mm_fadepop > 0 and not lvar.showpoponly) then
        gfx.a = 0.2
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[10000].x+mpad+x+lvar.mmov_offset,obj.sections[10000].y-1,w,lvar.mmov_vsize+mpad*2,1)
      end

      gfx.a = 1
      local mp = lvar.mmov_pos
      local xp = -mp
      local mpadd = 0
      for r = 0, #lvar.mmov_rows do
        local xw = lvar.mmov_rows[r]
        if xw then
          mpadd = mpadd + lvar.mmov_rows[r]
  --add boundary checks
            mp = 0
            gfx.blit(950,1,0,mp,r*(lvar.mmov_vsize*2)--[[+lvar.mmov_vsize]],xw, lvar.mmov_vsize, obj.sections[10000].x+mpad+xp +lvar.mmov_offset, obj.sections[10000].y+mpad)

          xp = xp + xw
        end
      end

      if not lvar.poponly or (lvar.mm_fadepop > 0 and not lvar.showpoponly) then
        gfx.a = lvar.mmov_tint
        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y,mpad+x+lvar.mmov_offset,lvar.mmov_vsize+mpad*2,1)
        gfx.rect(obj.sections[10000].x+mpad+x+w+lvar.mmov_offset,obj.sections[10000].y,obj.sections[10000].w-mpad-x-w,lvar.mmov_vsize+mpad*2,1)
        gfx.a = 1
        gfx.rect(obj.sections[10000].x,obj.sections[10000].y+lvar.mmov_vsize+mpad*2-1,obj.sections[10000].w,1,1)

        gfx.rect(obj.sections[10000].x+mpad+x+lvar.mmov_offset,obj.sections[10000].y,w,lvar.mmov_vsize+mpad*2,0)
        gfx.rect(obj.sections[10000].x+mpad+x-1+lvar.mmov_offset,obj.sections[10000].y-1,w+2,lvar.mmov_vsize+mpad*2,0)
      else
        gfx.a = lvar.mmov_tint
        f_Get_SSV(gui.color.black)
        --gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,lvar.mmov_vsize+mpad*2,1)
      end
    end
  end

  function GUI_DrawMMOV(obj, gui)

    --[[gfx.setimgdim(950, -1, -1)
    gfx.setimgdim(950, lvar.maxdim, lvar.maxdim)]]
    Img_SetDim(950, lvar.maxdim, lvar.maxdim)

    gfx.dest = 950

    local vsize = lvar.mmov_vsize
    local mmov_rows = {}
    local mmov_max = 0
    lvar.mmov_max = 0
    local mixpos_max = 0
    lvar.mmov_scale = 0

    local strip = tracks[track_select].strip
    if lvar.stripdim and strips[strip] then

      local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      local extid = swdata.extid
      local row = 0
      if extid then

        if lvar.mixmodedir == 0 then

          

          local runpos = 0
          local maxw = 0

          gfx.a = 1

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
            local sw = swdata[swid].sr-swdata[swid].sl
            maxw = math.max(w, sw, maxw)

          end

          local scale = vsize/maxw
          lvar.mmov_scale = scale
          local padgap = lvar.dm_pady
          local gap = lvar.mmgap

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].pady or padgap

            local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
            local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
            local sw = swdata[swid].sr-swdata[swid].sl
            local sh = swdata[swid].sb-swdata[swid].st
            local x = (swdata[swid].stripl or 0)
            local y = (swdata[swid].stript or 0)
            local sx = swdata[swid].sl
            local sy = swdata[swid].st

            local ssh = h+sh+gap
            --mmov_rows[row] = math.floor(runpos*scale)
            mixpos_max = mixpos_max + ssh + padgap + gap

            if math.floor(runpos*scale)+math.floor(ssh*scale) > lvar.maxdim then
              mmov_max = mmov_max + math.floor(runpos*scale)
              row = row + 1
              runpos = 0
            end
            local ty = runpos

            local gfxpage = swdata[swid].gfxpage

            --local tx = math.floor((vsize/scale)/2) - math.floor(math.max(w,sw)/2)
            --local stx = tx + math.floor(math.max(w, sw)/2) - math.floor(sw/2)

            local tx = math.floor((vsize/scale)/2) - math.floor(w/2)
            local stx = math.floor((vsize/scale)/2) - math.floor(sw/2)

            if w > 0 then
              gfx.blit(strip_image + gfxpage, scale, 0, x, y, w, h, math.floor(tx*scale) + row*(vsize*2), math.floor((ty+sh+gap)*scale))
            end
            if not lvar.showpop or not lvar.popout_autoarrange_hideswitchers then
              gfx.blit(strip_image + gfxpage, scale, 0, sx, sy, sw, sh, math.floor(stx*scale) + row*(vsize*2), math.floor(ty*scale))
            end
            SetColor2(p)
            --gfx.rect(vsize + row*(vsize*2),math.floor((ty+sh)*scale),vsize,math.floor((ssh+padgap)*scale),1)
            gfx.rect(vsize + row*(vsize*2),math.floor((ty)*scale),vsize,math.ceil((ssh+padgap)*scale),1)

            runpos = runpos + padgap + ssh
            mmov_rows[row] = math.floor(runpos*scale)
          end

          lvar.mmov_max = mmov_max + math.floor(runpos*scale)

        else

          local runpos = 0
          local maxh = 0
          local gap = lvar.mmgap

          gfx.a = 1

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
            local sh = swdata[swid].sb-swdata[swid].st
            maxh = math.max(h + sh + gap, maxh)

          end

          local scale = vsize/maxh
          lvar.mmov_scale = scale
          local padgap = lvar.dm_padx

          for p = 1, #posidx[extid] do
            local swid = posidx[extid][p]

            --padgap = switchers[swid].padx or padgap

            local w = (swdata[swid].stripr or 0) - (swdata[swid].stripl or 0)
            local h = (swdata[swid].stripb or 0) - (swdata[swid].stript or 0)
            local sw = swdata[swid].sr-swdata[swid].sl
            local sh = swdata[swid].sb-swdata[swid].st
            local x = (swdata[swid].stripl or 0)
            local y = (swdata[swid].stript or 0)
            local sx = swdata[swid].sl
            local sy = swdata[swid].st

            local ssw = w --math.max(w,sw)
            --mmov_rows[row] = math.floor(runpos*scale)
            mixpos_max = mixpos_max + ssw + padgap

            if math.floor(runpos*scale)+math.floor(ssw*scale) > lvar.maxdim then
              mmov_max = mmov_max + math.floor(runpos*scale)
              row = row + 1
              runpos = 0
            end
            local tx = runpos

            local gfxpage = swdata[swid].gfxpage

            --local ty = math.floor((vsize/scale)/2) - math.floor((h+sh)/2)
            --local stx = tx + math.floor(math.max(w, sw)/2) - math.floor(sw/2)

            local ty = math.floor((vsize/scale)/2) - math.floor((math.max(h+sh+gap))/2)
            local stx = tx + math.floor(--[[math.max(w, sw)]]w/2) - math.floor(sw/2)

            if w > 0 then
              local yoffs = 0
              if lvar.showpop and lvar.popout_autoarrange then
                yoffs = sh/2
              end
              
              gfx.blit(strip_image + gfxpage, scale, 0, x, y, w, h, math.floor(tx*scale), math.floor((ty+sh+gap-yoffs)*scale) + row*(vsize*2))
            end
            if not lvar.showpop or not lvar.popout_autoarrange_hideswitchers then
              gfx.blit(strip_image + gfxpage, scale, 0, sx, sy, sw, sh, math.floor(stx*scale), math.floor(ty*scale) + row*(vsize*2))
            end
            SetColor2(p)
            gfx.rect(math.floor(math.min(tx,stx)*scale),vsize + row*(vsize*2),math.ceil((ssw+padgap)*scale),vsize,1)

            runpos = runpos + padgap + ssw
            mmov_rows[row] = math.floor(runpos*scale)
          end

          lvar.mmov_max = mmov_max + math.floor(runpos*scale)

        end
      end
    end

    gfx.dest = 1
    lvar.mmov_rows = mmov_rows
    lvar.mixpos_max = mixpos_max
    return vsize
  end

  function GUI_DrawControls(obj, gui)

    --gfx.dest = strip_image
    gfx.a = 1
    xywharea = {}

    if lupd.update_gfx or lupd.update_bg then
      --if lvar.livemode == 0 then
        for i = 0, lvar.gfxpages do
          gfx.dest = strip_image + i
          local w,h = gfx.getimgdim(gfx.dest)
          gfx.blit(bg_image+i,1,0,0,0,surface_size.w,surface_size.h,0,0)
        end
      --[[else
        for i = 0, lvar.gfxpages do
          --if surface_size.w == -1 then
            gfx.setimgdim(strip_image+i,-1,-1)
            --gfx.setimgdim(bg_image+i,-1,-1)
            gfx.setimgdim(strip_image+i,surface_size.w, surface_size.h)
            gfx.setimgdim(bg_image+i,surface_size.w, surface_size.h)
          --end
        end
      end]]
    end

    if tracks[track_select] and strips[tracks[track_select].strip] then

      local strip = tracks[track_select].strip
      local ctls = strips[strip][page].controls
      local snaprand_hl = false
      local ctlcats = ctlcats

      if #ctls > 0 then

        local trackM = GetTrack(strips[strip].track.tracknum)
        if trackM == nil then
          if CheckTrack(strips[strip].track, tracks[track_select].strip) then
            trackM = GetTrack(strips[strip].track.tracknum)
          else
            return
          end
        end

        local cdu = ctls_dirty.update
        local cnt = #ctls_dirty.update
        if lupd.update_gfx == true then
          cnt = #ctls
        end

        --Mechanism to redraw on switcher change without redrawing everything
        if lvar.forceredraw and not lupd.update_gfx then
          --Sort items that need clearing first...
          lvar.forceredraw = nil
          local tab = {}
          for cdi = 1, cnt do
            local i = cdu[cdi]
            local ctl = ctls[i]
            if ctl then
              if ctl.forceredraw then
                table.insert(tab, 1, i)
              else
                table.insert(tab, i)
              end
            end
          end
          cdu = tab
        end

        for cdi = 1, cnt do

          if lupd.update_gfx == true then
            i = cdi
          else
            i = cdu[cdi]
          end

          local ctl = ctls[i]
          if ctl then
            ctl.dirty = false
            local hidden, _, swid = Switcher_CtlsHidden(ctl.switcher, ctl.grpid)
            --DBG(swid)

            local ctldraw 
            if (not ctl.hide and hidden ~= true and ((mode == 1 and ctl.hidden and not lvar.ss3_bmp) 
               or ctl.hidden ~= true or macro_lrn_mode == true or snaplrn_mode == true)) then
              ctldraw = true
            end
            if ctldraw or ctl.forceredraw then
              --if not lvar.ss3_bmp or not ctl.hidden then
                local ctlcat = ctl.ctlcat
                if lupd.update_gfx or cdu[cdi] or force_gfx_update or (ctlcat == ctlcats.snapshot and (lupd.update_snaps or lupd.update_fsnaps)) then

                  gfx.dest = strip_image + (ctl.gfxpage or 0)

                  local scale = ctl.scale
                  local x = ctl.x
                  local y = ctl.y
                  local px = math.floor(ctl.xsc)
                  local py = math.floor(ctl.ysc)
                  local w = ctl.w
                  local h = ctl.ctl_info.cellh

                  local gh = h
                  local val = math.floor(100*(ctl.val or 0))
                  local fxnum = ctl.fxnum or -1
                  local param = ctl.param
                  local pname = ctl.param_info.paramname
                  local iidx = ctl.ctl_info.imageidx
                  local spn = ctl.show_paramname
                  local spv = ctl.show_paramval
                  local tc = ctl.textcol
                  local tc2 = ctl.textcolv
                  local toff = math.floor(ctl.textoff)
                  local toffv = math.floor(ctl.textoffval)
                  local toffx = math.floor(ctl.textoffx)
                  local toffvx = math.floor(ctl.textoffvalx)
                  local tsz = ctl.textsize or 0
                  local tsz2 = ctl.textsizev or 0
                  local frames = math.floor(ctl.ctl_info.frames)
                  local ctltype = ctl.ctltype
                  local ctlnmov = ctl.ctlname_override or ''
                  local found = ctl.fxfound
                  local maxdp = ctl.maxdp or -1
                  local dvoff = ctl.dvaloffset
                  local tnum = ctl.tracknum
                  local font = ctl.font
                  local missing, ctype
                  if ctl_files[ctl.knob_select] then
                    ctype = ctl_files[ctl.knob_select].ctltype
                  end

    --              if fxnum == nil then return end

                  local track = trackM
                  if tnum ~= nil then
                    track = GetTrack(tnum)
                    --if track == nil then return end
                  else
                    tnum = strips[strip].track.tracknum
                  end

                  local Disp_ParamV
                  local Disp_Name
                  local v2, val2 = 0, 0

                  if track ~= nil then
                    local range
                    if ctlcat == ctlcats.fxparam or ctlcat == ctlcats.trackparam or ctlcat == ctlcats.tracksend or ctlcat == ctlcats.pkmeter or ctlcat == ctlcats.gr_meter then
                      if settings_enablednu ~= true or ctl.dnu ~= true then
              
                        v2 = math.max(math.min(GetParamValue2(ctlcat,track,fxnum,param,i) or 0,1),0)
              
                        if ctl.scalemode ~= 8 and (ctype == 7 or ctype == 5 or ctype == 6) then
                          v2 = ctlScaleInv(ctl.scalemode, v2)
                        else
                          v2 = frameScale(ctl.framemode, v2) or 0
                        end
                        val2 = ctl.animate_frame or F_limit(round(frames*v2),0,frames-1)
                      else
                        --local mn,mx = GetParamMinMax(ctlcat,track,fxnum,param,false,i)
                        --mn,mx = 0,1
                        --v2 = frameScale(ctl.framemode, normalize(mn,mx,ctl.val)) or 0
                        v2 = frameScale(ctl.framemode, ctl.val) or 0
                        val2 = ctl.animate_frame or F_limit(round(frames*v2),0,frames-1)
                      end

                    elseif ctlcat == ctlcats.action and ctl.monext then
                      v2 = ctl.val
                      range = (ctl.monext.range_end-ctl.monext.range_start)
                      val2 = F_limit(round(v2*range),0,frames-1)

                    elseif ctlcat == ctlcats.action or ctlcat == ctlcats.fxoffline or ctlcat == ctlcats.macro or ctlcat == ctlcats.midictl or ctlcat == ctlcats.switcher_pagesel
                           or ctlcat == ctlcats.fxgui or (ctlcat == ctlcats.infoctl and ctl.param == 2) or ctlcat == ctlcats.threshold or ctlcat == ctlcats.navictl or ctlcat == ctlcats.sk2ctl then
                      v2 = ctl.val or 0
                      val2 = ctl.animate_frame or F_limit(round(frames*v2),0,frames-1)
                    elseif ctlcat == ctlcats.rs5k then
                      if ctl.rsdata.samples and #ctl.rsdata.samples > 0 then
                        v2 = math.floor(ctl.val * lvar.maxsamples) / (#ctl.rsdata.samples -1)
                        val2 = F_limit(round(frames*v2),0,frames-1)
                      end
                    elseif ctlcat == ctlcats.takeswitcher then
                      if ctl.iteminfo then
                        v2 = (math.floor(ctl.val*takeswitch_max)/(ctl.iteminfo.numtakes-1))
                        val2 = F_limit(round(frames*v2),0,frames-1)
                      end
                    elseif ctlcat == ctlcats.statectl then
                      --v2 = ctl.stateinfo.min + (ctl.val * (ctl.stateinfo.max-ctl.stateinfo.min))
                      v2 = F_limit(ctl.stateinfo.min + round((ctl.val * (ctl.stateinfo.max-ctl.stateinfo.min))/ctl.stateinfo.step)*ctl.stateinfo.step,ctl.stateinfo.min,ctl.stateinfo.max)
                      local v3 = (v2 - ctl.stateinfo.min)/(ctl.stateinfo.max-ctl.stateinfo.min)
                      val2 = F_limit(round(frames*v3),0,frames-1)
                    end

                    local DVOV
                    if ctltype == 3 then
                      --invert button
                      val2 = (range or 1)-val2
                    elseif ctltype == 11 then
                      --invert knob/slider
                      val2 = frames-val2-1
                    elseif ctltype == 4 --[[and ctl.cycledata.posdirty == true]] then

                      --cycle button
                      if ctl.cycledata.mapptof then
                        --override val2
                        --prelim code for single state notify
                        if ctl.cycledata.statecnt == 1 then
                          local v3 = ctl.val
                          --must convert to string to compare
                          if not ctl.cycledata[1].startval then
                            if tostring(v3) ~= tostring(ctl.cycledata[1].val) then
                              --not selected
                              val2 = frames-1
                            else
                              --selected
                              val2 = 0
                            end
                          else
                            if v3 >= ctl.cycledata[1].startval and v3 < ctl.cycledata[1].nextval-0.001 then
                              --DBG(v3..'  '..ctl.cycledata[1].startval..'  '..ctl.cycledata[1].nextval)
                              --selected
                              val2 = 0
                            else
                              --not selected
                              val2 = frames-1
                            end
                          end
                        else

                          Disp_ParamV = GetParamDisp(ctlcat, tnum, fxnum, param, dvoff, i)
                          local p = ctl.cycledata.pos
                          if ctl.cycledata[p] and
                             Disp_ParamV ~= ctl.cycledata[p].dv then
                            --DBG(Disp_ParamV..'  '..ctl.cycledata[p].dv)
                            --[[for p = 2, ctl.cycledata.statecnt do
                              local vc = ctl.cycledata[p].val
                              --if p < ctl.cycledata.statecnt then
                              --  vc = vc + (ctl.cycledata[p+1].val - vc)/2
                              --end
                              if Disp_ParamV == ctl.cycledata[p-1].dv or
                                 (ctl.val and ctl.val < vc) then
                                ctl.cycledata.pos = p-1
                                break
                              elseif p == ctl.cycledata.statecnt then
                                ctl.cycledata.pos = p
                              end
                            end]]
                            
                            for p = 1, ctl.cycledata.statecnt do
                              local vc = ctl.cycledata[p].val
                              if p < ctl.cycledata.statecnt then
                                vc = vc + (ctl.cycledata[p+1].val - vc)/2
                              end
                              if Disp_ParamV == ctl.cycledata[p].dv or
                                 (ctl.val and ctl.val <= vc) then
                                ctl.cycledata.pos = p
                                break
                              end
                            end
                          end

                          if ctl.cycledata.spread then
                            val2 = F_limit(math.floor((((ctl.cycledata.pos or 0)-1) /
                                      (ctl.cycledata.statecnt-1)) * (frames-1)),0,frames-1)
                          else
                            val2 = F_limit((ctl.cycledata.pos or 0)-1,0,frames-1)
                          end
                          if ctl.cycledata and
                             ctl.cycledata[(ctl.cycledata.pos or 0)] then
                            DVOV = nz(ctl.cycledata[(ctl.cycledata.pos or 0)].dispval,'')
                          end
                        end

                      else
                        local p = tonumber(ctl.cycledata.pos)

                        if ctl.cycledata and
                           ctl.cycledata[p or 0] then
                          DVOV = nz(ctl.cycledata[(p or 0)].dispval,'')

                        end

                      end

                      --val2 = math.min(frames, val2)

                      if ctl.cycledata.invert then
                        val2 = (frames-1)-val2
                      end


                    elseif ctltype == 6 then
                      --mem button
                      if ctl.membtn == nil then
                        ctl.membtn = {state = false, mem = 0}
                      end
                      local v3 = GetParamValue_Ctl(i)
                      if tostring(v3) ~= tostring(tonumber(ctl.defval)) then
                        ctl.membtn = {state = false, mem = v3}
                      end
                      if ctl.membtn.state == true then
                        val2 = frames-1
                      else
                        val2 = 0
                      end
                    elseif ctltype == 7 or ctltype == 9 then
                      val2 = ctl.val or 0
                    elseif ctltype == 8 or ctltype == 10 then
                      --if ctl.val then
                        val2 = 1-(ctl.val or 0)
                      --end
                    end

                    if not found then
                      gfx.a = 0.2
                    end
                    if ctlcat == ctlcats.fxparam then
                      if not found then
                        if settings_hideplugnotfound ~= true then
                          Disp_Name = CropFXName(ctl.fxname)
                          Disp_ParamV = 'PLUGIN NOT FOUND'
                          tc = gui.color.red
                          val2 = 0
                          missing = true
                        else
                          Disp_Name = ctlnmov or ctl.param_info.paramname
                          Disp_ParamV = ''

                          val2 = 0
                          missing = true
                        end
                      else
                        if ctlnmov == '' then
                          _, Disp_Name = reaper.TrackFX_GetParamName(track, fxnum, param, "")
                        else
                          Disp_Name = ctlnmov
                        end
                        if settings_enablednu ~= true or ctl.dnu ~= true then
                          _, Disp_ParamV = reaper.TrackFX_GetFormattedParamValue(track, fxnum, param, "")
                        else
                          Disp_ParamV = ctl.dval
                        end
                        if dvoff and dvoff ~= 0 then
                          Disp_ParamV = dvaloffset(Disp_ParamV, ctl.dvaloffset)
                        end
                        if maxdp > -1 then
                          Disp_ParamV = roundX(Disp_ParamV, maxdp)
                        end

                      end
                    elseif ctlcat == ctlcats.trackparam then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      Disp_ParamV = GetParamDisp(ctlcat, tnum, nil, param, dvoff, i)
                      if maxdp > -1 then
                        Disp_ParamV = roundX(Disp_ParamV, maxdp)
                      end

                    elseif ctlcat == ctlcats.tracksend then

                      if ctlnmov == '' then
                        local pidx = ctl.param_info.paramidx
                        local dsttrack = reaper.BR_GetMediaTrackSendInfo_Track(track, 0, pidx, 1)
                        if dsttrack then
                          local sname, _ = reaper.GetTrackState(dsttrack)
                          if sname ~= '' then
                            Disp_Name = sname
                          else
                            local tnum = reaper.GetMediaTrackInfo_Value(dsttrack,'IP_TRACKNUMBER')
                            Disp_Name = 'Track '..string.format('%i',tnum)
                          end
                        else
                          Disp_Name = ''
                        end
                      else
                        Disp_Name = ctlnmov
                      end

                      Disp_ParamV = GetParamDisp(ctlcat, tnum, nil, param, dvoff, i)
                      if maxdp > -1 then
                        Disp_ParamV = roundX(Disp_ParamV, maxdp)
                      end

                    elseif ctlcat == ctlcats.action then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      if DVOV and DVOV ~= '' and cycle_editmode == false then
                      else
                        spv = false
                      end

                    elseif ctlcat == ctlcats.pkmeter then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      if param < 64 then
                        Disp_ParamV = GetParamDisp(ctlcat, tnum, nil, param, dvoff, i)
                        if tonumber(Disp_ParamV) ~= nil and tonumber(Disp_ParamV) < -120 then
                          Disp_ParamV = '-inf'
                        end
                      else
                        Disp_ParamV = ''
                      end

                    elseif ctlcat == ctlcats.gr_meter then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      Disp_ParamV = ctl.dval or 0
                      if maxdp > -1 then
                        Disp_ParamV = roundX(Disp_ParamV, maxdp)
                      end
                      
                    elseif ctlcat == ctlcats.snapshot then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      local v
                      if ctl.param_info.paramnum == 2 then
                        v = nz(tonumber(ctl.param_info.paramidx),-1)
                        Disp_ParamV = ''
                        if v > -1 then
                          if snapshots and snapshots[strip] and snapshots[strip][page][param] then
                            if param == 1 then
                              if snapshots[strip][page][param][v] then
                                Disp_ParamV = snapshots[strip][page][param][v].name
                              end
                            else
                              if snapshots[strip][page][param].snapshot[v] then
                                Disp_ParamV = snapshots[strip][page][param].snapshot[v].name
                              end
                            end
                          end
                        end
                      else
                        v = ctl.val or -1
                        Disp_ParamV = ''
                        if v > -1 then
                          if snapshots and snapshots[strip] and snapshots[strip][page][param] and snapshots[strip][page][param].selected then
                            if param == 1 then
                              if snapshots[strip][page][param][snapshots[strip][page][param].selected] then
                                Disp_ParamV = snapshots[strip][page][param][snapshots[strip][page][param].selected].name
                              end
                            else
                              if snapshots[strip][page][param].snapshot[snapshots[strip][page][param].selected] then
                                Disp_ParamV = snapshots[strip][page][param].snapshot[snapshots[strip][page][param].selected].name
                              end
                            end
                          end
                        end
                      end

                    elseif ctlcat == ctlcats.xy or ctlcat == ctlcats.snapshotrand or ctlcat == ctlcats.fxgui then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      if show_randomopts == true and randopts_selectctl == i then
                        snaprand_hl = true
                      end
                    elseif ctlcat == ctlcats.fxoffline or ctlcat == ctlcats.macro_updateparam or ctlcat == ctlcats.navictl then
                      spv = false
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.fxmulti then
                      v2 = ctl.val
                      val2 = F_limit(math.floor(frames*v2),0,frames-1)
                      Disp_ParamV = lvar.fxmulti_table[math.floor(v2*(#lvar.fxmulti_table-1) + 1)]
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.rcm_switch then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      if ctl.rcmdata and ctl.val and ctl.rcmdata[ctl.val] then
                        Disp_ParamV = ctl.rcmdata[ctl.val].name
                      else
                        Disp_ParamV = ''
                      end

                    elseif ctlcat == ctlcats.midictl then
                      --spv = false
                      local ctv = ctl.val
                      if ctl.midiout then
                        ctv = math.floor((ctl.midiout.vmax - ctl.midiout.vmin)*ctv)+ctl.midiout.vmin
                        --[[if ctl.midiout.msgtype <= 6 then
                          ctv = math.floor(ctv * 127)
                        else
                          ctv = math.floor(ctv * 16383)
                        end
                        ctv = roundX(ctv,0)]]
                      end
                      Disp_ParamV = ctv
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.macro then
                      --spv = false
                      Disp_ParamV = round(ctl.val,2)
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.statectl then
                      Disp_ParamV = v2
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.sk2ctl then
                      Disp_ParamV = ctl.dval or v2
                      if ctlnmov == '' then
                        Disp_Name = ctl.slot_name or ctl.fxslot_name or pname
                      else
                        Disp_Name = ctl.slot_name or ctl.fxslot_name or ctlnmov
                      end
                      
                      --ctl.ofxslot_name = ctl.fxslot_name
                      if maxdp > -1 then
                        Disp_ParamV = roundX(Disp_ParamV, maxdp)
                      end
                    elseif ctlcat == ctlcats.statectl_str then

                      Disp_ParamV = ctl.param_info.paramstr or ''

                    elseif ctlcat == ctlcats.threshold then
                      --spv = false
                      Disp_ParamV = math.floor(ctl.val*127)
                      if ctlnmov == '' then
                        Disp_Name = pname..' (Threshold)'
                      else
                        Disp_Name = ctlnmov..' (Threshold)'
                      end

                    elseif ctlcat == ctlcats.eqcontrol then
                      spv = false
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.rs5k then

                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      --if ctl.rsdata and ctl.rsdata[ctl.val] then
                      --  Disp_ParamV = ctl.rsdata[ctl.val].sample
                      --else
                        Disp_ParamV = 'No sample'
                      --end

                      local retval, fn = reaper.TrackFX_GetNamedConfigParm(track, fxnum,'FILE')
                      if retval == true then
                        Disp_ParamV = string.match(fn,'.*[\\/](.*)') or '[No sample]'
                      end

                    elseif ctlcat == ctlcats.switcher then
                      spv = false
                      --if ctlnmov == '' then
                        Disp_Name = pname
                      --else
                      --  Disp_Name = ctlnmov
                      --end

                    elseif ctlcat == ctlcats.takeswitcher then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                      if ctl.iteminfo then
                        Disp_ParamV = ctl.iteminfo.curtake
                      else
                        Disp_ParamV = ''
                      end

                    elseif ctlcat == ctlcats.paramvalue_glob or ctlcat == ctlcats.paramvalue_strip then
                        Disp_ParamV = ctl.pvc_val or ''

                    elseif ctlcat == ctlcats.infoctl then
                        Disp_ParamV = ctl.info_val or ''
                        tc2 = ctl.info_col or tc2

                    elseif ctlcat == ctlcats.fxname then
                        --local retval, fn = reaper.TrackFX_GetFXName(track, fxnum, '')
                        --if retval == true then
                          Disp_Name = ctl.dval --CropFXName(fn or '')
                        --  ctl.dval = Disp_Name
                        --end
                        --DBG(Disp_Name)

                    elseif ctlcat == ctlcats.midieditor_pageswitch then
                      if ctlnmov == '' then
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end

                    elseif ctlcat == ctlcats.switcher_pagesel then
                      if ctlnmov == '' then
                        --local switchid = ctl.switcher
                        --local grpid = ctl.grpid

                        --Disp_Name = switcher[switchid].grpids[
                        Disp_Name = pname
                      else
                        Disp_Name = ctlnmov
                      end
                    end

                    if ctltype == 4 and cycle_editmode == false then
                      if DVOV and DVOV ~= '' then
                        --if ctl.cycledata.posdirty == false then
                          Disp_ParamV = DVOV

                          if maxdp > -1 then
                            Disp_ParamV = roundX(Disp_ParamV, maxdp)
                          end
                        --end
                      --else
                      end
                    end

                    local offl = false
                    if ctlcat == ctlcats.fxparam and ctl.offline then
                      offl = true
                      Disp_Name = ''
                      if settings_showparamnamelabelwhenoffline == true then
                        if ctlnmov ~= '' then
                          Disp_Name = ctlnmov
                        else
                          Disp_Name = pname
                        end
                      end
                      Disp_ParamV = ''
                    end

                  else
                    Disp_ParamV = ''
                    Disp_Name = ''
                  end --track ~= nil

                  local mid = x+(w/2)

                  gfx.setfont(1, font, gui.fontsz_knob +tsz-4)
                  local text_len1x, text_len1y = gfx.measurestr(Disp_Name)
                  
                  gfx.setfont(1, font, gui.fontsz_knob +tsz2-4)
                  local text_len2x, text_len2y = gfx.measurestr(Disp_ParamV)
                  
                  local tl1 = ctl.tl1 or text_len1x
                  local tl2 = ctl.tl2 or text_len2x

                  local th1 = ctl.th1 or text_len1y
                  local th2 = ctl.th2 or text_len2y

                  local xbox1_y = math.floor(y+(h/2)-toff-1)
                  local xywh1 = {x = math.floor(mid-(text_len1x/2))-toffx, y = xbox1_y-math.floor(text_len1y/2), w = text_len1x, h = text_len1y}
                  local xywh2 = {x = math.floor(mid-(text_len2x/2))+toffx+toffvx, y = math.floor(y+(h/2)+toff+toffv-1), w = text_len2x, h = 1}
                  
                  --[[xywh2.y = xywh2.y-math.floor(text_len2y/2)
                  xywh2.h = text_len2y]]
                  
                  local t1y, t2y
                  
                  local wwdata, wwc
                  
                  if (ctl.wwtext or 0) > 0 then

                    if lupd.update_gfx or ctl.wwdata == nil or ctl.wwdata.txt ~= Disp_Name then
                      wwdata = GetWWData(Disp_Name, ctl.wwtext)
                      if ctl.limittext and ctl.limittext > 0 then
                        wwdata.maxlines = ctl.limittext
                      end
                      ctl.wwdata = wwdata
                    end
                    wwdata = ctl.wwdata
                    wwc = math.min(#wwdata, wwdata.maxlines or math.huge)

                    xywh1.w = ctl.wwtext
                    xywh1.x = math.floor(mid-(xywh1.w/2)-toffx)
                    xywh1.h = math.floor(th1*(ctl.owwcnt or 1))
                    xywh1.y = xbox1_y-math.floor(xywh1.h/2)
                    --t1y = xywh1.y-math.ceil(th1/2)

                    xywh1.hh = text_len1y*wwc
                    xywh1.yy = xbox1_y-math.floor(xywh1.hh/2)

                    if (ctl.limittext or 0) > 8 then
                      if ctl.ctlcat ~= ctlcats.sk2ctl then
                        xywh2.w = ctl.limittext
                        xywh2.x = math.floor(mid-(xywh2.w/2)+toffx+toffvx)
                      end
                      t2y = xywh2.y-math.ceil(th2/2)
                      xywh2.y = xywh2.y-math.floor(text_len2y/2)
                      xywh2.h = text_len2y
                    end

                  elseif (ctl.limittext or 0) > 8 then
                    xywh1.w = ctl.limittext
                    xywh1.x = math.floor(mid-(xywh1.w/2)-toffx)
                    --t1y = xywh1.y-math.ceil(th1/2)
                    xywh1.y = xbox1_y-math.floor(text_len1y/2)
                    xywh1.h = text_len1y

                    xywh2.w = ctl.limittext
                    xywh2.x = math.floor(mid-(xywh2.w/2)+toffx+toffvx)
                    t2y = xywh2.y-math.ceil(th2/2)
                    xywh2.y = xywh2.y-math.floor(text_len2y/2)
                    xywh2.h = text_len2y
                  end

                  xywh1.yy = xywh1.yy or xywh1.y
                  xywh1.hh = xywh1.hh or xywh1.h
                  
                  local tx1, tx2 = math.floor(mid-(tl1/2))-toffx,
                                   math.floor(mid-(tl2/2))+toffx+toffvx --gui.fontsz_knob+tsz-4
                  gfx.a=1
                  if not lupd.update_gfx and not lupd.update_bg and ctlcat ~= ctlcats.xy then

                    if ctl.bypassbg_c ~= true then
                      gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, px,
                                         py,
                                         math.floor(w*scale),
                                         math.floor(h*scale),
                                         px,
                                         py)
                    end
                    if spn and ctl.bypassbg_n ~= true then
                      if (ctl.limittext or 0) > 8 or (ctl.wwtext or 0) > 0 then
                        gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, 
                                           (ctl.name_x or xywh1.x),
                                           (ctl.name_y or xywh1.y),
                                           (ctl.name_w or xywh1.w),
                                           ctl.name_h or xywh1.h,
                                           ctl.name_x or xywh1.x,
                                           ctl.name_y or xywh1.y)
                        
                        --[[f_Get_SSV('0 0 0')
                        gfx.rect((ctl.name_x or xywh1.x),
                                 (ctl.name_y or xywh1.y),
                                 (ctl.name_w or xywh1.w),
                                 ctl.name_h or xywh1.h,1)
                        f_Get_SSV('255 0 0')

                        gfx.rect((ctl.name_x or xywh1.x),
                                 (ctl.name_y or xywh1.y),
                                 (ctl.name_w or xywh1.w),
                                 ctl.name_h or xywh1.h,0)]]

                        xywh1.h = xywh1.hh
                        xywh1.y = xywh1.yy
                      else
                        gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, 
                                           ctl.name_x or tx1,
                                           ctl.name_y or xywh1.y-math.floor(th1/2),
                                           ctl.name_w or tl1,
                                           ctl.name_h or --[[th_a]]th1,
                                           ctl.name_x or tx1,
                                           ctl.name_y or xywh1.y-math.floor(th1/2))

                        --[[f_Get_SSV('255 0 0')
                        gfx.rect(ctl.name_x or tx1,
                                           ctl.name_y or xywh1.y-math.floor(th1/2),
                                           ctl.name_w or tl1,
                                            ctl.name_h or th1,0)]]
                        
                        --[[xywh1.h = xywh1.hh
                        xywh1.y = xywh1.yy]]
                      end
                    end
                    if spv and ctl.bypassbg_v ~= true then
                      if (ctl.limittext or 0) > 8 then
                        gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, xywh2.x,
                                           t2y,
                                           xywh2.w,
                                           th2+1,
                                           xywh2.x,
                                           t2y)
                      else
                        gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, tx2,
                                           xywh2.y-math.floor(th2/2),
                                           tl2,
                                           th2+1,
                                           tx2,
                                           xywh2.y-math.floor(th2/2))

                        --[[gfx.blit(bg_image + (ctl.gfxpage or 0),1,0, tx2,
                                           xywh2.y,
                                           tl2,
                                           th2+1,
                                           tx2,
                                           xywh2.y)]]
                      end
                    end
                    gfx.a=1
                  end

                  gfx.a=1
                  if ctlcat == ctlcats.fxparam and param ~= -1 and ((track ~= nil and not reaper.TrackFX_GetEnabled(track, fxnum) and pname ~= 'Bypass') or ctl.offline or missing) then
                    if ctl.offline or missing then
                      gfx.a = 0.25
                    else
                      gfx.a = 0.5
                    end
                  elseif (mode == 1 and submode == 1) or ctl.hidden then
                    gfx.a = 0.5
                  end
                  if ctl.alpha_override then
                    gfx.a = ctl.alpha_override
                  end

                  if ctldraw then 

                    if ctlcat == ctlcats.sk2ctl and tonumber(ctl.param_info.paramnum or 0)&1 == 1 then
                      local tmpa = gfx.a
                      gfx.setimgdim(tmpctl, -1, -1)
                      gfx.setimgdim(tmpctl, w, h)
                      gfx.dest = tmpctl
                      gfx.a = 1
                      
                      gfx.blit(iidx,1 ,0, 0, val2*gh, w, h, 0, 0)
                      if lvar.sk2data_assign then
                        local cidx = tonumber(ctl.param_info.paramidx)
                        if cidx and lvar.sk2data_assign[cidx] then
                          local sscolor = lvar.sk2data_assign[cidx].sscolor
                          if tonumber(sscolor) then
                          
                            if not ctl.adjust or ctl.adjust_active ~= 1 then
                              local t = tab_xtouch_colors[tonumber(sscolor)]
                              gfx.muladdrect(0,0,w,h,(t.r/255),(t.g/255),(t.b/255))
                            else
                              local t = ctl.adjust
                              local ba = -F_limit((0.5-t.bright/512)*2,-1,1)
                              local bc = t.contrast/512
                              if bc > 0.5 then
                                bc = 1+(bc-0.5)*10
                              else
                                bc = bc*2
                              end
                            
                              local t = tab_xtouch_colors[tonumber(sscolor)]
                              gfx.muladdrect(0,0,w,h,bc*(t.r/255),bc*(t.g/255),bc*(t.b/255),1,ba,ba,ba)
                            end
                          end
                        end
                      end
                      gfx.a = tmpa
                      gfx.dest = strip_image + (ctl.gfxpage or 0)
                      gfx.blit(tmpctl,_,0, 0, 0, w, h, px, py, math.floor(w*scale), math.floor(h*scale))
                      --gfx.blit(iidx,_,0, 0, val2*gh, w, h, px, py, math.floor(w*scale), math.floor(h*scale))
                    else 
                      --ctl.adjust = {r = 255, g = 255, b = 255}
                      if not ctl.adjust or ctl.adjust_active ~= 1 then
                        gfx.blit(iidx,_,0, 0, val2*gh, w, h, px, py, math.floor(w*scale), math.floor(h*scale))
                      else
                        local t = ctl.adjust
                        local tmpa = gfx.a
                        gfx.setimgdim(tmpctl, -1, -1)
                        gfx.setimgdim(tmpctl, w, h)
                        gfx.dest = tmpctl
                        gfx.a = 1
                        gfx.blit(iidx,1 ,0, 0, val2*gh, w, h, 0, 0)
                        
                        local ba = -F_limit((0.5-t.bright/512)*2,-1,1)
                        local bc = t.contrast/512
                        if bc > 0.5 then
                          bc = 1+(bc-0.5)*10
                        else
                          bc = bc*2
                        end
                        
                        local mr = t.r/512
                        local mg = t.g/512
                        local mb = t.b/512
                        if mr > 0.5 then
                          mr = 1+(mr-0.5)*10
                        else
                          mr = mr*2
                        end
                        if mg > 0.5 then
                          mg = 1+(mg-0.5)*10
                        else
                          mg = mg*2
                        end
                        if mb > 0.5 then
                          mb = 1+(mb-0.5)*10
                        else
                          mb = mb*2
                        end
                        gfx.muladdrect(0,0,w,h,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)
                        gfx.a = tmpa
                        gfx.dest = strip_image + (ctl.gfxpage or 0)
                        gfx.blit(tmpctl,_,0, 0, 0, w, h, px, py, math.floor(w*scale), math.floor(h*scale))
                      end
                    end
                    if ctype == 5 then
                      local _, knby = gfx.getimgdim(iidx)
                      local knbh = (knby-h)
  
                      local knbv = math.max(math.min(ctl.val,1),0)
                      local knbyp = math.floor(((h*scale)-knbh*scale) - knbv * ((h*scale)-knbh*scale))
                      gfx.blit(iidx,_,0, 0, h, w, knbh, px, py+knbyp, math.floor(w*scale), math.floor(knbh*scale))
  
                    elseif ctype == 6 then
  
                      local knbx, _ = gfx.getimgdim(iidx)
                      local knbw = ctl_files[ctl.knob_select].knbsz
  
                      local knbv = math.max(math.min(ctl.val,1),0)
                      local knbxp = --[[math.floor(((w*scale)-knbw*scale) -]] math.floor(knbv * ((w*scale)-knbw*scale))
  
                      gfx.blit(iidx,_,0, 0, h, knbw, h, px+knbxp, py, math.floor(knbw*scale), math.floor(h*scale))
  
                    elseif ctlcat == ctlcats.xy then
  
                      --draw pos
                      local ppw, pph = gfx.getimgdim(def_xytarget)
                      local ppx = 12+px+math.floor(ctl.xydata.x * (w-24)) - math.floor(ppw/2)
                      local ppy = 12+py+math.floor(ctl.xydata.y * (h-34-24)) - math.floor(pph/2)
  
                      gfx.blit(def_xytarget,1,0, 0, 0, ppw, pph, ppx, ppy)
  
                    end
                    if ctl.ctllock then
                      local iw, ih = gfx.getimgdim(skin.padlock)
                      gfx.blit(skin.padlock,1,0, 0, 0, iw, ih, px --[[+ math.floor((w/2)*scale - (iw/2))]], py --[[+ math.floor((h/2)*scale - (ih/2))]])
                    end
                    --ctl.otl2 = ctl.tl2
                    --ctl.oth2 = ctl.th2
                    
                    ctl.tl1 = text_len1x
                    ctl.tl2 = text_len2x
                    ctl.th1 = text_len1y
                    ctl.th2 = text_len2y
                    
                    ctl.name_ox = ctl.name_x
                    ctl.name_oy = ctl.name_y
                    ctl.name_ow = ctl.name_w
                    ctl.name_oh = ctl.name_h
                    ctl.name_y = xywh1.yy --t1y --xywh1.y-8
                    ctl.name_h = xywh1.hh --+16
                    ctl.name_x = xywh1.x
                    ctl.name_w = xywh1.w
                    
                    if ctl.wwdata then
                      ctl.owwcnt = #ctl.wwdata
                    end
  
                    local alpha = 1
                    if settings_hideofflinelabel and offl then
                      spn = false
                    elseif offl or ctl.hidden then
                      alpha = 0.4
                    end
  
                    if settings_showfaderassignments == true and ctl.macrofader then
                      if mode0_submode == 1 and fader_select == ctl.macrofader then
                        f_Get_SSV(faderselcol)
                      else
                        f_Get_SSV(faderhighcol)
                      end
                      gfx.roundrect(px+1,py+1,math.floor((w*scale-2)),math.floor(h*scale-2),5,1)
                    end
  
                    if snaprand_hl == true and mode == 0 then
                      f_Get_SSV(gui.color.yellow)
                      gfx.roundrect(px+1,py+1,math.floor(w*scale-2),math.floor(h*scale-2),5,1)
                      snaprand_hl = false
                    end
  
                    if settings_showfaderassignments == true and ctl.mod then
                      if (mode0_submode == 2 or (show_lfoedit == true and modwinsz.minimized ~= true)) and mod_select == ctl.mod then
                        f_Get_SSV(modselcol)
                      else
                        f_Get_SSV(modhighcol)
                      end
  
                      if modulators[ctl.mod].active == false then
                        gfx.a = 0.3
                      end
                      gfx.roundrect(px+1,py+1,math.floor(w*scale-2),math.floor(h*scale-2),5,1)
                      gfx.a = 1
                    end
  
                    if ctlcat == ctlcats.sk2ctl then
                      if tonumber(ctl.param_info.paramnum or 0)&2 == 2 then
                        if lvar.sk2data_assign then
                          local cidx = tonumber(ctl.param_info.paramidx)
                          if cidx and lvar.sk2data_assign[cidx] then
                            local sscolor = lvar.sk2data_assign[cidx].sscolor
                            if tonumber(sscolor) then
                              local t = tab_xtouch_colors[tonumber(sscolor)]
                              tc = tostring(math.min(t.r*5,255))..' '..tostring(math.min(t.g*5,255))..' '..tostring(math.min(t.b*5,255))
                              tc2 = tc
                            end
                          end
                        end
                      end
                    end
  
                    --LABELS
                    if spn then
                      gfx.setfont(1, font, gui.fontsz_knob +tsz-4)
                      if (ctl.wwtext or 0) > 0 and ctl.wwdata then
                        local tflags = ctl.textflags or 5
                        local wwdata = ctl.wwdata
                        local box = {x = xywh1.x, y = xywh1.yy, w = xywh1.w, h = text_len1y}
                        for wwt = 1, math.min(#wwdata, (wwdata.maxlines or math.huge)) do
                          if wwdata[wwt].t then
                            GUI_textCtl2(gui, box, wwdata[wwt].t , tc,-4 + tsz, alpha, tflags)
                            box.y = box.y + text_len1y
                          end
                        end
                        if mode == 1 and submode == 0 then
                          gfx.a = 0.5
                          gfx.rect(xywh1.x,xywh1.yy,xywh1.w,xywh1.hh,0)
                        end
  
                      elseif (ctl.limittext or 0) > 8 then
                        local tflags = ctl.textflags or 5
                        if tflags == -1 then
                          tflags = 5
                          if text_len1x > xywh1.w then
                            tflags = 4
                          end
                        end
                        GUI_textCtl2(gui,xywh1, Disp_Name,tc,-4 + tsz, alpha, tflags)
                        if mode == 1 and submode == 0 then
                          gfx.a = 0.5
                          gfx.rect(xywh1.x,xywh1.y,xywh1.w,xywh1.h,0)
                        end
                      else
                        GUI_textCtl(gui, xywh1, Disp_Name, tc, -4 + tsz, alpha)
                      end
                    end
                    ctl.display_value = Disp_ParamV or ''
                    if spv then
                      gfx.setfont(1, font, gui.fontsz_knob +tsz2-4)
                      if (ctl.limittext or 0) > 8 and ctl.ctlcats ~= ctlcats.sk2ctl then
                        local tflags = ctl.textflags or 5
                        if tflags == -1 then
                          tflags = 5
                          if text_len2x > xywh2.w then
                            tflags = 4
                          end
                        end
                        GUI_textCtl2(gui,xywh2, Disp_ParamV,tc2,-4 + tsz2, alpha, tflags)
                        if mode == 1 and submode == 0 then
                          gfx.a = 0.5
                          gfx.rect(xywh2.x,xywh2.y,xywh2.w,xywh2.h,0)
                        end
                      else
                        GUI_textCtl(gui,xywh2, Disp_ParamV,tc2,-4 + tsz2, alpha)
                      end
                    end
  
                    if setting_reddotindicator == true and ctltype == 4 and DVOV and DVOV ~= '' and cycle_editmode == false then
                      if ctl.cycledata.posdirty == true then
                        gfx.a = 0.8
                        f_Get_SSV(gui.color.red)
                        gfx.circle(x+4,y+4,2,1,1)
                      end
                    end
  
                    if mode == 1 and submode == 2 and not lvar.ss3_bmp then
                      if tnum and tnum ~= tracks[track_select].tracknum then
  
                        gfx.a = 0.8
                        f_Get_SSV(gui.color.red)
                        gfx.circle(x,y,2,1,1)
  
                      end
                    end
                    
                  end
                  ctl.forceredraw = nil
                  
                  if not lupd.update_gfx and not lupd.update_bg and lupd.update_ctls then
                    if lvar.livemode >= 1 or (lvar.livemode == 0 and gfx.dest == strip_image) then
                      --just blit control area to main backbuffer - create area table
                      local md_x = mid+toffx+toffvx
                      
                      local al, ar, at, ab = px, px+math.floor(w*scale), py, py+math.floor(h*scale)
                      if spn then
                        local md_y = xbox1_y
                        --local ttl1x = math.max(text_len1x, tl1, ctl.name_ow or 0, ctl.name_w or 0)
                        local ttl1y = math.max(text_len1y, th1, ctl.name_oh or 0, ctl.name_h or 0)
                        al = math.min(al, xywh1.x, --[[tx1,]] ctl.name_ox or math.huge, ctl.name_x or math.huge)
                        ar = math.max(ar, --[[tx1+ttl1x,]] xywh1.x+xywh1.w, (ctl.name_ox or 0)+(ctl.name_ow or 0), (ctl.name_x or 0)+(ctl.name_w or 0))
                        --at = math.min(at, xywh1.y-math.floor(ttl1y/2))
                        --ab = math.max(ab, xywh1.y-math.floor(ttl1y/2)+xywh1.h)
                        at = math.min(at, md_y-math.floor(ttl1y/2))
                        ab = math.max(ab, md_y+math.floor(ttl1y/2))

                      end
                      if spv then
                        local md2_y = xywh2.y --+math.floor(xywh2.h/2)
                        local ttl2x = math.max(text_len2x, tl2)
                        local ttl2y = math.max(text_len2y, th2+4) --shitty hack
                        al = math.min(al, md_x-math.floor(ttl2x/2))
                        ar = math.max(ar, md_x+math.floor(ttl2x/2))
                        --al = math.min(al, xywh2.x, tx2)
                        --ar = math.max(ar, tx2+ttl2x, xywh2.x+xywh2.w)
                        at = math.min(at, md2_y-math.floor(ttl2y/2))
                        ab = math.max(ab, md2_y+math.floor(ttl2y/2))
                        --at = math.min(at, xywh2.y-math.floor(ttl2y/2))
                        --ab = math.max(ab, xywh2.y+math.floor(ttl2y/2))
                      end

                      --[[if i == 247 then
                        DBG(math.max(text_len1y, th1, ctl.name_oh or 0, ctl.name_h or 0))
                        local c = string.format('%i',math.floor(math.random()*255))..' '..
                                  string.format('%i',math.floor(math.random()*255))..' '..
                                  string.format('%i',math.floor(math.random()*255))
                                                                                  
                        f_Get_SSV(c)
                        gfx.rect(al,
                                 at,
                                 ar-al,
                                 ab-at,0)
                      end]]
                      
                       --[[ local ttl1x = math.max(text_len1x, tl1)
                        local ttl2x = math.max(text_len2x, tl2)
                        local ttl1y = math.max(text_len1y, th1)
                        local ttl2y = math.max(text_len2y, th2)

                        al = math.min(px, xywh1.x, xywh2.x, tx1, tx2)
                        ar = math.max(px+math.floor(w*scale), tx1+ttl1x, tx2+ttl2x, xywh1.x+xywh1.w, xywh2.x+xywh2.w)
                        at = math.min(py, xywh1.y-math.floor(ttl1y/2), xywh2.y-math.floor(ttl2y/2))
                        ab = math.max(py+math.floor(h*scale),xywh1.y-math.floor(ttl1y/2)+xywh1.h, xywh2.y+math.floor(ttl2y/2))
                      ]]

                      --local swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
                      xywharea[#xywharea+1] = {x=al,y=at,w=ar-al,h=ab-at,r=ar,b=ab, c = i, swid = swid, ox = px-al, oy = py-at, gfxsrc = gfx.dest}
                      --DBG(w)

                    end
                  end
                end
              --end
            end

          end
        end

        ctls_dirty.update = {}
        ctls_dirty.idx = {}

        if not lupd.update_gfx and not lupd.update_bg and lupd.update_ctls and show_striplayout == false and stripgallery_view == 0 --[[and lvar.livemode == 0]] then
          --loop through blit area table - blit to backbuffer
          gfx.a=1
          local ox, oy = 0,0
          --if surface_offset.x < 0 then ox=-1 end
          --if surface_offset.y < 0 then oy=-1 end

          if #xywharea > 0 then

            gfx.dest = 1
            local floor = math.floor

            local o10x = obj.sections[10].x
            local o10y = obj.sections[10].y
            if lvar.mmov_show then
              if lvar.mixmodedir == 0 then
                o10x = o10x + lvar.mmov_vsize + lvar.mmov_pad*2 + 1
              else
                o10y = o10y + lvar.mmov_vsize + lvar.mmov_pad*2
              end
            end

            for i = 1, #xywharea do

              local xywha = xywharea[i]

              local xx = (xywha.x - surface_offset.x)*lvar.zoom + obj.sections[10].x --+ ox
              local yy = (xywha.y - surface_offset.y)*lvar.zoom + obj.sections[10].y --+ oy
              local xxx = (xywha.x - surface_offset.x) + obj.sections[10].x
              local yyy = (xywha.y - surface_offset.y) + obj.sections[10].y
              local strip_image = xywha.gfxsrc
              if xx+xywha.w*lvar.zoom < obj.sections[10].x or yy+xywha.h*lvar.zoom < obj.sections[10].y
                 or yy > obj.sections[10].y+obj.sections[10].h or xx > obj.sections[10].x+obj.sections[10].w then
                 --DBG('skipped')

              elseif lvar.livemode == 0 then
                if xx < obj.sections[10].x then
                  xywha.x = xywha.x + (obj.sections[10].x - xxx)
                  xywha.w = xywha.w - (obj.sections[10].x - xxx)
                  xx = obj.sections[10].x
                end
                if xx + xywha.w > obj.sections[10].x+obj.sections[10].w then
                  xywha.w = (obj.sections[10].x+obj.sections[10].w)-xxx
                end
                if yy < obj.sections[10].y then
                  xywha.y = xywha.y + (obj.sections[10].y - yyy)
                  xywha.h = xywha.h - (obj.sections[10].y - yyy)
                  yy = obj.sections[10].y
                end
                if yy + xywha.h > obj.sections[10].y+obj.sections[10].h then
                  xywha.h = (obj.sections[10].y+obj.sections[10].h)-yyy
                end

                --[[if lvar.zoom ~= 1 then
                  xx = xx*lvar.zoom
                  yy = yy*lvar.zoom
                end]]

                gfx.dest = 1
                gfx.blit(strip_image,lvar.zoom,0,
                                   xywha.x,
                                   xywha.y,
                                   xywha.w,
                                   xywha.h,
                                   xx,
                                   yy)
                
              end

              if mode == 0 and lvar.livemode >= 1 then
                if lvar.mixmode_fastdraw == 2 then
                  local swid = ctls[xywha.c].switcherid
                  if swid then
                    lvar.mixswids[swid] = true
                  end

                elseif lvar.mixmode_fastdraw == 1 then

                  local xx, yy = TranslateMixCtlPos(xywha.c, xywha.swid)
                  if xx and yy then
                    local shadtop, shadleft
                    gfx.dest = 1
                    local disp = true
                    local yyy = floor(yy-xywha.oy*lvar.zoom)
                    local xxx = floor(xx-xywha.ox*lvar.zoom)
                    if yyy < o10y then
                      local nh = yyy+floor(xywha.h*lvar.zoom) - o10y
                      if nh > 0 then
                        xywha.y = xywha.y + (xywha.h - nh/lvar.zoom)
                        xywha.h = nh/lvar.zoom
                        yyy = o10y

                        if lvar.enablegfxshadows then
                          shadtop = true
                        end
                      else
                        disp = false
                      end
                    elseif yyy < o10y+lvar.shadowmax then

                      if lvar.enablegfxshadows then
                        local dy = lvar.shadowmax-((o10y+lvar.shadowmax)-yyy)
                        yyy = yyy-dy
                        xywha.y = xywha.y-dy
                        xywha.h = xywha.h+dy
                        shadtop = true
                      end
                    end
                    if yyy + floor(xywha.h*lvar.zoom) > obj.sections[10].y+obj.sections[10].h then
                      local nh = floor(xywha.h*lvar.zoom) - ((yyy+floor(xywha.h*lvar.zoom)) - (obj.sections[10].y+obj.sections[10].h))
                      if nh > 0 then
                        xywha.h = nh/lvar.zoom - 1
                      else
                        disp = false
                      end
                    end
                    if disp then
                      if xxx < o10x then
                        local nw = xxx+floor(xywha.w*lvar.zoom) - o10x
                        if nw > 0 then
                          xywha.x = xywha.x + (xywha.w - nw/lvar.zoom)
                          xywha.w = nw/lvar.zoom
                          xxx = o10x

                          if lvar.enablegfxshadows then
                            shadleft = true
                          end
                        else
                          disp = false
                        end
                      elseif xxx < o10x+lvar.shadowmax then
                        if lvar.enablegfxshadows then
                          local dx = lvar.shadowmax-((o10x+lvar.shadowmax)-xxx) - 2
                          xxx = xxx-dx
                          xywha.x = xywha.x-dx
                          xywha.w = xywha.w+dx
                          shadleft = true
                        end
                      end
                      if xxx + floor(xywha.w*lvar.zoom) > obj.sections[10].x+obj.sections[10].w then
                        local nw = floor(xywha.w*lvar.zoom) - ((xxx+floor(xywha.w*lvar.zoom)) - (obj.sections[10].x+obj.sections[10].w))
                        if nw > 0 then
                          xywha.w = nw/lvar.zoom -- 1
                        else
                          disp = false
                        end
                      end
                    end
                    if disp then
                      local popidx = strips[strip][page].popidx or {}
                      local pop = strips[strip][page].pop
                      if lvar.showpop == true and popidx and not popidx[xywha.swid] then
                        gfx.a = 1
                        if lvar.bgloaded > 0 then
                          local bx, by
                          bx = xxx - o10x
                          by = yyy - o10y
                          if lvar.mixmodedir == 0 then
                            if lvar.mmov_show then
                              bx = bx + (lvar.mmov_vsize + lvar.mmov_pad*2) + 1
                            end
                          else
                            if lvar.mmov_show then
                              by = by + (lvar.mmov_vsize) --[[+ lvar.mmov_pad*2)]]
                            end
                          end
                          gfx.blit(lvar.bgloaded,1,0,bx-lvar.bgoffx,by-lvar.bgoffy,floor(xywha.w*lvar.zoom),floor(xywha.h*lvar.zoom),xxx,yyy)
                        elseif lvar.backcol then
                          f_Get_SSV(lvar.backcol)
                          gfx.rect(xxx,yyy,floor(xywha.w*lvar.zoom),floor(xywha.h*lvar.zoom),1)
                        end

                        if popidx[xywha.swid] then
                          gfx.a = 0.1
                        elseif pop and #pop > 0 then
                          gfx.a = lvar.mm_fadepop
                        end
                        lvar.redrawpopup = true
                      elseif popidx and not popidx[xywha.swid] then
                        lvar.redrawpopup = true
                      end

                      if not lvar.showpop or (popidx and not popidx[xywha.swid]) then
                        if not switchers[xywha.swid].dragging then
                          gfx.blit(strip_image,lvar.zoom,0,
                                             floor(xywha.x),
                                             floor(xywha.y),
                                             floor(xywha.w),
                                             floor(xywha.h),
                                             xxx,
                                             yyy)
                          
                        end
                      end

                      --shadows
                      if shadtop then
                        local s = lvar.shadows[1]
                        if s then
                          local shadbits = lvar.shadowbits or {}
                          --local offy = math.max(0, yyy-s.y)
                          shadbits[#shadbits+1] =  {x = xxx, y = s.y, w = floor(xywha.w)*lvar.zoom, h = math.min(xywha.h,s.h),
                                                    srcx = s.srcx, srcy = s.srcy, srcw = s.srcw, srch = s.srch}
                          lvar.shadowbits = shadbits
                        end
                      end
                      if shadleft then
                        local s = lvar.shadows[2]
                        if s then
                          local shadbits = lvar.shadowbits or {}
                          shadbits[#shadbits+1] =  {x = s.x, y = yyy, w = math.min(xywha.w,s.w), h = floor(xywha.h)*lvar.zoom,
                                                    srcx = s.srcx, srcy = s.srcy, srcw = s.srcw, srch = s.srch}
                          lvar.shadowbits = shadbits
                        end
                      end

                    end
                  end
                end
              end
            end
          end
        end

      end
    end
    force_gfx_update = false

  end

  ------------------------------------------------------------

  function CalcSelRect()

    if strips and tracks[track_select] and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page] and ctl_select and ctl_select[1] then
      if #strips[tracks[track_select].strip][page].controls > 0 then
        local i = ctl_select[1].ctl
        local ctl = strips[tracks[track_select].strip][page].controls[i]

        local x = ctl.x
        local y = ctl.y
        local w = ctl.w
        local h = ctl.ctl_info.cellh

        local xsc = ctl.xsc
        local ysc = ctl.ysc
        local wsc = ctl.wsc
        local hsc = ctl.hsc

        local rx, ry = x+w, y+h
        local rxsc, rysc = xsc+wsc, ysc+hsc

        if #ctl_select > 1 then
          for i = 2, #ctl_select do
            j = ctl_select[i].ctl
            local ctlj = strips[tracks[track_select].strip][page].controls[j]

            x = math.min(x, ctlj.x)
            y = math.min(y, ctlj.y)
            rx = math.max(rx, ctlj.x + ctlj.w)
            ry = math.max(ry, ctlj.y + ctlj.ctl_info.cellh)
            xsc = math.min(xsc, ctlj.xsc)
            ysc = math.min(ysc, ctlj.ysc)
            rxsc = math.max(rxsc, ctlj.xsc + ctlj.wsc)
            rysc = math.max(rysc, ctlj.ysc + ctlj.hsc)

          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1, #gfx3_select do
            j = gfx3_select[i].ctl

            x = math.min(x, strips[tracks[track_select].strip][page].graphics[j].x)
            y = math.min(y, strips[tracks[track_select].strip][page].graphics[j].y)
            rx = math.max(rx, strips[tracks[track_select].strip][page].graphics[j].x + strips[tracks[track_select].strip][page].graphics[j].stretchw)
            ry = math.max(ry, strips[tracks[track_select].strip][page].graphics[j].y + strips[tracks[track_select].strip][page].graphics[j].stretchh)

            xsc = math.min(xsc, strips[tracks[track_select].strip][page].graphics[j].x)
            ysc = math.min(ysc, strips[tracks[track_select].strip][page].graphics[j].y)
            rxsc = math.max(rxsc, strips[tracks[track_select].strip][page].graphics[j].x + strips[tracks[track_select].strip][page].graphics[j].stretchw)
            rysc = math.max(rysc, strips[tracks[track_select].strip][page].graphics[j].y + strips[tracks[track_select].strip][page].graphics[j].stretchh)
            
          end
        end

        local selrect = {x = x, y = y, w = rx-x, h = ry-y}
        local selrect_sc = {x = xsc, y = ysc, w = rxsc-xsc, h = rysc-ysc}
        return selrect, selrect_sc
      end
    end

    return nil

  end

  function CalcCtlRect()

    local rect = nil
    if strips and tracks[track_select] and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page] then
      if #strips[tracks[track_select].strip][page].controls > 0 then
        local i = 1
        local x = strips[tracks[track_select].strip][page].controls[i].x
        local y = strips[tracks[track_select].strip][page].controls[i].y
        local w = strips[tracks[track_select].strip][page].controls[i].w
        local h = strips[tracks[track_select].strip][page].controls[i].ctl_info.cellh
        local rx, ry = x+w, y+h
        if #strips[tracks[track_select].strip][page].controls > 1 then
          for j = 2, #strips[tracks[track_select].strip][page].controls do

            x = math.min(x, strips[tracks[track_select].strip][page].controls[j].x)
            y = math.min(y, strips[tracks[track_select].strip][page].controls[j].y)
            rx = math.max(rx, strips[tracks[track_select].strip][page].controls[j].x + strips[tracks[track_select].strip][page].controls[j].w)
            ry = math.max(ry, strips[tracks[track_select].strip][page].controls[j].y + strips[tracks[track_select].strip][page].controls[j].ctl_info.cellh)

          end
        end

        rect = {x = x, y = y, w = rx-x, h = ry-y}
      end
    end

    return rect
  end

  function CalcGFXSelRect()

    if strips and tracks[track_select] and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page] then
      if #strips[tracks[track_select].strip][page].graphics > 0 then
        local i = gfx2_select
        local gfxx = strips[tracks[track_select].strip][page].graphics[i]
        local x = gfxx.x
        local y = gfxx.y
        local w = gfxx.stretchw
        local h = gfxx.stretchh
        local rx, ry = x+w, y+h
        local selrect = {x = x-4, y = y-4, w = w+8, h = h+8}
        return selrect
      end
    end

    return nil

  end

  function CalcGFX4SelRect()

    if strips and tracks[track_select] and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page] then
      if #strips[tracks[track_select].strip][page].graphics > 0 and gfx4_select then

        local x,y,r,b,w,h,rx,ry = lvar.maxdim, lvar.maxdim, 0, 0, 0, 0
        local strip = tracks[track_select].strip
        --local lbl
        for g = 1, #gfx4_select do
          local i = gfx4_select[g]
          local gfxx = strips[strip][page].graphics[i]
          x = math.min(x, gfxx.x)
          y = math.min(y, gfxx.y)
          r = math.max(r, gfxx.x + gfxx.stretchw)
          b = math.max(b, gfxx.y + gfxx.stretchh)
          --local rx, ry = x+w, y+h
        end

        local selrect = {x = x-4, y = y-4, w = r-x+8, h = b-y+8}
        return selrect
      end
    end

    return nil

  end

  ------------------------------------------------------------

    function GUI_DrawParamLearn(obj, gui)

      gfx.a=1

      GUI_DrawPanel(obj.sections[115],true,'PARAM LEARN')

      --[[f_Get_SSV(gui.color.black)
      gfx.rect(obj.sections[115].x,
               obj.sections[115].y,
               obj.sections[115].w,
               obj.sections[115].h, 1, 1)
      f_Get_SSV('64 64 64')
      gfx.rect(obj.sections[115].x,
               obj.sections[115].y,
               obj.sections[115].w,
               obj.sections[115].h, 0, 1)]]

      xywh = {x = obj.sections[115].x,
              y = obj.sections[115].y,
              w = obj.sections[115].w,
              h = butt_h}

      --[[f_Get_SSV(gui.color.white)
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               butt_h, 1 )]]

      --GUI_textC(gui,xywh,'PARAM LEARN',gui.color.black,-2)

      xywh.y = obj.sections[116].y
      local iidx = 1023

      if knob_select > -1 then
        if ctl_files[knob_select].imageidx ~= nil then
          iidx = ctl_files[knob_select].imageidx
        else
          gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
        end
        local w, _ = gfx.getimgdim(iidx)
        gfx.a = 1
        local sx,sy = 1,1
        if w > obj.sections[115].w then
          sx = obj.sections[115].w/w
        end
        if ctl_files[knob_select].cellh > 128 then
          sy = 128/ctl_files[knob_select].cellh
        end
        local sc = F_limit(math.min(sx, sy),0,1)
        gfx.blit(iidx,sc,0, 0,
                            ctl_files[knob_select].cellh*math.floor(ctl_files[knob_select].frames*0.75),
                            w,
                            ctl_files[knob_select].cellh, xywh.x + (xywh.w/2-(w*sc)/2),
                            xywh.y + (62.5 - (ctl_files[knob_select].cellh*sc)/2))

      end

      if last_touch_fx then

        GUI_textsm_LJ(gui,obj.sections[117],last_touch_fx.tracknum..': '..last_touch_fx.trname,gui.color.white,-5,obj.sections[117].w)
        GUI_textsm_LJ(gui,obj.sections[118],last_touch_fx.fxname,gui.color.white,-5,obj.sections[117].w)
        GUI_textsm_LJ(gui,obj.sections[119],last_touch_fx.prname,gui.color.white,-5,obj.sections[117].w)

      end

    end

  ------------------------------------------------------------

  function GUI_DrawPanel(objPanel, tobgd, tit, noscale, alpha, talpha)

    gfx.a=alpha or 1
    local x,y = 0,0
    if tobgd then
      x,y = objPanel.x, objPanel.y
    end
    --objPanel.h = math.floor(objPanel.h)
    
    local wt, ht = gfx.getimgdim(skin.panela_top)
    local wb, hb = gfx.getimgdim(skin.panela_bot)
    local hh = ht + hb
    local pw = objPanel.w
    local ph = tonumber(objPanel.h)
    if hh > ph then ht = ph - hb end
    local edge = 10

    if objPanel.h <= gui.winsz.pnltit*pnl_scale then
      ht = objPanel.h

      local thh = gui.winsz.pnltit*pnl_scale
      gfx.blit(skin.panela_top, 1, 0, 0, 0, edge, edge, x, y)
      gfx.blit(skin.panela_top, 1, 0, 0, edge, edge, gui.winsz.pnltit-edge, x, y+edge, edge, math.floor((thh)-edge))

      gfx.blit(skin.panela_top, 1, 0, wt-edge, 0, edge, edge, x+(pw-edge), y)
      gfx.blit(skin.panela_top, 1, 0, wt-edge, edge, edge, gui.winsz.pnltit-edge, x+(pw-edge), y+edge, edge, math.floor((thh)-edge))

      gfx.blit(skin.panela_top, 1, 0, edge, 0, wt-(2*edge), edge, x+edge, y, pw-(2*edge))
      gfx.blit(skin.panela_top, 1, 0, edge, edge, wt-(2*edge), gui.winsz.pnltit-edge, x+edge, y+edge, pw-(2*edge),math.floor((thh)-edge))

      --gfx.blit(skin.panela_top, 1, 0, 0, 0, edge, ht, x, y)
      --gfx.blit(skin.panela_top, 1, 0, wt-edge, 0, edge, ht, x+(pw-edge), y)
      --gfx.blit(skin.panela_top, 1, 0, 10, 0, wt-(2*edge), ht, x+edge, y, pw-(2*edge))
    else

      local adjustth = 0
      if noscale ~= true then
    
        local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
        --Left top
        gfx.a = talpha or 1
        gfx.blit(skin.panela_top, 1, 0, 0, 0, edge, edge, x, y)
        gfx.blit(skin.panela_top, 1, 0, 0, edge, edge, gui.winsz.pnltit-edge, x, y+edge, edge, math.ceil((thh)-edge))
        gfx.a=alpha or 1
        gfx.blit(skin.panela_top, 1, 0, 0, gui.winsz.pnltit+1, edge, ht-gui.winsz.pnltit, x, math.ceil(y+thh), edge, math.ceil(ht-(thh)))

        --Right top
        gfx.a = talpha or 1
        gfx.blit(skin.panela_top, 1, 0, wt-edge, 0, edge, edge, x+(pw-edge), y)
        gfx.blit(skin.panela_top, 1, 0, wt-edge, edge, edge, gui.winsz.pnltit-edge, x+(pw-edge), y+edge, edge, math.ceil((thh)-edge))
        gfx.a=alpha or 1
        gfx.blit(skin.panela_top, 1, 0, wt-edge, gui.winsz.pnltit+1, edge, ht-gui.winsz.pnltit, x+(pw-edge), math.ceil(y+thh), edge, math.ceil(ht-(thh)))

        --Mid top
        gfx.a = talpha or 1
        gfx.blit(skin.panela_top, 1, 0, edge, 0, wt-(2*edge), edge, x+edge, y, pw-(2*edge))
        gfx.blit(skin.panela_top, 1, 0, edge, edge, wt-(2*edge), gui.winsz.pnltit-edge, x+edge, y+edge, pw-(2*edge),math.ceil((thh)-edge))
        gfx.a=alpha or 1
        gfx.blit(skin.panela_top, 1, 0, edge, gui.winsz.pnltit+1, wt-(2*edge), ht-gui.winsz.pnltit, x+edge, math.ceil(y+thh), pw-(2*edge),math.ceil(ht-(thh)))
      
        adjustth = ht
      else
        gfx.blit(skin.panela_top, 1, 0, 0, 0, edge, ht, x, y)
        gfx.blit(skin.panela_top, 1, 0, wt-edge, 0, edge, ht, x+(pw-edge), y)
        gfx.blit(skin.panela_top, 1, 0, edge, 0, wt-(2*edge), ht, x+edge, y, pw-(2*edge))
        adjustth = ht
      end

      local th = adjustth
      local ad
      local shh = ph - th - hb
      if pnl_scale <= 1 then 
        --stupid maths to deal with pnl_scale <= 1
        ad = math.floor(((1-pnl_scale)/0.05))+2
        th = th - ad
      end
      local sh = ph - th - hb
      gfx.blit(skin.panela_bot, 1, 0, 0, 0, edge, hb, x, y+ph-hb)
      gfx.blit(skin.panela_bot, 1, 0, wt-edge, 0, edge, hb, x+(pw-edge), y+ph-hb)
      gfx.blit(skin.panela_bot, 1, 0, edge, 0, wb-(2*edge), hb, x+edge, y+ph-hb, pw-(2*edge))

      if shh > 0 then
        local w, h = gfx.getimgdim(skin.panela_mid)
        gfx.blit(skin.panela_mid, 1, 0, 0, 0, edge, h, x, y+th, edge, sh)
        gfx.blit(skin.panela_mid, 1, 0, w-edge, 0, edge, h, x+(pw-edge), y+th, edge, sh)
        gfx.blit(skin.panela_mid, 1, 0, edge, 0, w-(2*edge), h, x+edge, y+th, pw-(2*edge), sh)
      end
    end

    --[[if skin.texture ~= -1 then
      gfx.mode = 1
      gfx.a = -0.2
      gfx.blit(skin.texture, 1, 0, 0, 0, pw, ph, x, y)
      gfx.mode = gmode
    end]]
    gfx.a=1
    if tit then
      local yoff = gui.winsz.pnltit - butt_h
      local tscale = 0
      local pscale = 1
      if noscale ~= true then
        tscale = (pnl_scale-1)*fontscale
        pscale = pnl_scale
      end
      xywh = {x = x,
              y = y+yoff,
              w = pw,
              h = butt_h*pscale}
      GUI_Str(gui,xywh,tit,5,gui.skol.pnl_tittxt,gui.fontsz.pnltit + tscale ,1,gui.skol.pnltit_shad,gui.fontnm.pnltit,gui.fontflag.pnltit)
    end

  end

  function GUI_DrawSnapshots_Morph(obj, gui)

    gfx.dest = 1003

    gfx.a = 1

    local butt_h = butt_h*pnl_scale

    SS_butt_cnt = math.floor(obj.sections[163].h / butt_h) - 1
    local sbobj = obj.sections[1016]
    if snaplrn_mode == false then

      local strip = tracks[track_select].strip
      if strip and snapshots and snapshots[strip] and snapshots[strip][page][sstype_select] then

        local p
        local bbcol
        local morphing = false
        if #morph_data > 0 then
          for i = 1, #morph_data do
            if morph_data[i].strip == strip and
               morph_data[i].page == page and
               morph_data[i].sstype == sstype_select and
               morph_data[i].targetss == ss_select then
              if morph_data[i].active == true then
                morphing = true
                p = morph_data[i].psc
                local col = string.format('%i',math.floor(96*(1-p)))
                --local col = string.format('%i',math.floor(96+60*(p)))
                bbcol = col..' '..col..' '..col
              end
              break
            end
          end
        end

        if morphing == false then
          return
        end

        xywh = {x = obj.sections[163].x+2,
                y = obj.sections[163].y,
                w = obj.sections[163].w-4,
                h = butt_h--[[*pnl_scale]]}
        local ss
        if sstype_select == 1 then
          ss = snapshots[strip][page][sstype_select]
        else
          ss = snapshots[strip][page][sstype_select].snapshot
        end
        if SS_butt_cnt < #ss then
          xywh.w = xywh.w - sbobj.w
        end

        if #ss > 0 then
          for i = 1,SS_butt_cnt do

            xywh.y = obj.sections[163].y + i*(butt_h--[[*pnl_scale]])
            local c = gui.color.white
            if ss_select == ssoffset+i then
              if morphing == false then
                f_Get_SSV(gui.color.white)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w,
                 xywh.h-1, 1 )
                c = gui.color.black
              else
                f_Get_SSV(bbcol)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w,
                 xywh.h-1, 1 )
                f_Get_SSV(gui.color.white)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w*p,
                 xywh.h-1, 1 )
                c = gui.color.black
              end
              if ss[i+ssoffset] then
                GUI_textsm_LJ(gui,xywh,roundX(i+ssoffset,0)..': '..ss[i+ssoffset].name,c,-2 +(pnl_scale-1)*fontscale ,xywh.w)
              end
            end
          end

          if SS_butt_cnt < #ss then
            local msbh = sbobj.h
            local p1 = 1 / #ss
            local sbh = math.ceil(F_limit(p1*SS_butt_cnt * msbh,20,msbh))
            local p2 = p1*msbh
            local sby = math.floor(ssoffset * p2)
            GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
            if mouse.context == contexts.scrollsswin then
              GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
            end
          end
        end

        --[[if sstype_select == 1 then
          if #snapshots[strip][page][sstype_select] > 0 then
            for i = 1,SS_butt_cnt do

              xywh.y = obj.sections[163].y + i*(butt_h*pnl_scale)
              local c = gui.color.white
              if ss_select == ssoffset+i then
                if morphing == false then
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w,
                   xywh.h-1, 1 )
                  c = gui.color.black
                else
                  f_Get_SSV(bbcol)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w,
                   xywh.h-1, 1 )
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w*p,
                   xywh.h-1, 1 )
                  c = gui.color.black
                end
                if snapshots[strip][page][sstype_select][i+ssoffset] then
                  GUI_textsm_LJ(gui,xywh,roundX(i+ssoffset,0)..': '..snapshots[strip][page][sstype_select][i+ssoffset].name,c,-2 +(pnl_scale-1)*fontscale ,xywh.w)
                end
              end
            end
          end
        else

          if #snapshots[strip][page][sstype_select].snapshot > 0 then
            for i = 1,SS_butt_cnt do

              xywh.y = obj.sections[163].y + i*(butt_h*pnl_scale)
              local c = gui.color.white
              if ss_select == ssoffset+i then
                if morphing == false then
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w,
                   xywh.h-1, 1 )
                  c = gui.color.black
                else
                  f_Get_SSV(bbcol)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w,
                   xywh.h-1, 1 )
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y+1,
                   xywh.w*p,
                   xywh.h-1, 1 )
                  c = gui.color.black
                  if snapshots[strip][page][sstype_select].snapshot[i+ssoffset] then
                    GUI_textsm_LJ(gui,xywh,roundX(i+ssoffset,0)..': '..snapshots[strip][page][sstype_select].snapshot[i+ssoffset].name,c,-2 +(pnl_scale-1)*fontscale,xywh.w)
                  end
                end
              end
            end
          end

        end]]

      end
    end
  end

  function GUI_DrawSnapshots(obj, gui)

    gfx.dest = 1003

    gfx.a=1

    local butt_h = butt_h*pnl_scale

    --gfx.setimgdim(1003,-1,-1)
    Img_SetDim(1003,obj.sections[160].w,obj.sections[160].h)
    GUI_DrawPanel(obj.sections[160], nil, 'SNAPSHOTS')
    local b
    if settings_ssdock == true then
      b = gui.color.white
    else
      b = -5
    end
    GUI_DrawButton(gui, 'DOCK', obj.sections[1160], b, gui.skol.butt1_txt, true, '', false, -2, true)
    b = gui.color.white
    if sstype_select > 1 then
      GUI_DrawButton(gui, 'EDIT', obj.sections[1161], b, gui.skol.butt1_txt, true, '', false, -2, true)
    end

    local snaps
    if tracks[track_select] and tracks[track_select].strip and snapshots[tracks[track_select].strip] and
       snapshots[tracks[track_select].strip][page][sstype_select] then
      snaps = snapshots[tracks[track_select].strip][page][sstype_select]
    end

    local sstypestr = 'PAGE'
    if sstype_select > 1 then
      if snaps then
        sstypestr = snaps.subsetname
      else
        sstypestr = ''
      end
    end

    GUI_DrawButton(gui, sstypestr, obj.sections[161], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, '', obj.sections[168], gui.color.white, gui.skol.butt1_txt, true, '', false)
    local xywh = {x = obj.sections[168].x,
                  y = obj.sections[168].y+3,
                  w = obj.sections[168].w,
                  h = obj.sections[168].h}
    GUI_textC(gui,xywh,'*',gui.skol.butt1_txt,9)
    GUI_DrawButton(gui, 'RANDOMIZE', obj.sections[169], gui.color.white, gui.skol.butt1_txt, true, '', false)

    local txt = 'CAPTURE'
    if snaps then
      if snaps.ignorevals ~= true then
        if snaps.capturemods then
          txt = txt..' (+MOD)'
        end
        if snaps.capturefaders then
          txt = txt..' (+FB)'
        end
      else
        txt = ''
        if snaps.capturemods then
          txt = 'MODS'
        end
        if snaps.capturefaders then
          if txt ~= '' then
            txt = txt .. ' & '
          end
          txt = txt..'FADERS'
        end
        if txt == '' then
          txt = 'NOTHING TO CAPTURE'
        else
          txt = 'CAPTURE '..txt .. ' ONLY'
        end
      end
    end
    GUI_DrawButton(gui, txt, obj.sections[162], gui.color.white, gui.skol.butt1_txt, true, '', false)
    local bc = gui.color.white
    if lvar.livemode == 2 then
      bc = -1
    end
    GUI_DrawButton(gui, 'NEW SUBSET', obj.sections[166], bc, gui.skol.butt1_txt, true, '', false)
    local bc, bc2 = gui.color.white, gui.color.white
    if sstype_select == 1 then
      bc = -1
      bc2 = -1
    elseif snaplrn_mode then
      bc = -2
    end
    GUI_DrawButton(gui, 'RENAME SUB', obj.sections[164], bc2, gui.skol.butt1_txt, true, '', false)
    if lvar.livemode == 2 then
      bc = -1
    end
    GUI_DrawButton(gui, 'LEARN CTLS', obj.sections[167], bc, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'META LITE XY', obj.sections[224], bc2, gui.skol.butt1_txt, true, '', false)

    local mv = 0
    local sync = false
    local scale = 1
    if snaps then
      scale = snaps.morph_scale
      sync = snaps.morph_sync
      if sync == true then
        mv = lvar.sync_table[snaps.morph_syncv]
      else
        mv = round(nz(snaps.morph_time,0) * 100,3)
      end
    end
    if sync == false then
      if mv == nil or mv == 0 then
        t = 'INSTANT'
      else
        t = mv..'s'
      end
    else
      t = mv
    end
    GUI_DrawButton(gui, t, obj.sections[1010], gui.color.white, gui.skol.butt1_txt, true, '', false)
    if sync then
      bc = gui.color.white
    else
      bc = -1
    end
    GUI_DrawButton(gui, 'SYNC', obj.sections[1011], bc, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, lvar.macroscale_sm_table[scale], obj.sections[1012], gui.color.white, gui.skol.butt1_txt, true, '', false)

    xywh = {x = obj.sections[163].x,
            y = obj.sections[163].y,
            w = obj.sections[163].w,
            h = obj.sections[163].h}

    xywh.h = butt_h
    f_Get_SSV(gui.skol.ss_bg)
    gfx.a = 1
    gfx.rect(obj.sections[163].x-2,
             obj.sections[163].y-2,
             obj.sections[163].w+4,
             obj.sections[163].h, 1 )

    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[163].x-2,obj.sections[163].y-2+obj.sections[163].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[163].x-2+obj.sections[163].w+4-pnlcnr_w,obj.sections[163].y-2+obj.sections[163].h-pnlcnr_h)
    end

    GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
    gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
    --gfx.triangle(xywh.x+xywh.w/4,xywh.y+4,xywh.x+xywh.w/4-6,xywh.y+xywh.h-4,xywh.x+xywh.w/4+6,xywh.y+xywh.h-4,1)
    --gfx.triangle(xywh.x+xywh.w*0.75,xywh.y+xywh.h-4,xywh.x+xywh.w*0.75-6,xywh.y+4,xywh.x+xywh.w*0.75+6,xywh.y+4,1)
    local w, h = gfx.getimgdim(skin.arrowup)
    gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
    gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)


    xywh.x = xywh.x + 2
    xywh.w = xywh.w - 4

    gfx.a = 1

    local pause = false
    local dir = '>'
    local txt = 'LOOP'
    local loop = false

    SS_butt_cnt = math.floor(obj.sections[163].h / butt_h) - 1
    local sbobj = obj.sections[1016]

    --if snaplrn_mode == false then

      local strip = tracks[track_select].strip
      if snaps then

        local morphing = false
        local p, bbcol
        if #morph_data > 0 then
          for i = 1, #morph_data do
            if morph_data[i].strip == strip and
               morph_data[i].page == page and
               morph_data[i].sstype == sstype_select and
               morph_data[i].targetss == ss_select then
              if morph_data[i].active == true then
                morphing = true
                if morph_data[i].paused then
                  pause = true
                end
                if morph_data[i].dir == 1 then
                  dir = '<'
                end
                p = morph_data[i].psc
                local col = string.format('%i',math.floor(96*(1-p)))
                bbcol = col..' '..col..' '..col
              end
              break
            end
          end
        end

        loop = snaps.morph_loop
        if loop == 2 then
          txt = dir..dir
          loop = true
        elseif loop == 3 then
          txt = '<>'
          loop = true
        elseif loop == 4 then
          txt = '>> N'
          loop = true
        elseif loop == 5 then
          txt = '>> R'
          loop = true
        else
          loop = false
        end

        local ss
        if sstype_select == 1 then
          ss = snaps
        else
          ss = snaps.snapshot
        end
        if SS_butt_cnt < #ss then
          xywh.w = xywh.w - sbobj.w
        end

        if #ss > 0 then
          for i = 1,SS_butt_cnt do

            xywh.y = obj.sections[163].y + i*butt_h
            local c = gui.skol.ss_txt
            if ss_select == ssoffset+i then
              if morphing == false then
                f_Get_SSV(gui.skol.lst_barhl)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w,
                 xywh.h-1, 1 )
                c = gui.skol.lst_txthl
              else
                f_Get_SSV(bbcol)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w,
                 xywh.h-1, 1 )
                f_Get_SSV(gui.skol.lst_barhl)
                gfx.rect(xywh.x,
                 xywh.y+1,
                 xywh.w*p,
                 xywh.h-1, 1 )
                c = gui.skol.lst_txthl
              end
            end
            if ss[i+ssoffset] then
              GUI_textsm_LJ(gui,xywh,roundX(i+ssoffset,0)..': '..ss[i+ssoffset].name,c,-2 +(pnl_scale-1)*fontscale,xywh.w)
            end

            if snap_move and snap_move.epos == i+ssoffset and snap_move.epos ~= snap_move.spos and snap_move.epos ~= snap_move.spos+1 then
              f_Get_SSV(gui.color.red)
              gfx.rect(xywh.x,
               xywh.y-1,
               xywh.w,
               2, 1)
            end
          end

          if SS_butt_cnt < #ss then
            local msbh = sbobj.h
            local p1 = 1 / #ss
            local sbh = math.ceil(F_limit(p1*SS_butt_cnt * msbh,20,msbh))
            local p2 = p1*msbh
            local sby = math.floor(ssoffset * p2)
            GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
            if mouse.context == contexts.scrollsswin then
              GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
            end

          end
        end


      end

      if pause then
        bc = -2
      else
        bc = -1
      end
      GUI_DrawButton(gui, 'PAUSED', obj.sections[1013], bc, gui.skol.butt1_txt, true, '', false)

      local btc = gui.color.white
      local ctc = gui.color.white
      if snaps then
        if snaps.stages and snaps.stages > 1 then
          if snaps.morph_loop == 3 then
            btc = -2
            ctc = -2
          elseif snaps.morph_loop ~= 1 then
            ctc = -2
          end
        end
      end

      GUI_DrawButton(gui, dir, obj.sections[1014], ctc, gui.skol.butt1_txt, true, '', false)
      if loop then
        bc = gui.color.white
      else
        bc = -1
      end
      if btc ~= gui.color.white then
        bc = btc
      end
      GUI_DrawButton(gui, txt, obj.sections[1015], bc, gui.skol.butt1_txt, true, '', false)


    --else
      --learn mode

    --end

    gfx.dest = 1
  end

  function GUI_DrawFSnapshots(obj, gui)

    gfx.dest = 1005
    local w, h = gfx.getimgdim(1005)
    if obj.sections[180].w ~= w then
      Img_SetDim(1005, obj.sections[180].w, h, true)
    end

    gfx.a=1
    f_Get_SSV(gui.color.black)
    gfx.rect(0,
             0,
             obj.sections[180].w,
             obj.sections[180].h, 1, 1)
    f_Get_SSV('8 8 8')
    --[[gfx.rect(0,
             0,
             obj.sections[180].w,
             obj.sections[180].h, 0, 1)
    ]]
    f_Get_SSV(fsstype_color)
    gfx.a = 1
    gfx.rect(obj.sections[182].x,
             obj.sections[182].y,
             obj.sections[182].w,
             obj.sections[182].h, 1 )


    xywh = {x = obj.sections[181].x,
            y = obj.sections[181].y,
            w = obj.sections[181].w,
            h = obj.sections[181].h}
    --f_Get_SSV('64 64 64')
    f_Get_SSV(settings_snaplistbgcol)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )
    f_Get_SSV('64 64 64')
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 0 )

    xywh.h = butt_h+1
    gfx.rect(xywh.x,
     xywh.y-1,
     xywh.w,
     xywh.h, 1 )
    gfx.a = 0.5
    f_Get_SSV(gui.color.black)
    gfx.a = 1
    gfx.rect(xywh.x,xywh.y+xywh.h-1,xywh.x+xywh.w,2)
    gfx.rect(xywh.x+xywh.w/2,
     xywh.y-1,
     2,
     xywh.h, 1 )
    gfx.triangle(xywh.x+xywh.w/4,xywh.y+4,xywh.x+xywh.w/4-6,xywh.y+xywh.h-4,xywh.x+xywh.w/4+6,xywh.y+xywh.h-4,1)
    gfx.triangle(xywh.x+xywh.w*0.75,xywh.y+xywh.h-4,xywh.x+xywh.w*0.75-6,xywh.y+4,xywh.x+xywh.w*0.75+6,xywh.y+4,1)

    gfx.a = 1

    FSS_butt_cnt = math.floor(obj.sections[181].h / butt_h) - 1
    if snaplrn_mode == false then

      local strip = tracks[track_select].strip
      if strip and snapshots and snapshots[strip] and snapshots[strip][page][fsstype_select] then

        if fsstype_select == 1 then
          if #snapshots[strip][page][fsstype_select] > 0 then
            for i = 1,FSS_butt_cnt do

              xywh.y = obj.sections[181].y + i*butt_h
              local c = fsstype_color
              if fss_select == fssoffset+i then
                f_Get_SSV(fsstype_color)
                gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )
                c = settings_snaplistbgcol
              end
              if snapshots[strip][page][fsstype_select][i+fssoffset] then
                GUI_textsm_LJ(gui,xywh,roundX(i+fssoffset,0)..': '..snapshots[strip][page][fsstype_select][i+fssoffset].name,c,-2,xywh.w)
              end

            end

          end
        elseif fsstype_select > 1 then
          if #snapshots[strip][page][fsstype_select].snapshot > 0 then
            for i = 1,FSS_butt_cnt do

              xywh.y = obj.sections[181].y + i*butt_h
              local c = fsstype_color
              if fss_select == fssoffset+i then
                f_Get_SSV(fsstype_color)
                gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )
                c = settings_snaplistbgcol
              end
              if snapshots[strip][page][fsstype_select].snapshot[i+fssoffset] then
                GUI_textsm_LJ(gui,xywh,roundX(i+fssoffset,0)..': '..snapshots[strip][page][fsstype_select].snapshot[i+fssoffset].name,c,-2,xywh.w)
              end

            end

          end

        end

      end
    end

    gfx.dest = 1
  end

  ------------------------------------------------------------

  function GUI_DrawActionChooser(obj, gui)

    gfx.a=1
    f_Get_SSV(gui.color.black)
    gfx.rect(obj.sections[170].x,
             obj.sections[170].y,
             obj.sections[170].w,
             obj.sections[170].h, 1, 1)
    f_Get_SSV('64 64 64')
    gfx.rect(obj.sections[170].x,
             obj.sections[170].y,
             obj.sections[170].w,
             obj.sections[170].h, 0, 1)

    xywh = {x = obj.sections[170].x,
            y = obj.sections[170].y,
            w = obj.sections[170].w,
            h = butt_h}

    f_Get_SSV(gui.color.white)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             butt_h, 1)
    gfx.rect(obj.sections[171].x,
             obj.sections[171].y,
             obj.sections[171].w,
             obj.sections[171].h, 0)

    GUI_textC(gui,xywh,'CUSTOM ACTION CHOOSER',gui.color.black,-2)

    AL_butt_cnt = math.floor((obj.sections[171].h) / butt_h)-1
    xywh = {x = obj.sections[171].x+2,
            y = obj.sections[171].y,
            w = obj.sections[171].w-4,
            h = butt_h}

    for i = 1, AL_butt_cnt+1 do

      if action_tblF[i+al_offset] then

        xywh.y = obj.sections[171].y + butt_h*(i-1)
        local c = gui.color.white
        if al_select == i+al_offset then

          f_Get_SSV(gui.color.white)
          gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   butt_h, 1)
          c = gui.color.black

        end

        GUI_textsm_LJ(gui,xywh,action_tblF[i+al_offset].command_desc,c,-2,obj.sections[171].w-4)

      end

    end

    GUI_DrawButton(gui, 'FILTER ACTION LIST', obj.sections[172], gui.color.white, gui.color.black, true, '', false)
    GUI_DrawButton(gui, 'CLEAR FILTER', obj.sections[173], gui.color.white, gui.color.black, true, '', false)
    GUI_DrawButton(gui, 'SELECT', obj.sections[174], gui.color.white, gui.color.black, true, '', false)
    GUI_DrawButton(gui, 'CANCEL', obj.sections[175], gui.color.white, gui.color.black, true, '', false)

  end

  ------------------------------------------------------------
  --[[function PopulateCtlBrowser_Imgs()

    cbi = {}
    local icnt = ctl_browser_image+1
    local it = 0
    cbi_cnt = 0
    local cbof = 0
    for i = 0, #ctl_files do
      if ctl_files[i].ctltype == cbi_filter or cbi_filter == -1 then
        cbi_cnt = cbi_cnt + 1
      end
      if cbi_cnt == cbi_offset then
        cbof = i+1
      end
    end

    for i = 0, math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y-1,maximg_browse) do

      local fnd = false

      repeat

        local ii = cbof + i + it

        if ctl_files[ii] then


          if cbi_filter == -1 or ctl_files[ii].ctltype == cbi_filter then

            fnd = true
            cbi[i] = {idx = ii,
                      fn = ctl_files[ii].fn,
                      imageidx = ctl_files[ii].imageidx,
                      cellh = ctl_files[ii].cellh,
                      frames = ctl_files[ii].frames,
                      ctltype = ctl_files[ii].ctltype}

            if cbi[i].imageidx ~= nil then
              --iidx = cbi[i].imageidx
            else
              gfx.loadimg(icnt, paths.controls_path..cbi[i].fn)
              cbi[i].imageidx = icnt
              icnt = icnt + 1
            end
          else
            it = it + 1
          end
        else
          cbi[i] = nil
          gfx.loadimg(icnt,'')
          fnd = true
        end

      until fnd == true

    end


  end]]

  function SetCbiSelect()

    local ii = cbi_select
    if ctl_files[ii] then

      cbi_select_inf = {idx = ii,
                        fn = ctl_files[ii].fn,
                        imageidx = ctl_files[ii].imageidx,
                        cellh = ctl_files[ii].cellh,
                        frames = ctl_files[ii].frames,
                        ctltype = ctl_files[ii].ctltype}
      if cbi_select_inf.imageidx ~= nil then
      else
        gfx.loadimg(991, paths.controls_path..ctl_files[ii].fn)
        cbi_select_inf.imageidx = 991
      end
    end
  end

  function CB_SaveFavs()

    local favs = lvar.ctlbrowserfavs
    local savestr = ''
    for i = 1, lvar.ctlbrowserfavs_max do
      if favs[i] and (#favs[i] > 0 or favs[i].name) then
        if favs[i].name then
          local key = '['..i..'_name]'
          savestr = savestr .. key .. favs[i].name ..'\n'
        end
        for ii = 1, #favs[i] do
          local key = '['..i..'_'..ii..']'
          savestr = savestr .. key .. favs[i][ii].fn ..'\n'
        end
      end
    end
    local fn = paths.resource_path..'cbfavs.txt'
    local file = io.open(fn,'w')
    if file then
      file:write(savestr)
      file:close()
    end
  end

  function CB_LoadFavs()

    local favs = lvar.ctlbrowserfavs

    local fn = paths.resource_path..'cbfavs.txt'
    local file = io.open(fn,'r')
    if file then
      local datastr = file:read("*a")
      file:close()

      local data = {}
      local cnt = 0
      local lines = splitln(datastr)
      if lines and #lines > 0 then
        for ln = 1, #lines do
          local idxA, idxB, val = string.match(lines[ln],'%[(%d+)%_(%d+)%](.*)')
          if val then
            idxA = tonumber(idxA)
            idxB = tonumber(idxB)

            if not favs[idxA] then
              favs[idxA] = {}
            end
            favs[idxA][idxB] = {fn = val}

          else
            local idxA, val = string.match(lines[ln],'%[(%d+)%_name%](.*)')
            if val then
              idxA = tonumber(idxA)
              if not favs[idxA] then
                favs[idxA] = {}
              end
              favs[idxA].name = val
            end
          end
        end
      end
    end

    return favs
  end

  function PopulateCtlBrowser_Cbi()

    cbi = {}
    local cbicnt = 0
    if cbi_filter ~= -2 then
      for i = 0, #ctl_files do
        if cbi_filter ~= 5 then
          if ctl_files[i].ctltype == cbi_filter or cbi_filter == -1 then
            cbi[cbicnt] = {idx = i,
                          fn = ctl_files[i].fn,
                          imageidx = ctl_files[i].imageidx,
                          cellh = ctl_files[i].cellh,
                          frames = ctl_files[i].frames,
                          ctltype = ctl_files[i].ctltype}
            cbicnt = cbicnt + 1
          end
        else
          if ctl_files[i].ctltype == 5 or ctl_files[i].ctltype == 6 or ctl_files[i].ctltype == 7 then
            cbi[cbicnt] = {idx = i,
                          fn = ctl_files[i].fn,
                          imageidx = ctl_files[i].imageidx,
                          knbsz = ctl_files[i].knbsz,
                          cellh = ctl_files[i].cellh,
                          frames = ctl_files[i].frames,
                          ctltype = ctl_files[i].ctltype}
            cbicnt = cbicnt + 1
          end
        end

      end
    else
      --favs
      local sel = lvar.ctlbrowserfav_select
      local favs = lvar.ctlbrowserfavs
      if favs[sel] and #favs[sel] > 0 then
        local fidx = lvar.ctlfiles_idx
        --[[for i = 0, #ctl_files do
          fidx[ctl_files[i].fn] = i
        end]]

        for fi = 1, #favs[sel] do
          local i = fidx[favs[sel][fi].fn]
          if i then
            cbi[cbicnt] = {idx = i,
                          fn = ctl_files[i].fn,
                          imageidx = ctl_files[i].imageidx,
                          knbsz = ctl_files[i].knbsz,
                          cellh = ctl_files[i].cellh,
                          frames = ctl_files[i].frames,
                          ctltype = ctl_files[i].ctltype}
            cbicnt = cbicnt + 1
          end
        end
      end
    end
    if cbicnt ~= 0 then
      lvar.cbi_loaded = true
    end
  end

  function GUI_DrawCtlBrowserCtls(obj, gui)

    gfx.dest = 905

    --gfx.setimgdim(905, -1, -1)
    Img_SetDim(905, obj.sections[210].w, obj.sections[210].h)

    --local p = math.floor(cbi_offset / (ctl_browser_size.slots_x*ctl_browser_size.slots_y))+1
    for cg = 0, ctl_browser_size.slots_x*ctl_browser_size.slots_y-1 do
      local i = cbi_offset + cg
      if cbi[i] then

        iidx = cbi[i].imageidx
        if iidx == nil then
          iidx = 989
          gfx.loadimg(iidx, paths.controls_path..cbi[i].fn)
        end

        local w, _ = gfx.getimgdim(iidx)
        local h = cbi[i].cellh
        gfx.a = 1
        local scale_select = 1
        xywh = {x = (cg % ctl_browser_size.slots_x)*ctl_browser_size.slotsz,
                y = math.floor(cg / ctl_browser_size.slots_x)*ctl_browser_size.slotsz,
                w = ctl_browser_size.slotsz,
                h = ctl_browser_size.slotsz}
        if w > h then
          if w > ctl_browser_size.slotsz then
            scale_select = ctl_browser_size.slotsz / w
          end
        else
          if h > ctl_browser_size.slotsz then
            scale_select = ctl_browser_size.slotsz / h
          end
        end
        gfx.blit(iidx,scale_select,0, 0, h*math.ceil((cbi[i].frames-1)*0.55), w, h,
                 math.floor(xywh.x + (xywh.w/2-(w*scale_select)/2)), math.floor(xywh.y + ((xywh.h - (h*scale_select))/2)))

      end
    end

    gfx.dest = 1

  end

  function GUI_DrawCtlBrowser(obj, gui)

    gfx.a=1

    local favs = lvar.ctlbrowserfavs
    local sel = lvar.ctlbrowserfav_select

    local txt = ''
    local bidx
    if cbi_filter ~= -2 then
      bidx = lvar.ctlbrowserbutt_transtable[cbi_filter+2]
      txt = lvar.ctlbrowserbutt_table[bidx]
    else
      bidx = sel+ #lvar.ctlbrowserbutt_transtable
      if favs[sel] then
        txt = favs[sel].name or ('USER SET '..string.format('%i',sel))
      else
        txt = ('USER SET '..string.format('%i',sel))
      end
    end

    local b
    if lvar.ctlbrowser_docked then
      GUI_DrawPanel(obj.sections[200],true,'CTL BROWSER')
      b = gui.color.white
    else
      GUI_DrawPanel(obj.sections[200],true,'CTL BROWSER  -  '..(txt or ''),true)
      b = -5
    end
    GUI_DrawButton(gui, 'DOCK', obj.sections[237], b, gui.skol.butt1_txt, true, '', false, -2, true)
    
    if not lvar.cbi_loaded then
      PopulateCtlBrowser_Cbi()
      GUI_DrawCtlBrowserCtls(obj, gui)
      cbi_select = knob_select
      SetCbiSelect()
      --lupd.update_surface = true
    end

    f_Get_SSV('16 16 16')
    local xywh = {x = obj.sections[210].x-2,
                  y = obj.sections[210].y-2,
                  w = obj.sections[210].w+4,
                  h = obj.sections[210].h+4}
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1, 1)
    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w,xywh.y)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x,xywh.y+xywh.h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,xywh.x+xywh.w-pnlcnr_w,xywh.y+xywh.h-pnlcnr_h)
    end

    local p = lvar.ctlbrowser_offs
    --lvar.ctlbrowserbutt_table
    local slh = math.floor(lvar.ctlbrowser_btnh*pnl_scale)
    local buttslots = math.floor(obj.sections[209].h / slh)
    local xywh = {x = obj.sections[209].x,
                  y = obj.sections[209].y,
                  w = obj.sections[209].w,
                  h = slh}
    for i = 1, buttslots do
      if p+i > lvar.ctlbrowserfavs_max+#lvar.ctlbrowserbutt_table then break end

      local tc = gui.skol.butt1_txt
      local txt
      local bc = gui.color.white
      if p+i <= #lvar.ctlbrowserbutt_table then
        if p+i == bidx then
          bc = -4
        end
        txt = lvar.ctlbrowserbutt_table[p+i]
      else
        local idx = p+i - (#lvar.ctlbrowserbutt_table)
        bc = -6
        if favs[idx] then
          txt = favs[idx].name or ('USER SET '..string.format('%i',idx))
          if #favs[idx] > 0 then
            bc = gui.color.white
            if p+i == bidx then
              bc = -4
            end
          elseif p+i == bidx then
            bc = -4
          end
        else
          txt = ('USER SET '..string.format('%i',idx))
          if p+i == bidx then
            bc = -4
          end
        end
      end
      if bc == -6 then
        GUI_DrawButton(gui, txt, xywh, bc, '128 128 128', true, '', false)
      else
        GUI_DrawButton(gui, txt, xywh, bc, tc, true, '', false)
      end
      xywh.y = xywh.y + slh
    end

    --gfx.rect(obj.sections[209].x,obj.sections[209].y,obj.sections[209].w,obj.sections[209].h,0,1)

    --[[GUI_DrawButton(gui, 'ALL', obj.sections[201], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'KNOBS', obj.sections[202], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'SLIDERS', obj.sections[203], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'SLIDERS X', obj.sections[204], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'BUTTONS', obj.sections[205], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'METERS', obj.sections[206], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, 'MISC', obj.sections[207], gui.color.white, gui.skol.butt1_txt, true, '', false)]]

    --local txt
    --if favs[sel] then
    --  txt = favs[sel].name
    --end
    --GUI_DrawButton(gui, (txt or ('FAV SET '..lvar.ctlbrowserfav_select)), obj.sections[208], gui.color.white, gui.skol.butt1_txt, true, '', false)

    GUI_DrawButton(gui, '<<', obj.sections[211], gui.color.white, gui.skol.butt1_txt, true, '', false)
    GUI_DrawButton(gui, '>>', obj.sections[212], gui.color.white, gui.skol.butt1_txt, true, '', false)


    xywh = {x = obj.sections[212].x+obj.sections[212].w+20,
            y = obj.sections[212].y,
            w = 20,
            h = butt_h}
    local p = math.floor(cbi_offset / math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y,maximg_browse))+1
    local p2 = math.floor(#cbi / math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y,maximg_browse))+1
    GUI_textsm_LJ(gui,xywh,'PAGE '..p..'/'..p2,gui.color.white,-2)

    gfx.blit(905,1,0, 0, 0, obj.sections[210].w, obj.sections[210].h, obj.sections[210].x, obj.sections[210].y)

    for cg = 0, ctl_browser_size.slots_x*ctl_browser_size.slots_y-1 do
      local ii = cbi_offset+cg
      if cbi[ii] then
        --DBG(ii..'  '..cbi_select)
        if cbi[ii].idx == cbi_select then

          xywh = {x = obj.sections[210].x + (cg % ctl_browser_size.slots_x)*ctl_browser_size.slotsz,
                  y = obj.sections[210].y + math.floor(cg / ctl_browser_size.slots_x)*ctl_browser_size.slotsz,
                  w = ctl_browser_size.slotsz,
                  h = ctl_browser_size.slotsz}
          gfx.a = 0.75

          f_Get_SSV(gui.color.yellow)
          gfx.roundrect(math.floor(xywh.x+1),
                   math.floor(xywh.y),
                   math.floor(xywh.w-2),
                   math.floor(xywh.h),8,0,1)
        --GUI_textC(gui,xywh,ctl_files[cg].fn,gui.color.white,-5)]]
        end

      else
        break
      end
    end

    gfx.a = 1
    if cbi_select_inf and cbi_select_inf.imageidx then
      local scale_selecta, scale_selectb = 1,1
      local w, _ = gfx.getimgdim(cbi_select_inf.imageidx)
      local h = cbi_select_inf.cellh
      if w > obj.sections[213].w then
        scale_selecta = obj.sections[213].w / w
      end
      if h > obj.sections[213].h then
        scale_selectb = obj.sections[213].h / h
      end
      local scale_select = F_limit(math.min(scale_selecta,scale_selectb),0,1)

      local xywh = {x = obj.sections[213].x,
                    y = obj.sections[213].y,
                    w = obj.sections[213].w,
                    h = butt_h}
      if xywh.y + h*scale_select > obj.sections[200].y + obj.sections[200].h then
        xywh.y = obj.sections[200].y + obj.sections[200].h - h*scale_select-2
      end
      if xywh.y < obj.sections[200].y + obj.sections[200].h then
        gfx.blit(cbi_select_inf.imageidx,scale_select,0, 0, h*math.ceil((cbi_select_inf.frames-1)*0.55), w, h,
                 xywh.x + (xywh.w/2-(w*scale_select)/2), xywh.y)-- + ((obj.sections[213].h/2) - (h*scale_select))/2)
      end

      local xywh = {x = obj.sections[213].x,
                    y = math.max(obj.sections[213].y-butt_h*6, obj.sections[209].y+obj.sections[209].h+10),
                    w = obj.sections[213].w,
                    h = butt_h}
      GUI_Str(gui,xywh,cbi_select_inf.fn,4,gui.color.white,-5,1,gui.color.black)
      --GUI_textsm_LJ(gui,xywh,cbi_select_inf.fn,gui.color.white,-5,xywh.w)
      xywh.y = xywh.y + butt_h
      GUI_Str(gui,xywh,'W = '..w,4,gui.color.white,-5,1,gui.color.black)
      --GUI_textsm_LJ(gui,xywh,'W = '..w,gui.color.white,-5,xywh.w)
      xywh.y = xywh.y + butt_h
      GUI_Str(gui,xywh,'H = '..h,4,gui.color.white,-5,1,gui.color.black)
      --GUI_textsm_LJ(gui,xywh,'H = '..h,gui.color.white,-5,xywh.w)
      xywh.y = xywh.y + butt_h
      GUI_Str(gui,xywh,'Frames = '..cbi_select_inf.frames,4,gui.color.white,-5,1,gui.color.black)
      --GUI_textsm_LJ(gui,xywh,'Frames = '..cbi_select_inf.frames,gui.color.white,-5,xywh.w)
      xywh.y = xywh.y + butt_h
      GUI_Str(gui,xywh,'Type = '..lvar.ctlfile_type_table[cbi_select_inf.ctltype+1],4,gui.color.white,-5,1,gui.color.black)
      --GUI_textsm_LJ(gui,xywh,'Type = '..lvar.ctlfile_type_table[cbi_select_inf.ctltype+1],gui.color.white,-5,xywh.w)
      --xywh.y = xywh.y + butt_h

    end

  end



  ------------------------------------------------------------

  function GUI_DrawMsgX(obj, gui, txt, c, max, bar)

    gfx.mode = gmode
    if gui == nil then
      gui = GetGUI_vars()
    end

    local msgwinw, msgwinh = 500, 200
    xywh1 = {x = gfx1.main_w/2-msgwinw/2,
              y = gfx1.main_h/2-msgwinh/2,
              w = msgwinw,
              h = msgwinh}
    xywh2 = {x = gfx1.main_w/2-msgwinw/2,
              y = gfx1.main_h/2-msgwinh/2 + butt_h*2,
              w = msgwinw,
              h = butt_h}

    xywh3 = {x = gfx1.main_w/2-msgwinw/2 + 20,
              y = gfx1.main_h/2-msgwinh/2 + butt_h*4,
              w = msgwinw-40,
              h = butt_h}

    gfx.dest = 1
    f_Get_SSV('0 0 0')
    gfx.a = 1
    gfx.rect(xywh1.x,
             xywh1.y,
             xywh1.w,
             xywh1.h, 1)
    f_Get_SSV(gui.color.white)
    gfx.rect(xywh1.x,
             xywh1.y,
             xywh1.w,
             xywh1.h, 0)
    GUI_textC(gui,xywh2,nz(txt,''),gui.color.white,-2)

    if c and max then

      gfx.rect(xywh3.x,
               xywh3.y,
               xywh3.w,
               xywh3.h, 0)
      xywh3.w = (c/max)*xywh3.w
      gfx.rect(xywh3.x,
               xywh3.y,
               xywh3.w,
               xywh3.h, 1)
      xywh3.w = msgwinw
      GUI_textC(gui,xywh3,string.format('%i',round((c/max)*100))..'%',gui.color.black,-2)
      xywh3.x = xywh3.x + 1
      xywh3.y = xywh3.y + 1
      GUI_textC(gui,xywh3,string.format('%i',round((c/max)*100))..'%',gui.color.white,-2)
    elseif bar then


      local t = (reaper.time_precise()*1000) % 2000
      gfx.rect(xywh3.x,
               xywh3.y,
               xywh3.w,
               xywh3.h, 0)
      local lw = math.floor((t/2000)*(xywh3.w-100))
      gfx.rect(xywh3.x+lw,
               xywh3.y,
               100,
               xywh3.h, 1)

    end

    gfx.dest = -1
    gfx.a = 1
    gfx.blit(1, 1, 0,
      0,0, gfx1.main_w,gfx1.main_h,
      0,0, gfx1.main_w,gfx1.main_h, 0,0)
    gfx.update()

  end

  function GUI_DrawStateWin(obj, gui, txt, reset)

    gfx.mode = gmode
    if gui == nil then
      gui = GetGUI_vars()
    end

    DBGOut(txt)

    local lineh = 20
    if reset or statewin_txtpos == nil then
      statewin_txtpos = -1
    end
    statewin_txtpos = statewin_txtpos + 1

    local msgwinw, msgwinh = obj.sections[10].w - 100 - obj.sections[10].x, math.floor((obj.sections[10].h-100) / lineh) * lineh
    xywh1 = {x = math.floor(gfx1.main_w/2-msgwinw/2),
              y = math.floor(gfx1.main_h/2-msgwinh/2),
              w = msgwinw,
              h = msgwinh}
    xywh2 = {x = math.floor(gfx1.main_w/2-msgwinw/2),
              y = math.floor(gfx1.main_h/2-msgwinh/2+lineh),
              w = msgwinw,
              h = msgwinh-lineh-1}

    xywh3 = {x = math.floor(gfx1.main_w/2-msgwinw/2+5),
              y = math.floor(gfx1.main_h/2-msgwinh/2 +math.min(statewin_txtpos*lineh,msgwinh-lineh)),
              w = msgwinw-10,
              h = lineh}

    gfx.dest = 1
    if reset then
      f_Get_SSV('0 0 0')
      gfx.a = 1
      gfx.rect(xywh1.x,
               xywh1.y,
               xywh1.w,
               xywh1.h, 1)
    end
    if statewin_txtpos*lineh > msgwinh-lineh then
      gfx.blit(1,1,0,xywh2.x,xywh2.y,xywh2.w,xywh2.h,xywh1.x,xywh1.y)
      f_Get_SSV('0 0 0')
      gfx.a = 1
      gfx.rect(xywh3.x,
               xywh3.y,
               xywh3.w,
               xywh3.h, 1)
    end
    GUI_textsm_LJ(gui,xywh3,nz(txt,''),'180 180 180',-2,msgwinw-10)

    f_Get_SSV(gui.color.white)
    gfx.rect(xywh1.x,
             xywh1.y,
             xywh1.w,
             xywh1.h, 0)

    gfx.dest = -1
    gfx.a = 1
    gfx.blit(1, 1, 0,
      0,0, gfx1.main_w,gfx1.main_h,
      0,0, gfx1.main_w,gfx1.main_h, 0,0)
    gfx.update()

  end

  function calc_eqgraph_getmin(tr, fx, param, freq)

    if param then
      local sldiv = 40
      local track = GetTrack(tr)
      local bkp = reaper.TrackFX_GetParamNormalized(track, fx, param)
      reaper.TrackFX_SetParamNormalized(track, fx, param, 0)
      local del = 0
      os.sleep(auto_delay/sldiv)
      local _, d = reaper.TrackFX_GetFormattedParamValue(track, fx, param, '')
      local mult = 1
      if freq then
        local s = string.find(string.lower(d), 'k')
        if s and s>0 then mult = 1000 end
      end
      if d and d~= '' then
        rd = tonumber(GetNumericPart(d))
        if rd then rd = rd * mult else rd = d end

        reaper.TrackFX_SetParamNormalized(track, fx, param, bkp)
      end
      return rd
    end

  end

  function calc_eqgraph_getmax(tr, fx, param, freq)

    if param then
      local sldiv = 40
      local track = GetTrack(tr)
      local bkp = reaper.TrackFX_GetParamNormalized(track, fx, param)
      reaper.TrackFX_SetParamNormalized(track, fx, param, 1)
      local del = 0
      os.sleep(auto_delay/sldiv)
      local _, d = reaper.TrackFX_GetFormattedParamValue(track, fx, param, '')
      local mult = 1
      if freq then
        local s = string.find(string.lower(d), 'k')
        if s and s>0 then mult = 1000 end
      end
      if d and d~= '' then
        rd = tonumber(GetNumericPart(d))
        if rd then rd = rd * mult else rd = d end

        reaper.TrackFX_SetParamNormalized(track, fx, param, bkp)
      end
      return rd
    end

  end

  function calc_eqgraph(tr, fx, param, min, max, khz, param2, min2, max2)

    --local ad = auto_delay*100000
    local track = GetTrack(tr)
    --pixmap = {}
    local lookmap = {}
    local gmap = {}
    local mult = 1
    local sldiv = 400
    if khz then
      mult = 1000
      min = min * mult
      max = max * mult
    end
    if min == 0 then min = 10 end
    --if min2 == 0 then min2 = 10 end

    local inc = math.min(10^math.floor(math.log(min,10)),1000)
    local look = (math.floor(min/inc)+1)*inc
    --local look = min
    local inc2 = 3
    local look2 = min2
    if param then
      bkp = reaper.TrackFX_GetParam(track, fx, param)
      reaper.TrackFX_SetParam(track, fx, param, 0)
    end
    if param2 then
      bkp2 = reaper.TrackFX_GetParamNormalized(track, fx, param2)
      reaper.TrackFX_SetParamNormalized(track, fx, param2, 0)
    end
    local del = 0
    --for dx = 1, ad do del = del + 1 end
    os.sleep((auto_delay/sldiv)*10)
    local fnd, fnd2 = false, false

    for p = 0, 2010 do
      GUI_DrawMsgX(obj, gui, 'Calculating Graph Data...',p,2000)
      local pp = p/(2000)
      if param then
        reaper.TrackFX_SetParamNormalized(track, fx, param, pp)
      end
      if param2 then
        reaper.TrackFX_SetParamNormalized(track, fx, param2, pp)
      end
      os.sleep(auto_delay/sldiv)
      local d, d2
      if param then
        _, d = reaper.TrackFX_GetFormattedParamValue(track, fx, param, '')
      end
      if param2 then
        _, d2 = reaper.TrackFX_GetFormattedParamValue(track, fx, param2, '')
      end

      if not khz then
        local s = string.find(string.lower(d), 'k')
        if s and s>0 then mult = 1000 end
      end
      d = tonumber(GetNumericPart(nz(d,'')))*mult

      if d and d >= look and not fnd then
        lookmap[#lookmap+1] = {pix = math.min(p,2000),
                               hz = look}

        if look >= max then fnd = true end

        local inc = math.min(10^math.floor(math.log(look,10)),1000)
        look = look + inc
      end

      d2 = tonumber(GetNumericPart(nz(d2,'')))

      if tonumber(look2) == nil then
        if d2 then look2 = d2 end
      else
        if d2 and d2 >= look2 and not fnd2 then
          gmap[#gmap+1] = {pix = math.min(p,2000),
                           db = look2}
          if look2 >= max2 then fnd2 = true end
          look2 = math.floor((look2 + inc2)/inc2)*inc2
          if look2 > max2 then look2 = max2 end
        end
      end
    end
    if param then
      reaper.TrackFX_SetParamNormalized(track, fx, param, bkp)
    end
    if param2 then
      reaper.TrackFX_SetParamNormalized(track, fx, param2, bkp2)
    end

    return lookmap, gmap
  end

  function logspace(start, stop, n, N)
    if n and stop and N then
    return math.log(n,10)*(N/math.log(stop,10))
    end
    --return math.log(1+(n/stop)*400,10) * N
  end

  function logspaceinv(start, stop, v, N)
    return 10^(v / (N/math.log(stop,10)))
    --return ((((10^(v/N)) / 400.0) * stop) -1.0)
  end

  function GUI_DrawEQBands(obj, gui)

    local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
    if bands then

      for bb = 1, #bands+1 do

        if bb ~= eqcontrolband_select then
          local b = bb
          if b == #bands+1 then
            b = eqcontrolband_select
          end

          if bands[b] and (eq_single == false or b == eqcontrolband_select) then
            local track = GetTrack(tracks[track_select].tracknum)

            local pmin = bands[b].posmin
            local pmax = bands[b].posmax
            local gmin = bands[b].gmin
            local gmax = bands[b].gmax
            local fxnum = bands[b].fxnum
            local freq_param = bands[b].freq_param
            local khz = bands[b].khz
            local gain_param = bands[b].gain_param
            local q_param = bands[b].q_param
            local c1_param = bands[b].c1_param
            local c2_param = bands[b].c2_param
            local c3_param = bands[b].c3_param
            local c4_param = bands[b].c4_param
            local c5_param = bands[b].c5_param
            local bypass_param = bands[b].bypass_param
            local col = bands[b].col
            local xoff = obj.sections[300].x + obj.sections[302].x
            local yoff = obj.sections[300].y + obj.sections[302].y
            local bn = bands[b].bandname
            local bt = bands[b].bandtype

            if eq_scale == false then
              pmin = 0
              pmax = 1
              gmin = 0
              gmax = 1
            end

            if eq_edit == false then
              f_Get_SSV(gui.color.black)
              local xywh = {x = obj.sections[300].x + obj.sections[326].x,
                            y = obj.sections[300].y + obj.sections[326].y,
                            w = obj.sections[326].w,
                            h = obj.sections[326].h}
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)
              local xywh = {x = obj.sections[300].x + obj.sections[325].x,
                            y = obj.sections[300].y + obj.sections[325].y,
                            w = obj.sections[325].w,
                            h = obj.sections[325].h}
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)
              local xywh = {x = obj.sections[300].x + obj.sections[327].x,
                            y = obj.sections[300].y + obj.sections[327].y,
                            w = obj.sections[327].w,
                            h = obj.sections[327].h}
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)
            end

            local freq_val, gain_val, q_val, bypass_val, c1_val, c2_val, c3_val = 0, 0.5, nil, 0, 0, 0, 0
            local freq_d, gain_d, q_d, c1_d, c2_d, c3_d
            if freq_param then
              freq_val = reaper.TrackFX_GetParamNormalized(track,fxnum,freq_param)
              _, freq_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,freq_param,'')
              if khz == true then
                freq_d = GetNumericPart(freq_d)
                local dd = tonumber(dd)
                if dd then
                  freq_d = freq_d*1000
                end
              end

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[325].x,
                              y = obj.sections[300].y + obj.sections[325].y,
                              w = obj.sections[325].w,
                              h = obj.sections[325].h}
                local w = gfx.getimgdim(def_eqcknobf)
                local h = ctl_files[def_eqcknobfctl].cellh
                local frames = ctl_files[def_eqcknobfctl].frames-1
                local v = math.floor(freq_val*frames)
                gfx.blit(def_eqcknobf, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                local suffix = ' Hz'
                if khz then
                  suffix = ' kHz'
                else
                  local s = string.find(string.lower(freq_d), 'k')
                  if s and s>0 then suffix = ' kHz' end
                end
                GUI_textC(gui,xywh,roundX(freq_d,1, suffix),gui.color.white,-2)
              end
            end
            if gain_param then
              gain_val = reaper.TrackFX_GetParamNormalized(track,fxnum,gain_param)
              _, gain_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,gain_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[326].x,
                              y = obj.sections[300].y + obj.sections[326].y,
                              w = obj.sections[326].w,
                              h = obj.sections[326].h}
                local w = gfx.getimgdim(def_eqcknobg)
                local h = ctl_files[def_eqcknobgctl].cellh
                local frames = ctl_files[def_eqcknobgctl].frames-1
                local v = math.floor(gain_val*frames)
                gfx.blit(def_eqcknobg, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,round(GetNumericPart(gain_d),2)..' dB',gui.color.white,-2)
              end
            end

            if q_param then
              q_val = reaper.TrackFX_GetParamNormalized(track,fxnum,q_param)
              _, q_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,q_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[327].x,
                              y = obj.sections[300].y + obj.sections[327].y,
                              w = obj.sections[327].w,
                              h = obj.sections[327].h}
                local w = gfx.getimgdim(def_eqcknobg)
                local h = ctl_files[def_eqcknobgctl].cellh
                local frames = ctl_files[def_eqcknobgctl].frames-1
                local v = math.floor(q_val*frames)
                gfx.blit(def_eqcknobg, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(q_d,2),gui.color.white,-2)
              end
            end

            if c1_param then
              c1_val = reaper.TrackFX_GetParamNormalized(track,fxnum,c1_param)
              _, c1_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,c1_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[328].x,
                              y = obj.sections[300].y + obj.sections[328].y,
                              w = obj.sections[328].w,
                              h = obj.sections[328].h}
                local w = gfx.getimgdim(def_knobsm)
                local h = ctl_files[def_knobsmctl].cellh
                local frames = ctl_files[def_knobsmctl].frames-1
                local v = math.floor(c1_val*frames)
                gfx.blit(def_knobsm, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(c1_d,2),gui.color.white,-2)
              end
            end

            if c2_param then
              c2_val = reaper.TrackFX_GetParamNormalized(track,fxnum,c2_param)
              _, c2_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,c2_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[329].x,
                              y = obj.sections[300].y + obj.sections[329].y,
                              w = obj.sections[329].w,
                              h = obj.sections[329].h}
                local w = gfx.getimgdim(def_knobsm)
                local h = ctl_files[def_knobsmctl].cellh
                local frames = ctl_files[def_knobsmctl].frames-1
                local v = math.floor(c2_val*frames)
                gfx.blit(def_knobsm, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(c2_d,2),gui.color.white,-2)
              end
            end

            if c3_param then
              c3_val = reaper.TrackFX_GetParamNormalized(track,fxnum,c3_param)
              _, c3_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,c3_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[330].x,
                              y = obj.sections[300].y + obj.sections[330].y,
                              w = obj.sections[330].w,
                              h = obj.sections[330].h}
                local w = gfx.getimgdim(def_knobsm)
                local h = ctl_files[def_knobsmctl].cellh
                local frames = ctl_files[def_knobsmctl].frames-1
                local v = math.floor(c3_val*frames)
                gfx.blit(def_knobsm, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(c3_d,2),gui.color.white,-2)
              end
            end

            if c4_param then
              c4_val = reaper.TrackFX_GetParamNormalized(track,fxnum,c4_param)
              _, c4_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,c4_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[334].x,
                              y = obj.sections[300].y + obj.sections[334].y,
                              w = obj.sections[334].w,
                              h = obj.sections[334].h}
                local w = gfx.getimgdim(def_knobsm)
                local h = ctl_files[def_knobsmctl].cellh
                local frames = ctl_files[def_knobsmctl].frames-1
                local v = math.floor(c4_val*frames)
                gfx.blit(def_knobsm, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(c4_d,2),gui.color.white,-2)
              end
            end

            if c5_param then
              c5_val = reaper.TrackFX_GetParamNormalized(track,fxnum,c5_param)
              _, c5_d = reaper.TrackFX_GetFormattedParamValue(track,fxnum,c5_param,'')

              if eq_edit == false and b == eqcontrolband_select then
                local xywh = {x = obj.sections[300].x + obj.sections[335].x,
                              y = obj.sections[300].y + obj.sections[335].y,
                              w = obj.sections[335].w,
                              h = obj.sections[335].h}
                local w = gfx.getimgdim(def_knobsm)
                local h = ctl_files[def_knobsmctl].cellh
                local frames = ctl_files[def_knobsmctl].frames-1
                local v = math.floor(c5_val*frames)
                gfx.blit(def_knobsm, 1, 0, 0, v* h, w, h, xywh.x, xywh.y)
                xywh.y = xywh.y + 30
                GUI_textC(gui,xywh,roundX(c5_d,2),gui.color.white,-2)
              end
            end

            if bypass_param then
              bypass_val = reaper.TrackFX_GetParamNormalized(track,fxnum,bypass_param)
              bands[b].bypass_val = bypass_val
            end

            bands[b].freq_val = freq_val
            bands[b].gain_val = gain_val
            bands[b].q_val = q_val
            bands[b].c1_val = c1_val
            bands[b].c2_val = c2_val
            bands[b].c3_val = c3_val
            bands[b].c4_val = c4_val
            bands[b].c5_val = c5_val

            local xp = (freq_val * (pmax-pmin)*obj.sections[302].w)+(pmin*obj.sections[302].w)
            if bands[b].gain_inv then
              gain_val = 1-gain_val
            end
            local yp = obj.sections[302].h-(gmin*obj.sections[302].h) - (gain_val * (gmax-gmin)*obj.sections[302].h)

            if bypass_val and bypass_val == 1 then
              gfx.a = 0.3
            else
              gfx.a = 1
            end

            f_Get_SSV(col)
            if q_val and b == eqcontrolband_select then
              --[[local xywh = {x = (xp+xoff)-(q_val*50)-25,
                            y = yp+yoff-1,
                            w = 50+(q_val*50)*2,
                            h = 3}]]
              local qv = q_val
              if bands[b].q_inv then
                qv=1-qv
              end
              qv=qv*100

              gfx.triangle((xp+xoff)-qv-12, yp+yoff-4,
                           (xp+xoff)-qv-12, yp+yoff+4,
                           (xp+xoff)-qv-17, yp+yoff)
              gfx.triangle((xp+xoff)+qv+12, yp+yoff-4,
                           (xp+xoff)+qv+12, yp+yoff+4,
                           (xp+xoff)+qv+17, yp+yoff)

            end

            gfx.circle(xp+xoff,yp+yoff,6,1,1)
            f_Get_SSV(gui.color.black)
            gfx.circle(xp+xoff,yp+yoff,6,0,1)
            if b == eqcontrolband_select then
              f_Get_SSV(gui.color.white)
              gfx.circle(xp+xoff,yp+yoff,7,0,1)
            end

            gfx.a = 1

            if eqcdrag == nil or b == eqcontrolband_select then
              if bt or bn then
                txt = ''
                if bt then
                  txt = bt
                end
                if bn then
                  if txt ~= '' then
                    txt = txt .. ': '
                  end
                  txt = txt .. bn
                end
                gfx.setfont(1, gui.fontname, gui.fontsz_knob -5)
                local text_len = gfx.measurestr(txt)

                local xywh = {x = xp+xoff-(text_len/2)-8,
                              y = yp+yoff-30,
                              w = text_len+16,
                              h = 12+6}
                local cc = '160 160 200'
                if b ~= eqcontrolband_select then
                  cc = '64 64 80'
                end
                gfx.a = 0.1
                f_Get_SSV(gui.color.black)
                gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
                f_Get_SSV(cc)
                gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
                xywh.y = xywh.y - 1
                GUI_textC(gui,xywh,txt,cc,-5)
                gfx.a = 1
              end


              local hh = 0
              if freq_d then
                hh = hh + 12
              end
              if gain_d then
                hh = hh + 12
              end
              if q_d then
                hh = hh + 12
              end


              if b == eqcontrolband_select then
                gfx.a = 0.1
                if hh > 0 then
                  local xywh = {x = xp+xoff-40,
                                y = yp+yoff+20,
                                w = 80,
                                h = hh+6}
                  local cc = '160 160 200'
                  f_Get_SSV(gui.color.black)
                  gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
                  f_Get_SSV(cc)
                  gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
                  xywh.h = 12
                  xywh.y = xywh.y + 2
                  if freq_d then
                    local suffix = ' Hz'
                    if khz then
                      suffix = ' kHz'
                    else
                      local s = string.find(string.lower(freq_d), 'k')
                      if s and s>0 then suffix = ' kHz' end
                    end

                    GUI_textC(gui,xywh,roundX(freq_d,1,suffix),cc,-5)
                  end
                  if gain_d then
                    xywh.y = xywh.y + 12
                    GUI_textC(gui,xywh,round(GetNumericPart(gain_d),2)..' dB',cc,-5)
                  end
                  if q_d then
                    xywh.y = xywh.y + 12
                    GUI_textC(gui,xywh,round(q_d,2),cc,-5)
                  end
                end
                gfx.a = 1
              end
            end
          end
        end
      end

    end

  end

  function GUI_DrawEQControl(obj, gui)

    local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
    gfx.dest = 1009
    local w, h = gfx.getimgdim(1009)
    if obj.sections[300].w ~= w or obj.sections[300].h ~= h or lupd.update_gfx then
      Img_SetDim(1009, obj.sections[300].w, obj.sections[300].h, true)

      f_Get_SSV(gui.color.black)
      gfx.rect(0,
               0,
               obj.sections[300].w,
               obj.sections[300].h, 1)
      f_Get_SSV(gui.color.white)
      gfx.rect(0,
               0,
               obj.sections[300].w,
               obj.sections[300].h, 0)
      gfx.rect(obj.sections[351].x,
               obj.sections[351].y,
               obj.sections[351].w,
               obj.sections[351].h, 1)
      local xywh = {x = obj.sections[351].x+8,
                    y = obj.sections[351].y+8,
                    w = obj.sections[351].w-16,
                    h = obj.sections[351].h-16}
      GUI_DrawBar(gui,'',obj.sections[351],skin.bar,true,gui.color.black,nil,-2)
      f_Get_SSV(gui.color.black)
      gfx.line(xywh.x,xywh.y,xywh.x+xywh.w,xywh.y+xywh.h,1)
      gfx.line(xywh.x+xywh.w,xywh.y,xywh.x,xywh.y+xywh.h,1)

      GUI_DrawBar(gui,'ADD',obj.sections[304],skin.bar,true,gui.color.black,nil,-2,true,false,nil,nil,true)

      f_Get_SSV(gui.color.white)
      local c = gui.color.white
      local f = skin.barG
      if eq_edit then
        c = gui.color.black
        f = skin.bar
      end
      GUI_DrawBar(gui,'EDIT',obj.sections[311],f,true,c,nil,-2,true,false,nil,nil,true)

      f_Get_SSV(gui.color.white)
      local c = gui.color.white
      local f = skin.barG
      if eq_single == true then
        c = gui.color.black
        f = skin.bar
      end
      GUI_DrawBar(gui,'',obj.sections[320],f,true,c,nil,-2,true,false,nil,nil,true)
      xywh = {x = obj.sections[320].x,
              y = obj.sections[320].y-6,
              w = obj.sections[320].w,
              h = obj.sections[320].h}
      GUI_textC(gui,xywh,'SINGLE',c,-8)
      xywh.y = xywh.y + 8
      GUI_textC(gui,xywh,'BAND',c,-8)

      f_Get_SSV(gui.color.white)
      local c = gui.color.white
      local f = skin.barG
      if eq_scale == true then
        c = gui.color.black
        f = skin.bar
      end
      GUI_DrawBar(gui,'',obj.sections[321],f,true,c,nil,-2,true,false,nil,nil,true)
      xywh = {x = obj.sections[321].x,
              y = obj.sections[321].y-1,
              w = obj.sections[321].w,
              h = obj.sections[321].h}
      GUI_textC(gui,xywh,'SCALE',c,-8)

      f_Get_SSV(gui.color.white)
      f = skin.bar
      c = gui.color.black
      GUI_DrawBar(gui,'',obj.sections[345],f,true,c,nil,-2,true,false,nil,nil,true)

      xywh = {x = obj.sections[345].x,
              y = obj.sections[345].y-6,
              w = obj.sections[345].w,
              h = obj.sections[345].h}
      GUI_textC(gui,xywh,'OPEN',c,-8)
      xywh.y = xywh.y + 8
      GUI_textC(gui,xywh,'FX',c,-8)

      f_Get_SSV(gui.color.white)
      --gfx.line(obj.sections[303].x,obj.sections[303].y,obj.sections[303].x+obj.sections[303].w,obj.sections[303].y,1)
      --gfx.line(obj.sections[303].x,obj.sections[303].y+obj.sections[303].h,obj.sections[303].x+obj.sections[303].w,obj.sections[303].y+obj.sections[303].h,1)
      local bandsn = 20
      local track = GetTrack(tracks[track_select].tracknum)
      for l = 1, bandsn do
        local x = math.floor(obj.sections[303].w / bandsn) * (l-1)
        f_Get_SSV(gui.color.white)

        local xywh = {x = obj.sections[303].x+x,
                      y = obj.sections[303].y,
                      w = obj.sections[303].w / bandsn,
                      h = obj.sections[303].h}
        if l < bandsn then
          local c = '32 32 32'

          local byp = 0
          if bands and bands[l] then
            local p_byp = bands[l].bypass_param
            local fxnum = bands[l].fxnum

            if bands[l].bypass_param then
              byp = reaper.TrackFX_GetParamNormalized(track, fxnum, p_byp)
              bands[l].bypass_val = byp
            end
          end

          if byp == 1 then
            f_Get_SSV('64 0 0')
          else
            f_Get_SSV('32 32 32')
          end

          gfx.rect(xywh.x+2,xywh.y,xywh.w-4,xywh.h+1,1,1)

          if eqcontrolband_select == l then
            f_Get_SSV(gui.color.white)
            gfx.rect(xywh.x+2,
                     xywh.y,
                     xywh.w-4,
                     xywh.h+1, 0)
            c = gui.color.black
            if bands and l <= #bands then
              c = bands[l].col
            end
          else
            if bands and l <= #bands then
              c = bands[l].col
            end
          end
          f_Get_SSV(c)
          gfx.circle(xywh.x+math.floor(xywh.w/2),xywh.y+math.floor(xywh.h/2),6,1,1)
          f_Get_SSV(gui.color.black)
          gfx.circle(xywh.x+math.floor(xywh.w/2),xywh.y+math.floor(xywh.h/2),7,0,1)
          gfx.circle(xywh.x+math.floor(xywh.w/2),xywh.y+math.floor(xywh.h/2),8,0,1)
          xywh.y = xywh.y - 1

          GUI_textC(gui,xywh,string.format('%i',l),c,-4)
        end
      end

      if eqcontrolband_select and bands and
        bands[eqcontrolband_select] then
        if eq_edit then

          gfx.a=1

          GUI_DrawBar(gui,'SAVE BAND',obj.sections[312],skin.bar,true,gui.color.black,nil,-5,true,false,nil,nil,true)
          GUI_DrawBar(gui,'DEL BAND',obj.sections[315],skin.bar,true,gui.color.black,nil,-5,true,false,nil,nil,true)
          GUI_DrawBar(gui,'SAVE EQ',obj.sections[340],skin.bar,true,gui.color.black,nil,-5,true,false,nil,nil,true)

          local f = skin.barG
          local c = gui.color.white
          local txt = 'FOLDER'
          if bands[eqcontrolband_select].bandtype then
            f = skin.bar
            c = gui.color.black
            txt = bands[eqcontrolband_select].bandtype
          end
          GUI_DrawBar(gui,txt,obj.sections[313],f,true,c,nil,-5,true,false,nil,nil,true)

          GUI_DrawColorBox(gui, '', obj.sections[355], gui.color.white, bands[eqcontrolband_select].col)
          local xywh = {x = obj.sections[355].x,
                        y = obj.sections[355].y-5,
                        w = obj.sections[355].w,
                        h = obj.sections[355].h}
          GUI_textC(gui,xywh,'BAND',gui.color.black,-5)
          xywh.y = xywh.y + 10
          GUI_textC(gui,xywh,'COLOUR',gui.color.black,-5)

          local f = skin.barG
          local c = gui.color.white
          local txt = 'BAND NAME'
          if bands[eqcontrolband_select].bandname then
            f = skin.bar
            c = gui.color.black
            txt = bands[eqcontrolband_select].bandname
          end
          GUI_DrawBar(gui,txt,obj.sections[314],f,true,c,nil,-5,true,false,nil,nil,true)

          local f = skin.barG
          local c = gui.color.white
          local txt = 'SELECT PLUGIN'
          if bands[eqcontrolband_select].fxnum then
            f = skin.bar
            c = gui.color.black
            if bands[eqcontrolband_select].fxname then
              txt = string.format('%i',bands[eqcontrolband_select].fxnum+1)..': '..
                    bands[eqcontrolband_select].fxname
            else
              txt = string.format('%i',bands[eqcontrolband_select].fxnum+1)..': '
            end
          end
          GUI_DrawBar(gui,txt,obj.sections[305],f,true,c,nil,-5,true,false,nil,nil,true)

          if bands[eqcontrolband_select].fxnum then

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT FREQ PARAM'
            if bands[eqcontrolband_select].freq_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].freq_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[306],f,true,c,nil,-5,true,false,nil,nil,true)
            GUI_DrawBar(gui,'',obj.sections[309],f,true,c,nil,-5,true,false,nil,nil,true)
            GUI_DrawBar(gui,'',obj.sections[336],f,true,c,nil,-5,true,false,nil,nil,true)

            local xywh = {x = obj.sections[337].x-6,
                          y = obj.sections[337].y-13,
                          w = 1,
                          h = butt_h}
            GUI_textsm_RJ(gui,xywh,'DETECTION   ',gui.color.white,-5)
            xywh.y = xywh.y + 10
            GUI_textsm_RJ(gui,xywh,'SENSITIVITY',gui.color.white,-5)

            GUI_DrawSliderH(gui, '', obj.sections[337], gui.color.black, gui.color.white, F_limit(auto_delay/10,0,1))
            GUI_textC(gui,obj.sections[337],auto_delay,gui.color.red,-2)

            local xywh = {x = obj.sections[338].x,
                          y = obj.sections[338].y+3,
                          w = obj.sections[338].w,
                          h = 10}

            GUI_textsm_LJ(gui,xywh,'FREQ MIN:',gui.color.red,-5)
            xywh.y = xywh.y + 12
            GUI_textsm_LJ(gui,xywh,'FREQ MAX:',gui.color.red,-5)
            xywh.y = xywh.y + 15
            GUI_textsm_LJ(gui,xywh,'GAIN MIN:',gui.color.red,-5)
            xywh.y = xywh.y + 12
            GUI_textsm_LJ(gui,xywh,'GAIN MAX:',gui.color.red,-5)

            xywh.x = obj.sections[338].x
            xywh.y = obj.sections[338].y+3

            GUI_textsm_RJ(gui,xywh,nz(bands[eqcontrolband_select].freq_min,''),gui.color.red,-5)
            xywh.y = xywh.y + 12
            GUI_textsm_RJ(gui,xywh,nz(bands[eqcontrolband_select].freq_max,''),gui.color.red,-5)
            xywh.y = xywh.y + 15
            GUI_textsm_RJ(gui,xywh,nz(bands[eqcontrolband_select].gain_min,''),gui.color.red,-5)
            xywh.y = xywh.y + 12
            GUI_textsm_RJ(gui,xywh,nz(bands[eqcontrolband_select].gain_max,''),gui.color.red,-5)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT BAND BYPASS'
            if bands[eqcontrolband_select].bypass_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].bypass_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[322],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT CTL 1'
            if bands[eqcontrolband_select].c1_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].c1_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[323],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT CTL 2'
            if bands[eqcontrolband_select].c2_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].c2_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[324],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT CTL 3'
            if bands[eqcontrolband_select].c3_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].c3_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[331],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT CTL 4'
            if bands[eqcontrolband_select].c4_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].c4_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[332],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT CTL 5'
            if bands[eqcontrolband_select].c5_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].c5_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[333],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.bar
            c = gui.color.black
            GUI_DrawBar(gui,'CAPTURE CURRENT VALUES AS DEFAULT',obj.sections[356],f,true,c,nil,-5,true,false,nil,nil,true)

            c = gui.color.black
            if bands[eqcontrolband_select].lookmap then
              GUI_textC(gui,obj.sections[309],'ALIGN GRAPH',c,-5)
            else
              GUI_textC(gui,obj.sections[309],'CALC GRAPH',c,-5)
            end
            GUI_textC(gui,obj.sections[336],'CLEAR GRAPH',c,-5)

            xywh = {x = obj.sections[357].x,
                    y = obj.sections[357].y+10,
                    w = obj.sections[357].w,
                    h = butt_h}
            GUI_DrawBar(gui,'',obj.sections[357],skin.bar,true,c,nil,-5,true,false,nil,nil,true)

            GUI_textC(gui,xywh,'ALIGN',c,-5)
            xywh.y = xywh.y + 14
            GUI_textC(gui,xywh,'ALL',c,-5)
            xywh.y = xywh.y + 14
            GUI_textC(gui,xywh,'BANDS',c,-5)

            f_Get_SSV(gui.color.white)
            f = skin.barG
            c = gui.color.white
            if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph then
              f = skin.bar
              c = gui.color.black
            end
            GUI_DrawBar(gui,'',obj.sections[310],f,true,c,nil,-5)
            GUI_textC(gui,obj.sections[310],'SET',c,-6,nil,-5)
            GUI_textC(gui,obj.sections[310],'DEFAULT',c,-6,nil,4)

            f_Get_SSV(gui.color.white)
            f = skin.bar
            c = gui.color.black
            local txt = 'Hz/kHz'
            if bands[eqcontrolband_select].khz == true then
              txt = 'kHz'
            end
            GUI_DrawBar(gui,txt,obj.sections[316],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT GAIN PARAM'
            if bands[eqcontrolband_select].gain_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].gain_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[307],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            if bands[eqcontrolband_select].gain_inv then
              f = skin.bar
              c = gui.color.black
            end
            GUI_DrawBar(gui,'INVERT',obj.sections[317],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            txt = 'SELECT Q PARAM'
            if bands[eqcontrolband_select].q_param then
              f = skin.bar
              c = gui.color.black
              txt = bands[eqcontrolband_select].q_param_name
            end
            GUI_DrawBar(gui,txt,obj.sections[308],f,true,c,nil,-5,true,false,nil,nil,true)

            f = skin.barG
            c = gui.color.white
            if bands[eqcontrolband_select].q_inv then
              f = skin.bar
              c = gui.color.black
            end
            GUI_DrawBar(gui,'INVERT',obj.sections[318],f,true,c,nil,-5,true,false,nil,nil,true)

          end
        else

          local xywh = {x = obj.sections[325].x,
                        y = obj.sections[325].y-20,
                        w = obj.sections[325].w,
                        h = 10}
          if bands[eqcontrolband_select].freq_param then
            GUI_textC(gui,xywh,'FREQ',gui.color.white,-2)
          end
          if bands[eqcontrolband_select].gain_param then
            xywh.x = obj.sections[326].x
            GUI_textC(gui,xywh,'GAIN',gui.color.white,-2)
          end
          if bands[eqcontrolband_select].q_param then
            xywh.x = obj.sections[327].x
            GUI_textC(gui,xywh,'Q',gui.color.white,-2)
          end
          xywh.x = obj.sections[328].x
          xywh.w = obj.sections[328].w
          local txt = bands[eqcontrolband_select].c1_param_name
          if txt then
            GUI_textC(gui,xywh,txt,gui.color.white,-4)
          end
          local ofs = 15
          xywh.y = xywh.y - ofs
          xywh.x = obj.sections[329].x
          local txt = bands[eqcontrolband_select].c2_param_name
          if txt then
            GUI_textC(gui,xywh,txt,gui.color.white,-4)
          end
          xywh.y = xywh.y + ofs
          xywh.x = obj.sections[330].x
          local txt = bands[eqcontrolband_select].c3_param_name
          if txt then
            GUI_textC(gui,xywh,txt,gui.color.white,-4)
          end
          xywh.y = xywh.y - ofs
          xywh.x = obj.sections[334].x
          local txt = bands[eqcontrolband_select].c4_param_name
          if txt then
            GUI_textC(gui,xywh,txt,gui.color.white,-4)
          end
          xywh.y = xywh.y + ofs
          xywh.x = obj.sections[335].x
          local txt = bands[eqcontrolband_select].c5_param_name
          if txt then
            GUI_textC(gui,xywh,txt,gui.color.white,-4)
          end
        end
      end
    end

    local mp = math.floor(obj.sections[302].y+(obj.sections[302].h/2))

    if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph and eq_scale == true then
      local eqg = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph

      if type(eqg) == 'table' and eqg.gmap and eqg.lookmap then

        local pmin = eqg.posmin
        local pmax = eqg.posmax
        local gmin = eqg.gmin
        local gmax = eqg.gmax

        if eq_scale == false then
          pmin = 0
          pmax = 1
          gmin = 0
          gmax = 1
        end

        local xywh = {x = obj.sections[302].x + pmin*obj.sections[302].w,
                      y = obj.sections[302].y,
                      w = (pmax-pmin)*obj.sections[302].w,
                      h = obj.sections[302].h}
        f_Get_SSV('8 8 48')
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        --gfx.a = 0.3
        --gfx.gradrect(xywh.x,xywh.y,xywh.w,xywh.h, 0,0,1.6,0.5, 0,0,0.0008,0.00005, 0,0,0,-0.0005)
        --gfx.a = 1

        local pmin2, pmax2, gmin2, gmax2 = 0,1,0,1
        if bands and eqcontrolband_select
           and bands[eqcontrolband_select] then
          pmin2 = bands[eqcontrolband_select].posmin
          pmax2 = bands[eqcontrolband_select].posmax
          gmin2 = bands[eqcontrolband_select].gmin
          gmax2 = bands[eqcontrolband_select].gmax

          gmap2 = bands[eqcontrolband_select].gmap
        end

        if eq_scale == false then
          pmin2 = 0
          pmax2 = 1
          gmin2 = 0
          gmax2 = 1
        end

        local gmap = eqg.gmap

        f_Get_SSV('16 16 48')
        local prevx = 0
        gfx.setfont(1, gui.fontname, gui.fontsz_knob -5)
        local h = (gmax - gmin) * obj.sections[302].h

        if gmap2 and #gmap2 > 1 then
          local g1 = obj.sections[302].y + obj.sections[302].h -(gmap2[1].pix/2000)*h - (gmin2 * obj.sections[302].h)+5
          local g2 = obj.sections[302].y + obj.sections[302].h -((gmap2[#gmap2].pix/2000)*h - (gmin2 * obj.sections[302].h))-5

          if gmap then
            for l = 1, #gmap do
              local y = obj.sections[302].y + obj.sections[302].h - (gmap[l].pix/2000)*h - (gmin * obj.sections[302].h)
              f_Get_SSV('0 0 32')

              if (y > g1
                 or y < g2) or draggraph then
                if gmap[l].db % 6 == 0 then
                  --gfx.line( obj.sections[302].x, y, obj.sections[302].x + obj.sections[302].w, y)
                  xywh = {x = obj.sections[302].x-4,
                          y = y,
                          w = 1,
                          h = 1}
                  local txt = gmap[l].db
                  GUI_textsm_RJ(gui, xywh, txt, '128 0 0', -5)
                end
              end
            end
          end
        end

        local lookmap = eqg.lookmap
        f_Get_SSV('16 16 48')
        if lookmap then
          for l = 1, #lookmap do
            local w = (pmax - pmin) * obj.sections[302].w
            local x = (lookmap[l].pix/2000)*w + (pmin * obj.sections[302].w)
            local yinc = 0
            if (x < pmin2 * obj.sections[302].w or x > pmax2 * obj.sections[302].w) or draggraph then
              if 10^math.floor(math.log(lookmap[l].hz,10)) == lookmap[l].hz then
                local xywh = {x = obj.sections[302].x + x-4,
                            y = obj.sections[302].y + obj.sections[302].h+1,
                            w = 1,
                            h = 10}

                if draggraph then
                  yinc = 10
                  GUI_textsm_RJ(gui, xywh, string.format('%i',lookmap[l].hz), gui.color.white, -5)
                end
                f_Get_SSV('64 64 128')
              else
                f_Get_SSV('32 32 96')
              end
              if draggraph == nil then
                gfx.a = 0.3
              end
              gfx.line(obj.sections[302].x + x, obj.sections[302].y, obj.sections[302].x + x, obj.sections[302].y + obj.sections[302].h-1 + yinc)
              gfx.a = 1
            end
          end
        end
      end

    end

    if bands then

      if bands[eqcontrolband_select] and
         bands[eqcontrolband_select].lookmap then

        local pmin = bands[eqcontrolband_select].posmin
        local pmax = bands[eqcontrolband_select].posmax
        local gmin = bands[eqcontrolband_select].gmin
        local gmax = bands[eqcontrolband_select].gmax

        if eq_scale == false then
          pmin = 0
          pmax = 1
          gmin = 0
          gmax = 1
        end

        local xywh = {x = obj.sections[302].x + pmin*obj.sections[302].w,
                      y = obj.sections[302].y+obj.sections[302].h - gmax*obj.sections[302].h,
                      w = (pmax-pmin)*obj.sections[302].w,
                      h = (gmax-gmin)*obj.sections[302].h}
        f_Get_SSV('24 24 96')
        if draggraph then
          gfx.a = 0.2
        end
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        gfx.a = 1
        local lookmap = bands[eqcontrolband_select].lookmap
        local gmap = bands[eqcontrolband_select].gmap
        f_Get_SSV('16 16 48')
        local prevx = 0
        gfx.setfont(1, gui.fontname, gui.fontsz_knob -5)

        if gmap then
          for l = 1, #gmap do
            local h = (gmax - gmin) * obj.sections[302].h
            local y = obj.sections[302].y + obj.sections[302].h - (gmap[l].pix/2000)*h - (gmin * obj.sections[302].h)
            f_Get_SSV('16 16 60')
            if gmap[l].db % 6 == 0 then
              gfx.line( obj.sections[302].x, y, obj.sections[302].x + obj.sections[302].w, y)
              xywh = {x = obj.sections[302].x-4,
                      y = y,
                      w = 1,
                      h = 1}
              local txt = gmap[l].db
              GUI_textsm_RJ(gui, xywh, txt, gui.color.white, -5)
            end
          end
        end


        for l = 1, #lookmap do
          local w = (pmax - pmin) * obj.sections[302].w
          local x = (lookmap[l].pix/2000)*w + (pmin * obj.sections[302].w)
          local yinc = 0
          if 10^math.floor(math.log(lookmap[l].hz,10)) == lookmap[l].hz then
            local txt = string.format('%i',lookmap[l].hz)
            local tw = gfx.measurestr(txt)
            local xywh = {x = obj.sections[302].x + x-4,
                          y = obj.sections[302].y + obj.sections[302].h+1,
                          w = 1,
                          h = 10}
            if xywh.x - tw > prevx +10 then
              yinc = 10
              GUI_textsm_RJ(gui, xywh, txt, gui.color.white, -5)
              prevx = xywh.x
            end
            f_Get_SSV('48 48 96')
          else
            local txt = string.format('%i',lookmap[l].hz)
            local tw = gfx.measurestr(txt)
            local xywh = {x = obj.sections[302].x + x-4,
                          y = obj.sections[302].y + obj.sections[302].h+1,
                          w = 1,
                          h = 10}
            if xywh.x - tw > prevx +10 then
              yinc = 10
              GUI_textsm_RJ(gui, xywh, txt, gui.color.white, -5)
              prevx = xywh.x
            end
            f_Get_SSV('16 16 64')

          end

          gfx.line( obj.sections[302].x + x, obj.sections[302].y, obj.sections[302].x + x, obj.sections[302].y + obj.sections[302].h-1 + yinc)
          if yinc > 0 then
            f_Get_SSV('64 64 128')
            gfx.line( obj.sections[302].x + x, obj.sections[302].y + obj.sections[302].h-1, obj.sections[302].x + x, obj.sections[302].y + obj.sections[302].h-1 + yinc)

          end
        end
      end

      if bands[eqcontrolband_select] then
        local bn = bands[eqcontrolband_select].bandname
        local bt = bands[eqcontrolband_select].bandtype
        if bt or bn then
          local txt = ''
          if bt then
            txt = bt
          end
          if bn then
            if txt ~= '' then
              txt = txt .. ' : '
            end
            txt = txt .. bn
          end

          local xywh = {x = obj.sections[302].x + 10,
                        y = obj.sections[302].y + 10,
                        w = 2,
                        h = 14}
          GUI_textsm_LJ(gui, xywh, txt, '64 64 128', 4)
        end
      end
    end

    f_Get_SSV('128 128 128')
    gfx.line(obj.sections[302].x, mp, obj.sections[302].x + obj.sections[302].w-1, mp, 1)
    f_Get_SSV('64 64 64')
    gfx.rect(obj.sections[302].x,
             obj.sections[302].y,
             obj.sections[302].w,
             obj.sections[302].h, 0)

    if bands and
       bands[eqcontrolband_select] and
       bands[eqcontrolband_select].freq_param then

      local pmin = bands[eqcontrolband_select].posmin
      local pmax = bands[eqcontrolband_select].posmax

      --[[if eq_scale == false then
        pmin = 0
        pmax = 1
      end]]

      local x = obj.sections[302].x + pmin * obj.sections[302].w
      f_Get_SSV('0 255 0')
      if eq_edit then
        xywh = {x = x-4,
                y = obj.sections[302].y+obj.sections[302].h + 2,
                w = 8,
                h = 8}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        gfx.line(x, obj.sections[302].y, x, obj.sections[302].y+obj.sections[302].h, 1)
      else
        f_Get_SSV('64 64 240')
      end

      x = obj.sections[302].x + pmax * obj.sections[302].w
      f_Get_SSV('255 0 0')
      if eq_edit then
        xywh = {x = x-4,
                y = obj.sections[302].y+obj.sections[302].h + 2,
                w = 8,
                h = 8}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        gfx.line(x, obj.sections[302].y, x, obj.sections[302].y+obj.sections[302].h, 1)
      else
        f_Get_SSV('64 64 240')
      end

    end

    if bands and
       bands[eqcontrolband_select] and
       bands[eqcontrolband_select].gain_param then

      local gmin = bands[eqcontrolband_select].gmin
      local gmax = bands[eqcontrolband_select].gmax

      --[[if eq_scale == false then
        pmin = 0
        pmax = 1
      end]]

      local y = obj.sections[302].y + obj.sections[302].h  - (gmin * obj.sections[302].h)
      f_Get_SSV('0 255 255')
      if eq_edit then
        xywh = {x = obj.sections[302].x-10,
                y = y-4,
                w = 8,
                h = 8}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        gfx.line(obj.sections[302].x-2, y, obj.sections[302].x + obj.sections[302].w-1, y, 1)
      else
        f_Get_SSV('64 64 240')
      end

      y = obj.sections[302].y + obj.sections[302].h - gmax * obj.sections[302].h
      f_Get_SSV('0 255 255')
      if eq_edit then
        xywh = {x = obj.sections[302].x-10,
                y = y-4,
                w = 8,
                h = 8}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1)
        gfx.line(obj.sections[302].x-2, y, obj.sections[302].x + obj.sections[302].w-1, y, 1)
      else
        f_Get_SSV('64 64 240')
      end

    end

    gfx.dest = 1

  end

  ------------------------------------------------------------

  function GUI_DrawSnapEdit(obj, gui)

    local strip = tracks[track_select].strip
    local page = page
    local snaptype = snapshots[strip][page][sstype_select]
    local snapctl = snaptype.ctls
    local snap = snaptype.snapshot

    local snapedit_ss = lvar.snapedit.snapedit_ss
    local snapedit_poffs = lvar.snapedit.snapedit_poffs
    local monitor = lvar.snapedit.monitor

    gfx.dest = 1008
    local w, h = gfx.getimgdim(1008)

    local update_size
    if obj.sections[300].w ~= w or obj.sections[300].h ~= h then update_size = true lupd.update_gfx = true end
    if lupd.update_gfx or lupd.update_surface or lupd.update_macroedit or lupd.update_macrobutt then
      if update_size then
        Img_SetDim(1008, obj.sections[300].w, obj.sections[300].h, true)
      end

      if lupd.update_gfx or lupd.update_macrobutt then
        --f_Get_SSV(gui.color.black)
        f_Get_SSV('8 8 8')
        gfx.rect(0,
                 0,
                 obj.sections[300].w,
                 obj.sections[300].h, 1)

      end

      if lupd.update_gfx or lupd.update_macrobutt then
        local xywh = {x = obj.sections[401].x+2,
                      y = obj.sections[401].y+2,
                      w = obj.sections[401].w-4,
                      h = obj.sections[401].h-4}
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[401].x,
                 obj.sections[401].y,
                 obj.sections[401].w,
                 obj.sections[401].h, 1)
        f_Get_SSV(gui.color.black)
        gfx.line(xywh.x,xywh.y,xywh.x+xywh.w,xywh.y+xywh.h,1)
        gfx.line(xywh.x+xywh.w,xywh.y,xywh.x,xywh.y+xywh.h,1)

        local xywh = {x = obj.sections[429].x, y = obj.sections[429].y - 20, w = obj.sections[429].w, h = 20}
        --GUI_Str(gui, xywh, 'STAGES', 5, gui.color.white, -2, 1)
      end

      local stages = snaptype.stages
      GUI_DrawButton(gui, 'STAGE', obj.sections[427], gui.color.white, gui.skol.butt1_txt, true, '', false,0,true)
      GUI_DrawButton(gui, 'MORPH', obj.sections[428], gui.color.white, gui.skol.butt1_txt, true, '', false,0,true)
      GUI_DrawButton(gui, 'MEM', obj.sections[434], gui.color.white, gui.skol.butt1_txt, true, '', false,0,true)

      GUI_DrawButton(gui, snaptype.subsetname, obj.sections[430], gui.color.white, gui.skol.butt1_txt, true, '', false,0,true)
      GUI_DrawButton(gui, 'STAGES: '..(stages or ''), obj.sections[429], gui.color.white, gui.skol.butt1_txt, true, '', false,2,true)

      local ssname = ''
      if snap[snapedit_ss] then
        ssname = snap[snapedit_ss].name
      end
      GUI_DrawButton(gui, ssname, obj.sections[425], gui.color.white, gui.skol.butt1_txt, true, '', false,0,true)
      GUI_DrawButton(gui, '', obj.sections[433], gui.color.white, gui.skol.butt1_txt, true, '', false,12,true)
      local xywh = {x = obj.sections[433].x,
                        y = obj.sections[433].y+3,
                        w = obj.sections[433].w,
                        h = obj.sections[433].h}
      GUI_textC(gui,xywh,'*',gui.skol.butt1_txt,9)

      local b = -1
      if monitor == true then
        b = -4
      end
      GUI_DrawButton(gui, 'MONITOR', obj.sections[426], b, gui.skol.butt1_txt, true, '', false,0,true)

      b = -1
      if snaptype.mult == true then
        b = -4
      end
      GUI_DrawButton(gui, 'MULT', obj.sections[432], b, gui.skol.butt1_txt, true, '', false,0,true)

      local xywh = {x = obj.sections[431].x,
                    y = obj.sections[431].y,
                    w = math.floor(obj.sections[431].w/5)-2,
                    h = math.floor(obj.sections[431].h/2)-2}
      local xywh2 = {x = obj.sections[431].x,
                    y = obj.sections[431].y,
                    w = math.floor(obj.sections[431].w/5)-2,
                    h = 18}
      local xx = obj.sections[431].x
      local yy = obj.sections[431].y

      for y = 0, 1 do
        for x = 0, 4 do

          local v = (lvar.snapedit.SToffs*10) + x+(y*5)+1

          xywh.x = xx + x*(xywh.w+2)
          xywh.y = yy + y*xywh.h+2
          xywh2.x = xywh.x
          local txt = ''
          if v % 10 == 1 then
            txt = 'TIME'
          elseif v % 10 == 6 then
            txt = 'TIME'
          end

          if v <= (stages or 1) then
            if snaptype.deltype[v] == 0 then
              GUI_DrawButton(gui, snaptype.delay[v]..' s', xywh, gui.color.white, gui.skol.butt1_txt, true, txt, false,2,true)
            elseif snaptype.deltype[v] == 1 then
              local t = lvar.sync_table[snaptype.mtime[v]]
              if t == nil then
                snaptype.mtime[v] = 15
                t = lvar.sync_table[snaptype.mtime[v]]
              end
              GUI_DrawButton(gui, t, xywh, gui.color.white, gui.skol.butt1_txt, true, txt, false,2,true)
            else
              GUI_DrawButton(gui, 'REM', xywh, gui.color.white, gui.skol.butt1_txt, true, txt, false,2,true)
            end
          else
            GUI_DrawButton(gui, '', xywh, -1, gui.skol.butt1_txt, true, txt, false,2,true)
          end
          local lbly
          if (v-1)%10 < 5 then
            xywh2.y = yy-16
          else
            xywh2.y = yy + obj.sections[431].h - 2
          end
          if v <= stages then
            GUI_DrawButton(gui, 'STAGE '..string.format('%i',v), xywh2, -1, gui.skol.butt1_txt, true, '', false,-2,true)
          end
        end
      end

      for s = 1, macroedit.pcnt2 do

        gfx.a = 1
        local ss = s-1

        if snapctl and snapctl[s+snapedit_poffs] then
          local sctl = snapctl[s+snapedit_poffs]
          local ctl = strips[strip][page].controls[sctl.ctl]
          if ctl then

            local scol = 32+((sctl.stage-1)%10)*10
            local tcoffs = 0
            if sctl.stage > 4 then
              tcoffs = 60
            end
            local fxtc = 160-((sctl.stage-1)%10)*10 -tcoffs
            if lupd.update_gfx or lupd.update_macrobutt then
              local xywh = {x = obj.sections[420].x,
                            y = obj.sections[420].y + ss*macroedit.sech +2,
                            w = obj.sections[420].w,
                            h = macroedit.sech-4}
              local stc = '64 0 0'
              if sctl.stage <= stages then
                stc = scol..' '..scol..' '..scol
              end
              f_Get_SSV(stc)
              local tc = gui.color.white
              if snapparamdrag and snapparamdrag.p == s+snapedit_poffs then
                f_Get_SSV('8 8 8')
                tc = '64 64 64'
                stc = '8 8 8'
              end
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)
              if lvar.snapedit.selected and lvar.snapedit.selected == s+snapedit_poffs and snapparamdrag == nil then
                f_Get_SSV(gui.color.yellow)
                gfx.rect(xywh.x,
                         xywh.y,
                         xywh.w,
                         xywh.h, 0)
              end
              xywh = {x = obj.sections[420].x+10,
                      y = obj.sections[420].y + ss*macroedit.sech,
                      w = obj.sections[420].w-20,
                      h = macroedit.sech}
              local ctlnm = ctl.param_info.paramname
              local fxnm2 = CropFXName(ctl.fxname or '')
              local fxnm
              if fxnm2 ~= '' and fxnm2 ~= nil and ctl.fxnum then
                fxnm = '('..ctl.fxnum+1 ..': '..fxnm2..')'
              end
              if ctl.ctlname_override ~= '' then
                ctlnm = ctl.ctlname_override or ctl.param_info.paramname
              end
              if fxnm then
                GUI_Str(gui, xywh, fxnm, 4, '0 '..fxtc..' 0', -2, 1, nil, nil, 'i')
              end
              GUI_StrB(gui, xywh, ctlnm, 6, tc, -2, 1,nil,nil,'ib',stc)
              gfx.a = 1
            end

            local xywh = {x = obj.sections[421].x,
                          y = obj.sections[421].y + ss*macroedit.sech +2,
                          w = obj.sections[421].w,
                          h = macroedit.sech-4}
            if sctl.stage > stages then
              f_Get_SSV('64 0 0')
            else
              f_Get_SSV(scol..' '..scol..' '..scol)
            end
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1)
            GUI_Str(gui, xywh, sctl.stage, 5, gui.color.white, 0, 1)

            local xywh = {x = obj.sections[422].x,
                          y = obj.sections[422].y + ss*macroedit.sech +2,
                          w = obj.sections[422].w,
                          h = macroedit.sech-4}
            if sctl.stage > stages then
              f_Get_SSV('64 0 0')
            else
              f_Get_SSV(scol..' '..scol..' '..scol)
            end
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1)
            local b = -1
            local txt = 'OFF'
            if sctl.morph == true then
              b = -4
              txt = 'ON'
            end

            local mbh = math.max(xywh.h -12,20)
            xywh = {x = xywh.x + 20, y = math.floor(xywh.y+xywh.h/2-mbh/2), w = xywh.w -40, h = mbh}
            GUI_DrawButton(gui, txt, xywh, b, gui.skol.butt1_txt, true, '', false,2,true)

            local xywh = {x = obj.sections[435].x,
                          y = obj.sections[435].y + ss*macroedit.sech +2,
                          w = obj.sections[435].w,
                          h = macroedit.sech-4}
            if sctl.stage > stages then
              f_Get_SSV('64 0 0')
            else
              f_Get_SSV(scol..' '..scol..' '..scol)
            end
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1)
            local b = -1
            local txt = 'OFF'
            local mem = false
            if sctl.mem == true then
              b = -4
              txt = 'ON'
              mem = true
            end
            xywh = {x = xywh.x + 2, y = math.floor(xywh.y+xywh.h/2-mbh/2), w = xywh.w -4, h = mbh}
            GUI_DrawButton(gui, txt, xywh, b, gui.skol.butt1_txt, true, '', false,2,true)

            local xywh = {x = obj.sections[423].x - 12,
                          y = obj.sections[423].y + ss*macroedit.sech +2,
                          w = obj.sections[423].w + 24,
                          h = macroedit.sech-4}
            f_Get_SSV('16 16 16')
            gfx.rect(xywh.x,
                     xywh.y,
                     xywh.w,
                     xywh.h, 1)
            local xywh2 = {x = obj.sections[424].x,
                          y = obj.sections[424].y + ss*macroedit.sech +2,
                          w = obj.sections[424].w,
                          h = macroedit.sech-4}
            gfx.rect(xywh2.x,
                     xywh2.y,
                     xywh2.w,
                     xywh2.h, 1)

            if --[[mem == false and]] snap[snapedit_ss] and snap[snapedit_ss].data[s+snapedit_poffs] then

              local w, h = macroedit.sliderw, macroedit.sliderh

              local p = math.min(math.max(snap[snapedit_ss].data[s+snapedit_poffs].val,0),1)

              local py = (obj.sections[423].y + ss*macroedit.sech) + math.floor(macroedit.sech/2)-1

              xywh = {x = obj.sections[423].x,
                      y = (obj.sections[423].y + ss*macroedit.sech) + math.floor(macroedit.sech/2)-1,
                      w = obj.sections[423].w,
                      h = 2}
              if mem == false then
                f_Get_SSV(gui.color.blue)
              else
                f_Get_SSV(gui.color.red)
                gfx.a = 0.5
              end
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              if mem == false then
                xywh = {x = obj.sections[423].x + p*obj.sections[423].w - (w/2),
                        y = (obj.sections[423].y + ss*macroedit.sech) + math.floor(macroedit.sech/2) - (h/2),
                        w = w,
                        h = h}
                GUI_DrawBar(gui,'',xywh,skin.slidbutt,true,gui.color.black,gui.color.black,-2)

                if monitor == true then
                  local dv
                  if snap[snapedit_ss].data[s+snapedit_poffs].dispval then
                    dv = snap[snapedit_ss].data[s+snapedit_poffs].dispval
                  else
                    dv = GetParamDisp_Ctl(sctl.ctl)
                    snap[snapedit_ss].data[s+snapedit_poffs].dispval = dv
                  end
                  GUI_Str(gui, xywh2, dv, 5, gui.color.white, 0, 1)
                end
              end
            end

          end

        end
      end
    end

    gfx.dest = 1

  end

  ------------------------------------------------------------

  function GUI_DrawMacroEdit(obj, gui)

    local mctl = strips[tracks[track_select].strip][page].controls[macroctl_select]
    local macro = mctl.macroctl
    gfx.dest = 1008
    local w, h = gfx.getimgdim(1008)
    local update_size
    if obj.sections[300].w ~= w or obj.sections[300].h ~= h then update_size = true lupd.update_gfx = true end
    if lupd.update_gfx or lupd.update_surface or lupd.update_macroedit or lupd.update_macrobutt then
      if update_size then
        Img_SetDim(1008, obj.sections[300].w, obj.sections[300].h, true)
      end

      if lupd.update_gfx then --or update_surface then
        f_Get_SSV(gui.color.black)
        gfx.rect(0,
                 0,
                 obj.sections[300].w,
                 obj.sections[300].h, 1)

        local xywh = {x = obj.sections[408].x,
                      y = obj.sections[408].y - obj.sections[408].h,
                      w = obj.sections[408].w,
                      h = obj.sections[408].h}

        GUI_DrawButton(gui, 'ADD PARAMETERS', obj.sections[409], gui.color.white, gui.skol.butt1_txt, true, '', false)
        if macroedittype_select == 0 then
          GUI_textC(gui,xywh,'AUTOMATION',gui.color.white,-2)
          local macrofader = strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader
          if macrofader then
            GUI_DrawButton(gui, 'FADER '..string.format('%i',macrofader), obj.sections[408], gui.color.white, gui.skol.butt1_txt, true, '', false)
          else
            GUI_DrawButton(gui, 'NONE', obj.sections[408], -3, gui.color.black, false, '', false)
          end
          GUI_DrawButton(gui, 'CAPTURE A', obj.sections[411], gui.color.white, gui.skol.butt1_txt, true, '', false)
          GUI_DrawButton(gui, 'CAPTURE B', obj.sections[412], gui.color.white, gui.skol.butt1_txt, true, '', false)
          if settings_macroeditmonitor == true then
            GUI_DrawButton(gui, 'MONITOR', obj.sections[413], -4, gui.skol.butt1_txt, true, '', false)
            --GUI_DrawBar(gui, 'MONITOR', obj.sections[413], skin.butt18Y, true, gui.color.black, nil, -2)
          else
            --GUI_DrawBar(gui, 'MONITOR', obj.sections[413], skin.butt18, true, gui.color.black, nil, -2)
            GUI_DrawButton(gui, 'MONITOR', obj.sections[413], gui.color.white, gui.skol.butt1_txt, true, '', false)
          end
        end
      end

      if macroedittype_select == 0 then

        local w = gfx.getimgdim(def_eqcknobf)
        local h = ctl_files[def_eqcknobfctl].cellh
        local frames = ctl_files[def_eqcknobfctl].frames-1
        --DBG(tonumber(strips[tracks[track_select].strip][page].controls[macroctl_select].val))
        local v = F_limit(math.floor(strips[tracks[track_select].strip][page].controls[macroctl_select].val*frames),0,frames)
        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[410].x,
                 obj.sections[410].y,
                 obj.sections[410].w,
                 obj.sections[410].h,1)
        gfx.blit(def_eqcknobf, 1, 0, 0, v* h, w, h, obj.sections[410].x, obj.sections[410].y)
      end

      for m = 1, macroedit.pcnt do

        local mm = m-1

        if macro and macro[m+macroedit_poffs] then

          local ctl = strips[tracks[track_select].strip][page].controls[macro[m+macroedit_poffs].ctl]
          if ctl then

            if lupd.update_gfx then --or update_surface then
              local xywh = {x = obj.sections[402].x,
                            y = obj.sections[402].y + mm*macroedit.sech +2,
                            w = obj.sections[402].w+6,
                            h = macroedit.sech-4}
              f_Get_SSV('32 32 32')
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              if macroedittype_select == 0 then

                local xywh = {x = obj.sections[405].x,
                              y = obj.sections[405].y + mm*macroedit.sech +2,
                              w = obj.sections[405].w,
                              h = macroedit.sech-4}
                f_Get_SSV('32 32 32')
                gfx.rect(xywh.x,
                         xywh.y,
                         xywh.w,
                         xywh.h, 1)
                --GUI_textC(gui, xywh, lvar.macroscale_table[macro[m+macroedit_poffs].shape], gui.color.white, -2)
                GUI_Str(gui, xywh, lvar.macroscale_table[macro[m+macroedit_poffs].shape], 5, gui.color.white, -2, 1)
              end

              xywh = {x = obj.sections[402].x+30,
                      y = obj.sections[402].y + mm*macroedit.sech,
                      w = obj.sections[402].w,
                      h = macroedit.sech}
              --GUI_textsm_LJ(gui, xywh, ctl.param_info.paramname, gui.color.white, -2, xywh.w)
              GUI_Str(gui, xywh, ctl.param_info.paramname, 4, gui.color.white, -2, 1)
            end

            if lupd.update_gfx or lupd.update_macrobutt then
              local xywh = {x = obj.sections[4051].x,
                            y = obj.sections[4051].y + mm*macroedit.sech +2,
                            w = obj.sections[4051].w,
                            h = macroedit.sech-4}
              local c = gui.color.white
              if mctl.macromon == m then
                f_Get_SSV(gui.color.yellow)
                c = gui.color.black
              else
                f_Get_SSV('32 32 32')
              end
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)
              GUI_Str(gui, xywh, 'MON', 5, c, -4, 1)

              xywh = {x = obj.sections[406].x,
                      y = obj.sections[406].y + mm*macroedit.sech + 0.5*macroedit.sech - 10,
                      w = obj.sections[406].w,
                      h = 20}
              if macro[m+macroedit_poffs].mute then
                GUI_DrawBar(gui,'M',xywh,skin.butt18R,true,gui.color.black,gui.color.black,-2)
              else
                GUI_DrawBar(gui,'M',xywh,skin.butt18,true,gui.skol.sb_txt_on,gui.skol.sb_txt_off,-2)
              end

              if macroedittype_select == 0 then

                xywh = {x = obj.sections[414].x,
                        y = obj.sections[414].y + mm*macroedit.sech + 0.5*macroedit.sech - 10,
                        w = obj.sections[414].w,
                        h = 20}
                if macro[m+macroedit_poffs].bi then
                  GUI_DrawBar(gui,'BI',xywh,skin.butt18Y,true,gui.color.black,gui.color.black,-5)
                else
                  GUI_DrawBar(gui,'BI',xywh,skin.butt18,true,gui.skol.sb_txt_on,gui.color.black,-5)
                end

                xywh = {x = obj.sections[416].x,
                        y = obj.sections[416].y + mm*macroedit.sech + 0.5*macroedit.sech - 10,
                        w = obj.sections[416].w,
                        h = 20}
                if macro[m+macroedit_poffs].relative then
                  GUI_DrawBar(gui,'REL',xywh,skin.butt18Y,true,gui.color.black,gui.color.black,-5)
                else
                  GUI_DrawBar(gui,'REL',xywh,skin.butt18,true,gui.skol.sb_txt_on,gui.color.black,-5)
                end

                xywh = {x = obj.sections[415].x,
                        y = obj.sections[415].y + mm*macroedit.sech + 0.5*macroedit.sech - 10,
                        w = obj.sections[415].w,
                        h = 20}
                if macro[m+macroedit_poffs].inv then
                  GUI_DrawBar(gui,'INV',xywh,skin.butt18Y,true,gui.color.black,gui.color.black,-6)
                else
                  GUI_DrawBar(gui,'INV',xywh,skin.butt18,true,gui.skol.sb_txt_on,gui.color.black,-6)
                end
              end

              xywh = {x = obj.sections[407].x,
                      y = obj.sections[407].y + mm*macroedit.sech + 0.5*macroedit.sech - 10,
                      w = obj.sections[407].w,
                      h = 20}
              GUI_DrawBar(gui,'X',xywh,skin.butt18,true,gui.skol.sb_txt_on,gui.color.black,-2)
            end

            if macroedittype_select == 0 then

              local w, h = macroedit.sliderw, macroedit.sliderh

              local p = macro[m+macroedit_poffs].A_val
              local p2 = macro[m+macroedit_poffs].B_val

              local py = (obj.sections[403].y + mm*macroedit.sech) + math.floor(macroedit.sech/2)-1

              local xywh = {x = obj.sections[403].x - macroedit.sliderw*0.5-6,
                            y = obj.sections[403].y + mm*macroedit.sech +2,
                            w = obj.sections[403].w + macroedit.sliderw+12,
                            h = macroedit.sech-4}
              f_Get_SSV('32 32 32')
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              local xywh = {x = obj.sections[404].x - macroedit.sliderw*0.5-6,
                            y = obj.sections[404].y + mm*macroedit.sech +2,
                            w = obj.sections[404].w + macroedit.sliderw+12,
                            h = macroedit.sech-4}
              f_Get_SSV('32 32 32')
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              xywh = {x = obj.sections[403].x,
                      y = (obj.sections[403].y + mm*macroedit.sech) + math.floor(macroedit.sech/2)-1,
                      w = obj.sections[403].w,
                      h = 2}
              f_Get_SSV('16 16 16')
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              xywh.x = obj.sections[404].x
              gfx.rect(xywh.x,
                       xywh.y,
                       xywh.w,
                       xywh.h, 1)

              xywh = {x = obj.sections[403].x + p*obj.sections[403].w - (w/2),
                      y = (obj.sections[403].y + mm*macroedit.sech) + math.floor(macroedit.sech/2) - (h/2),
                      w = w,
                      h = h}
              if macro[m+macroedit_poffs].mute == true then
                f_Get_SSV(gui.color.red)
              else
                f_Get_SSV(gui.color.blue)
              end
              gfx.a = 0.6
              if macro[m+macroedit_poffs].relative == false then
                if macro[m+macroedit_poffs].bi == true then
                  x1 = F_limit(p*obj.sections[403].w - p2*obj.sections[403].w,0,obj.sections[403].w)
                  x2 = F_limit(p*obj.sections[403].w + p2*obj.sections[403].w,0,obj.sections[403].w)
                  gfx.line(obj.sections[403].x + x1,py,obj.sections[403].x + x2,py)
                else
                  gfx.line(obj.sections[403].x + p*obj.sections[403].w,py,obj.sections[403].x + p2*obj.sections[403].w,py)
                end
              end

              gfx.a = 1
              if macro[m+macroedit_poffs].relative ~= true then
                GUI_DrawBar(gui,'',xywh,skin.slidbutt,true,gui.color.black,gui.color.black,-2)
              end

              if macro[m+macroedit_poffs].mute == nil or macro[m+macroedit_poffs].mute == false then
                f_Get_SSV(gui.color.yellow)
                xywh.x = obj.sections[403].x + ctl.val*obj.sections[403].w
                xywh.w = 1
                xywh.y = xywh.y + 2
                xywh.h = xywh.h - 4
                gfx.rect(xywh.x,
                         xywh.y,
                         xywh.w,
                         xywh.h, 1)
              end

              xywh = {x = obj.sections[404].x + p2*obj.sections[404].w - (w/2),
                      y = (obj.sections[404].y + mm*macroedit.sech) + math.floor(macroedit.sech/2) - (h/2),
                      w = w,
                      h = h}
              if macro[m+macroedit_poffs].mute == true then
                f_Get_SSV(gui.color.red)
              else
                f_Get_SSV(gui.color.blue)
              end
              gfx.a = 0.6
              if macro[m+macroedit_poffs].bi == true or macro[m+macroedit_poffs].relative == true then
                gfx.line(obj.sections[404].x,py,obj.sections[404].x + p2*obj.sections[404].w,py)
              else
                gfx.line(obj.sections[404].x + p*obj.sections[404].w,py,obj.sections[404].x + p2*obj.sections[404].w,py)
              end
              gfx.a = 1
              GUI_DrawBar(gui,'',xywh,skin.slidbutt,true,gui.color.black,gui.color.black,-2)
            end
          end
        end
      end

      if lupd.update_gfx then --or update_surface then
        local xywh = {x = obj.sections[401].x+2,
                      y = obj.sections[401].y+2,
                      w = obj.sections[401].w-4,
                      h = obj.sections[401].h-4}
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[401].x,
                 obj.sections[401].y,
                 obj.sections[401].w,
                 obj.sections[401].h, 1)
        f_Get_SSV(gui.color.black)
        gfx.line(xywh.x,xywh.y,xywh.x+xywh.w,xywh.y+xywh.h,1)
        gfx.line(xywh.x+xywh.w,xywh.y,xywh.x,xywh.y+xywh.h,1)

      end


    end

    gfx.dest = 1

  end

  ------------------------------------------------------------

  function StripLayout_GetData()

    local x,y,w,h
    if obj.sections[10].w > obj.sections[10].h then
      x = math.floor((obj.sections[10].w-obj.sections[10].h)/2)
      y = 0
      w = obj.sections[10].h
      h = w
    else
      x = 0
      y = math.floor((obj.sections[10].h-obj.sections[10].w)/2)
      w = obj.sections[10].w
      h = w
    end

    local scale = 1-(w/surface_size.w)
    local striplayout_data = {scale = scale,
                        x = x,
                        y = y,
                        w = w,
                        h = h}
    return striplayout_data
  end

  function StripLayout_DrawImage(d)

    gfx.dest = 995
    Img_SetDim(995,d.w,d.h, true)
    gfx.blit(strip_image,0,0,0,0,surface_size.w,surface_size.h,0,0,d.w,d.h)
    gfx.dest = 1

  end

  function StripLayout_DrawImageGallery(d)

    gfx.dest = 993

    --local d = stlay_data
    if d and #d.reordered > 0 then

      local ww = obj.sections[10].w - 100

      local dh = 0
      local dw = d.reordered[#d.reordered].runx_e
      for i = 1, #d.reordered do
        dh = math.max(dh,d.reordered[i].h)
      end
      local sc = math.min(ww / dw,.4)

      local iw = math.ceil(dw*sc)
      local ih = math.ceil(dh*sc)
      --gfx.setimgdim(993,-1,-1)
      Img_SetDim(993,iw,ih)

      local ix = math.floor((ww-(dw*sc))/2)
      for i = 1, #d.loc do

        local ro = stlay_data.reordered[i].ro
        if not ro then
          ro = i
        end

        gfx.blit(strip_image,sc,0,
                 d.loc[ro].l, --*scale,
                 d.loc[ro].t, --*scale,
                 d.loc[ro].w, --*scale,
                 d.loc[ro].h, --*scale,
                 d.reordered[i].runx_s*sc,
                 math.floor((ih-d.reordered[i].h*sc)/2)
                 --[[d.reordered[i].w*sc,
                 d.reordered[i].h*sc]])
      end

    end
    gfx.dest = 1

  end

  function GUI_DrawStripLayout()

    if show_striplayout == true and stripgallery_view == 0 then
      striplayout_data = StripLayout_GetData()

      if lupd.update_gfx == true then
        StripLayout_DrawImage(striplayout_data)
      end

      local scale = surface_size.w/striplayout_data.w

      local px,py

      if striplayout_mt then
        --scale = 1-(scale*striplayout_mp)
        scale = 1+((scale-1)*(1-striplayout_mp))
        px = striplayout_data.x*striplayout_mp - (surface_offset.x * (1-striplayout_mp))
        py = striplayout_data.y*striplayout_mp - (surface_offset.y * (1-striplayout_mp))

        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10].x,
                 obj.sections[10].y,
                 obj.sections[10].w,
                 obj.sections[10].h,1)

        gfx.blit(995,scale,0,0,
                          0,
                          surface_size.w,
                          surface_size.h,
                          math.floor(obj.sections[10].x + px),
                          math.floor(obj.sections[10].y + py))

      else
        scale = 1-striplayout_data.scale
        px = striplayout_data.x
        py = striplayout_data.y

        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10].x,
                 obj.sections[10].y,
                 obj.sections[10].w,
                 obj.sections[10].h,1)
        f_Get_SSV(backcol)
        gfx.rect(obj.sections[10].x+px,
                 obj.sections[10].y+py,
                 surface_size.w*scale,
                 surface_size.h*scale,1)

        if stlay_data and #stlay_data.reordered > 0 then
          for i = 1, #stlay_data.loc do

            local ro = stlay_data.reordered[i].ro
            if not ro then
              ro = i
            end
            gfx.blit(995,1,0,
                      math.floor(stlay_data.loc[ro].l*scale),
                      math.floor(stlay_data.loc[ro].t*scale),
                      math.floor(stlay_data.loc[ro].w*scale),
                      math.floor(stlay_data.loc[ro].h*scale),
                      math.floor(obj.sections[10].x + px+stlay_data.reordered[i].l*scale),
                      math.floor(obj.sections[10].y + py+stlay_data.reordered[i].t*scale))


          end
        else

          GUI_textC(gui,obj.sections[10],'STRIP LAYOUT VIEW: No strips on page.', '96 96 96', 0)

        end
      end

      if striplayout_selstripid and striplayout_mt == nil then

        gfx.a = 0.8
        local ro
        for i = 1, #stlay_data.reordered do
          if striplayout_selstrip == stlay_data.reordered[i].stripid then
            ro = i
            break
          end
        end
        if ro then
          local xywh = {x = stlay_data.reordered[ro].l,
                        y = stlay_data.reordered[ro].t,
                        w = stlay_data.reordered[ro].w,
                        h = stlay_data.reordered[ro].h}
          f_Get_SSV(gui.color.yellow)
          gfx.roundrect(math.floor(obj.sections[10].x + px + xywh.x*scale),
                         math.floor(obj.sections[10].y + py + xywh.y*scale),
                         math.floor(xywh.w*scale),
                         math.floor(xywh.h*scale),8,1)
        end
        gfx.a = 1
      end

    elseif stripgallery_view == 0 then
      local x,y,w,h

      striplayout_mp = 1-striplayout_mp

      striplayout_data = StripLayout_GetData()
      local scale = (surface_size.w/striplayout_data.w)

      --local scale = striplayout_data.scale

      local px,py

      --scale = 1-(striplayout_data.scale*striplayout_mp)
      scale = 1+((scale-1)*(1-striplayout_mp))
      px = striplayout_data.x*striplayout_mp - (surface_offset.x * (1-striplayout_mp))
      py = striplayout_data.y*striplayout_mp - (surface_offset.y * (1-striplayout_mp))
      gfx.blit(995,scale,0,0,
                          0,
                          surface_size.w,
                          surface_size.h,
                          math.floor(obj.sections[10].x + px),
                          math.floor(obj.sections[10].y + py))


    elseif show_striplayout == true and stripgallery_view == 1 then

      if striplayout_mt and striplayout_mp then

        if lupd.update_gfx == true or lupd.update_surface == true then
          StripLayout_DrawImageGallery(stlay_data)
        end

        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10].x,
                 obj.sections[10].y,
                 obj.sections[10].w,
                 obj.sections[10].h,1)

        local w, h = gfx.getimgdim(993)
        local d = stlay_data
        if d and #d.reordered > 0 then
          local scale = math.max((d.reordered[#d.reordered].runx_e)/w,.4)
          scale = 1+((scale-1)*(1-striplayout_mp))
          local hh = h*scale
          local xs = -stlay_data.xpos+obj.sections[10].x
          local xe = math.floor(obj.sections[10].x + (obj.sections[10].w - w)/2)
          local xd = xe-xs
          local ix = xs + xd*striplayout_mp
          local iy = math.floor(obj.sections[10].y + (obj.sections[10].h - hh)/2)
        --gfx.a = 0.5+striplayout_mp*0.5

          gfx.blit(993,scale,0,
                    0,
                    0,
                    w,
                    h,
                    ix,
                    iy)

        end

      else
        if lupd.update_gfx == true or lupd.update_surface == true then
          StripLayout_DrawImageGallery(stlay_data)
        end

        f_Get_SSV(gui.color.black)
        gfx.rect(obj.sections[10].x,
                 obj.sections[10].y,
                 obj.sections[10].w,
                 obj.sections[10].h,1)

        local w, h = gfx.getimgdim(993)
        local d = stlay_data
        if d and #d.reordered > 0 then

          local ix = math.floor(obj.sections[10].x + math.floor(obj.sections[10].w - w)/2)
          local iy = math.floor(obj.sections[10].y + math.floor(obj.sections[10].h - h)/2)
          gfx.blit(993,1,0,
                    0,
                    0,
                    w,
                    h,
                    ix,
                    iy)

          if striplayout_selstripid and striplayout_mt == nil then
            gfx.a = 0.8
            local ro
            for i = 1, #d.reordered do
              if striplayout_selstrip == d.reordered[i].stripid then
                ro = i
                break
              end
            end
            if ro then
              local ww = obj.sections[10].w - 100
              local dh = d.hmax
              local dw = d.reordered[#d.reordered].runx_e
              local sc = math.min(ww / dw,.4)

              local xywh = {x = d.reordered[ro].runx_s*sc,
                            y = iy,
                            w = d.reordered[ro].w*sc,
                            h = h}
              f_Get_SSV(gui.color.yellow)
              gfx.roundrect(math.floor(ix + xywh.x),
                             math.floor(iy),
                             math.floor(xywh.w),
                             math.floor(xywh.h),4,1)
            end
            gfx.a = 1

          end
        else

          GUI_textC(gui,obj.sections[10],'GALLERY LAYOUT VIEW: No strips on page.', '96 96 96', 0)

        end

      end

    elseif stripgallery_view == 1 then


      if lupd.update_gfx == true or lupd.update_surface == true then
        StripLayout_DrawImageGallery(stlay_data)
      end

      f_Get_SSV(gui.color.black)
      gfx.rect(obj.sections[10].x,
               obj.sections[10].y,
               obj.sections[10].w,
               obj.sections[10].h,1)

      local w, h = gfx.getimgdim(993)
      local d = stlay_data
      if d and #d.reordered > 0 then
        local scale = math.max((d.reordered[#d.reordered].runx_e)/w,.4)
        --local scale = math.max(d.hmax / h,.4)
        scale = 1+((scale-1)*striplayout_mp)

        local hh = h*scale
        local ww = w*scale
        local xe = -stlay_data.xpos+obj.sections[10].x
        local xs = math.floor(obj.sections[10].x + (obj.sections[10].w - w)/2)
        local xd = xe-xs
        local ix = xs + xd*striplayout_mp
        local iy = math.floor(obj.sections[10].y + (obj.sections[10].h - hh)/2)
       -- gfx.a = 0.5+striplayout_mp*0.5
        gfx.blit(993,scale,0,
                  0,
                  0,
                  w,
                  h,
                  ix,
                  iy)


      else

        GUI_textC(gui,obj.sections[10],'GALLERY VIEW: No strips on page.', '96 96 96', 0)

      end
    end
  end

  function GUI_DrawGallery()

    gfx.a = 1

    f_Get_SSV(backcol)
    gfx.rect(obj.sections[10].x,
             obj.sections[10].y,
             obj.sections[10].w,
             obj.sections[10].h,1)

    if stripgallery_swipemt then

      local w, h = gfx.getimgdim(993)
      local d = stlay_data
      local xs = stripgallery_swipe.xstart
      local xe = stripgallery_swipe.xend
      local xd = -(xe-xs)
      d.xpos = (xs - (xd * stripgallery_swipe.mp))

    end
    if stlay_data and #stlay_data.reordered > 0 then
      local st,en = 1,1
      local px = stlay_data.xpos or 0
      while stlay_data.reordered[st] and px > stlay_data.reordered[st].runx_e do --+ gallery_itemgap do
        st=st+1
      end
      en = st
      while stlay_data.reordered[en] and px+obj.sections[10].w > stlay_data.reordered[en].runx_s do
        en=en+1
      end
      en=en-1
      local x = 0

      for i = st,en do
        local t = math.floor((obj.sections[10].h/2) - (stlay_data.reordered[i].h/2))
        if i == st then
          local sx = px-stlay_data.reordered[i].runx_s
          local sw = stlay_data.reordered[i].w - sx
          if px < 0 then --eliminate width error
            sw = sw - 1
          end
          local dx = sw-stlay_data.reordered[i].w
          gfx.blit(strip_image,1,0,
                    math.floor(stlay_data.reordered[i].l--[[+sx]]),
                    stlay_data.reordered[i].t,
                    stlay_data.reordered[i].w,
                    stlay_data.reordered[i].h,
                    math.floor(obj.sections[10].x + x + dx),
                    math.floor(obj.sections[10].y + t))
          x=x+sw + gallery_itemgap
        elseif i == en then
          local sx = 0
          local sw = ((px+obj.sections[10].w)-stlay_data.reordered[i].runx_s)
          local dw = stlay_data.reordered[i].w - sw
          gfx.blit(strip_image,1,0,
                    stlay_data.reordered[i].l,
                    stlay_data.reordered[i].t,
                    stlay_data.reordered[i].w,
                    stlay_data.reordered[i].h,
                    math.floor(obj.sections[10].x + x),
                    math.floor(obj.sections[10].y + t))
        else

          gfx.blit(strip_image,1,0,
                    stlay_data.reordered[i].l,
                    stlay_data.reordered[i].t,
                    stlay_data.reordered[i].w,
                    stlay_data.reordered[i].h,
                    math.floor(obj.sections[10].x + x),
                    math.floor(obj.sections[10].y + t))
          x=x+stlay_data.reordered[i].w + gallery_itemgap
        end
      end
    else

      GUI_textC(gui,obj.sections[10],'GALLERY VIEW: No strips on page.', '96 96 96', 0)

    end
  end

  ------------------------------------------------------------

  function GUI_DrawLFOBar(obj, gui)

    if modwinsz.minimized == true then return end

    gfx.dest = 992
    local m = modulators[mod_select]
    if m then

      local barw = ((obj.sections[1101].w-2) / m.steps)
      --local dbw = math.max(barw,1)
      local bw = 0
      if m.steps < (obj.sections[1101].w/2) then
        bw = 1
      end

      if modbaredit then

        for i = 1, #modbaredit do

          local x = obj.sections[1101].x + math.floor((modbaredit[i]-1) * barw)
          local w = math.floor(modbaredit[i]*barw) - math.floor((modbaredit[i]-1) * barw) - bw
          local h
          if m.mode >= 2 then
            h = math.floor(obj.sections[1101].h * ((m.data[modbaredit[i]])/(m.max-m.min)))
          else
            h = math.floor(obj.sections[1101].h * m.data[modbaredit[i]])
          end
          h = math.min(h, obj.sections[1101].h)
          f_Get_SSV(gui.skol.mod_bg)
          gfx.rect(x+bw,obj.sections[1101].y,math.max(w,1),obj.sections[1101].h,1)

          local c
          if m.mode >= 2 then
            c = 0.1 + ((m.data[modbaredit[i]])/(m.max-m.min)) * 0.9
          else
            c = 0.1 + m.data[modbaredit[i]] * 0.9
          end

          gfx.r = gui.skol.modbase_r+c*gui.skol.modmult_r
          gfx.g = gui.skol.modbase_g+c*gui.skol.modmult_g
          gfx.b = gui.skol.modbase_b+c*gui.skol.modmult_b
          gfx.rect(x+bw,obj.sections[1101].y + (obj.sections[1101].h-h),math.max(w,1),h,1)

        end

        modbaredit = {}
        modbaridx = {}

        local bars = lvar.sync_mult_table[m.syncv]
        local barsteps = m.steps / bars
        f_Get_SSV(gui.skol.mod_barlines)
        if bars >= 2 then
          for i = 2, bars do
            local x = obj.sections[1101].x + ((i-1)*barsteps) * barw
            gfx.line(x,obj.sections[1101].y,x,obj.sections[1101].y+obj.sections[1101].h)
          end
        end
        local y = obj.sections[1101].y + math.floor(obj.sections[1101].h/2)
        gfx.line(obj.sections[1101].x+1,y,obj.sections[1101].x+obj.sections[1101].w-2,y)
      end
    end
    gfx.dest = 1
  end

  function GUI_DrawLFOPos(obj, gui)

    if modwinsz.minimized == true then return end

    gfx.dest = 992
    local m = modulators[mod_select]
    if m then

      local barw = ((obj.sections[1101].w-2) / m.steps)
      --local dbw = math.max(barw,1)
      local bw = 0
      if m.steps < (obj.sections[1101].w/2) then
        bw = 1
      end
      local opos = m.oopos

      if opos and m.data[opos] then

        local x = obj.sections[1101].x + math.floor((opos-1) * barw)
        local w = math.floor(opos*barw) - math.floor((opos-1) * barw) - bw
        local h
        if m.mode >= 2 then
          h = math.floor(obj.sections[1101].h * ((m.data[opos])/(m.max-m.min)))
        else
          h = math.floor(obj.sections[1101].h * m.data[opos])
        end
        h = math.min(h, obj.sections[1101].h)

        f_Get_SSV(gui.skol.mod_bg)
        gfx.rect(x+bw,obj.sections[1101].y,math.max(w,1),obj.sections[1101].h+modpos,1)
        f_Get_SSV('32 32 32')
        gfx.rect(x+bw,obj.sections[1101].y+obj.sections[1101].h+1,math.max(w,1),modpos,1)

        local c
        if m.mode >= 2 then
          c = 0.1 + ((m.data[opos])/(m.max-m.min)) * 0.9
        else
          c = 0.1 + m.data[opos] * 0.9
        end
        gfx.r = gui.skol.modbase_r+c*gui.skol.modmult_r
        gfx.g = gui.skol.modbase_g+c*gui.skol.modmult_g
        gfx.b = gui.skol.modbase_b+c*gui.skol.modmult_b
        gfx.rect(x+bw,obj.sections[1101].y + (obj.sections[1101].h-h),math.max(w,1),h,1)

      end
      if m.pos and m.data[m.pos] then

        local x = obj.sections[1101].x + math.floor((m.pos-1) * barw)
        local w = math.floor(m.pos*barw) - math.floor((m.pos-1) * barw) - bw
--        local h = math.floor(obj.sections[1101].h * m.data[m.pos])
        local h
        if m.mode >= 2 then
          h = math.floor(obj.sections[1101].h * ((m.data[m.pos])/(m.max-m.min)))
        else
          h = math.floor(obj.sections[1101].h * m.data[m.pos])
        end
        h = math.min(h, obj.sections[1101].h)

        if gui.skol.mod_hl_t > 0 then
          f_Get_SSV(gui.skol.mod_bg)
          gfx.rect(x+bw,obj.sections[1101].y,math.max(w,1),obj.sections[1101].h,1)

          local c
          if m.mode >= 2 then
            c = 0.1 + ((m.data[m.pos])/(m.max-m.min)) * 0.9
          else
            c = 0.1 + m.data[m.pos] * 0.9
          end
          gfx.r = gui.skol.modbase_r+c*gui.skol.modmult_r
          gfx.g = gui.skol.modbase_g+c*gui.skol.modmult_g
          gfx.b = gui.skol.modbase_b+c*gui.skol.modmult_b
          gfx.rect(x+bw,obj.sections[1101].y + (obj.sections[1101].h-h),math.max(w,1),h,1)

          f_Get_SSV(gui.skol.mod_hl)
          gfx.mode = 3
          gfx.a=gui.skol.mod_hl_t
          gfx.rect(x+bw,obj.sections[1101].y + (obj.sections[1101].h-h),math.max(w,1),h,1)
          gfx.mode = gmode
          gfx.a=1
        end

        f_Get_SSV(gui.skol.mod_stepind)
        gfx.rect(x+bw,obj.sections[1101].y + obj.sections[1101].h+1,math.max(w,1),modpos-1,1)

      end
      m.opos = m.pos

      local bars = lvar.sync_mult_table[m.syncv]
      local barsteps = m.steps / bars
      f_Get_SSV(gui.skol.mod_barlines)
      if bars >= 2 then
        for i = 2, bars do
          local x = obj.sections[1101].x + ((i-1)*barsteps) * barw
          gfx.line(x,obj.sections[1101].y,x,obj.sections[1101].y+obj.sections[1101].h)
        end
      end
      local y = obj.sections[1101].y + math.floor(obj.sections[1101].h/2)
      gfx.line(obj.sections[1101].x+1,y,obj.sections[1101].x+obj.sections[1101].w-2,y)

    end
    gfx.dest = 1
  end

  function GUI_DrawLFOCtls(obj, gui)

    if modwinsz.minimized == true then return end

    gfx.dest = 992

    local m = modulators[mod_select]
    if m then
      GUI_DrawButton(gui,'STEP MULT: x'..lvar.divmult_table[m.stepsmult],obj.sections[1102],-1,gui.color.white,true)
      --GUI_DrawButton(gui,'-',obj.sections[1103],-1,gui.color.white,true)

      local c = -1
      if modulators[mod_select].active then
        c = -4
      end
      GUI_DrawButton(gui,'ON',obj.sections[1106],c,gui.skol.butt2_txt,true)

      GUI_DrawButton(gui,'LENGTH: '..lvar.sync_table[m.syncv],obj.sections[1104],-1,gui.color.white,true)
      local c = -1
      if m.interpolate == true then
        c = -4
      end
      GUI_DrawButton(gui,'SMOOTH',obj.sections[1105],c,gui.color.white,true)

      local c = -1
      GUI_DrawButton(gui,'STEPS: '..m.div,obj.sections[1107],c,gui.color.white,true)

      local txt
      if m.offset == 0.5 then
        txt = 'NO SHIFT'
      else
        local bt = CalcBeatTime()
        shifttime = -(((0.5-m.offset)*2) * bt * 1000)
        txt = 'SHIFT: '..round(shifttime)..'ms'
      end
      GUI_DrawButton(gui,txt,obj.sections[1108],c,gui.color.white,true)
      GUI_DrawButton(gui,'RANDOMIZE',obj.sections[1113],c,gui.color.white,true)
      if m.mode >= 2 then
        c = -4
      end
      GUI_DrawButton(gui,lvar.lfomode_table[m.mode],obj.sections[1114],c,gui.color.white,true)

      local c = -1
      if m.min > 0 then
        c = -4
      end
      GUI_DrawButton(gui,'MIN: '..math.floor(m.min*takeswitch_max),obj.sections[1109],c,gui.color.white,true)

      local c = -1
      if m.max < 1 then
        c = -4
      end
      local maxx = takeswitch_max
      if m.mode == 3 then
        maxx = lvar.maxsamples-1
      end
      GUI_DrawButton(gui,'MAX: '..math.floor(m.max*maxx),obj.sections[1110],c,gui.color.white,true)

    end

    gfx.dest = 1

  end

  function GUI_DrawLFOEdit(obj, gui)

    gfx.dest = 992
    if resize_display or lupd.update_gfx or modwinsz.resize then
      --gfx.setimgdim(992, -1, -1)
      if not settings_moddock and obj.sections[1100].w > obj.sections[10].w then
        obj.sections[1100].w = 800
        modwinsz.w = obj.sections[1100].w
      end
      Img_SetDim(992, obj.sections[1100].w,obj.sections[1100].h)
      modwinsz.resize = nil
    end

    --gfx.setimgdim(992, -1, -1)
    Img_SetDim(992, obj.sections[1100].w,obj.sections[1100].h)
    if settings_moddock == true and modwinsz and modwinsz.minimized == true then
      GUI_DrawPanel(obj.sections[1100],false,'MODULATORS')
    else
      local alpha=1
      if settings_moddock == true then
        alpha = 1
      end
      GUI_DrawPanel(obj.sections[1100],false,'MODULATORS - MOD '..string.format('%i',mod_select),nil,alpha)
    end

    local b
    if settings_moddock == true then
      b = gui.color.white
    else
      b = -5
    end
    GUI_DrawButton(gui, 'DOCK', obj.sections[1123], b, gui.skol.butt1_txt, true, '', false, -2, true)

    if modwinsz.minimized == true then
      gfx.dest = 1
      return
    end

    local m = modulators[mod_select]

    if m then

      local b = gui.color.white
      GUI_DrawButton(gui, '<', obj.sections[1115], b, gui.skol.butt1_txt, true, '', false, -2, true)
      GUI_DrawButton(gui, '>', obj.sections[1116], b, gui.skol.butt1_txt, true, '', false, -2, true)
      GUI_DrawButton(gui, 'ASSIGN', obj.sections[1117], b, gui.skol.butt1_txt, true, '', false, -2, true)
      if m.targets and #m.targets > 0 then
        GUI_DrawButton(gui, 'CLEAR TARGETS', obj.sections[1118], b, gui.skol.butt1_txt, true, '', false, -2, true)
      end

      local barw = ((obj.sections[1101].w-2) / m.steps)
      --local dbw = math.max(barw,1)
      local bw = 0
      --if barw >= 2 then
      --  bw = -1
      --end
      f_Get_SSV(gui.skol.mod_bg)
      gfx.rect(obj.sections[1101].x-2,obj.sections[1101].y,math.ceil(barw*m.steps+4),obj.sections[1101].h,1)
      f_Get_SSV('32 32 32')
      gfx.rect(obj.sections[1101].x-2,obj.sections[1101].y+obj.sections[1101].h+1,math.ceil(barw*m.steps+4),modpos-1,1)
      f_Get_SSV(gui.skol.mod_baroutline)
      gfx.rect(obj.sections[1101].x-2,obj.sections[1101].y-2,math.ceil(barw*m.steps+4),obj.sections[1101].h+4+modpos,0)

      if m.steps < (obj.sections[1101].w/2) then
        bw = 1
      end

      for i = 1, m.steps do
        local c
        if m.mode >= 2 then
          c = 0.1 + ((m.data[i])/(m.max-m.min)) * 0.9
        else
          c = 0.1 + m.data[i] * 0.9
        end
        gfx.r = gui.skol.modbase_r+c*gui.skol.modmult_r
        gfx.g = gui.skol.modbase_g+c*gui.skol.modmult_g
        gfx.b = gui.skol.modbase_b+c*gui.skol.modmult_b

        --f_Get_SSV(gui.color.white)
        local x = obj.sections[1101].x + math.floor((i-1) * barw)
        local w = math.floor(i*barw) - math.floor((i-1) * barw) - bw
        local h
        if m.mode >= 2 then
          h = math.floor(obj.sections[1101].h * ((m.data[i])/(m.max-m.min)))
        else
          h = math.floor(obj.sections[1101].h * m.data[i])
        end
        h = math.min(h, obj.sections[1101].h)

        gfx.rect(x+bw,obj.sections[1101].y + (obj.sections[1101].h-h),math.max(w,1),h,1)

      end

      local bars = lvar.sync_mult_table[m.syncv]
      local barsteps = m.steps / bars
      f_Get_SSV(gui.skol.mod_barlines)
      if bars >= 2 then
        for i = 2, bars do
          local x = obj.sections[1101].x + ((i-1)*barsteps) * barw
          gfx.line(x,obj.sections[1101].y,x,obj.sections[1101].y+obj.sections[1101].h)
        end
      end
      local y = obj.sections[1101].y + math.floor(obj.sections[1101].h/2)
      gfx.line(obj.sections[1101].x+1,y,obj.sections[1101].x+obj.sections[1101].w-2,y)

    else

      f_Get_SSV('0 0 0')
      gfx.rect(obj.sections[1101].x,obj.sections[1101].y,obj.sections[1101].w,obj.sections[1101].h,1)
      f_Get_SSV(gui.skol.mod_baroutline)
      gfx.rect(obj.sections[1101].x-2,obj.sections[1101].y-2,obj.sections[1101].w+4,obj.sections[1101].h+4,0)

    end

    GUI_DrawLFOCtls(obj, gui)

    gfx.dest = 1

  end

  function GUI_DrawMorph(obj, gui)

    --gfx.dest = 1
    local w,h = gfx.getimgdim(skin.morph_pop)
    local lw, lh = gfx.getimgdim(skin.morph_lp)
    lw = lw /3
    local y = obj.sections[10].y + 6
    local x = obj.sections[10].x + obj.sections[10].w - w - 6
    morph_puw = {x = x, y = y, w = w, h = 0}
    local xywh = {x = x, y = y, w = w, h = h}
    local xywhsc = {x = x, y = y, w = 40, h = h}
    local slidetime = 0.2
    for d = 1, #morph_data do

      if morph_data[d].active then

        morph_puw.h = morph_puw.h + h
        local strip = morph_data[d].strip
        local page = morph_data[d].page
        local sstype = morph_data[d].sstype
        local ss = morph_data[d].targetss
        local p

        if morph_data[d].morph_scale ~= 11 then
          p = macScale(morph_data[d].morph_scale,morph_data[d].p)
        else
          p = morph_data[d].p
        end
        local xoff = macScale(4,(1-(math.min(reaper.time_precise() - morph_data[d].popstart,slidetime)/slidetime))) * (w+6)

        gfx.a = 1
        if xoff > 0 then
          gfx.blit(strip_image, 1, 0, surface_offset.x + x - obj.sections[10].x, surface_offset.y + y - obj.sections[10].y, w+10, h, x, y)
          morph_data[d].drawback = true
        elseif morph_data[d].drawback then
          gfx.blit(strip_image, 1, 0, surface_offset.x + x - obj.sections[10].x, surface_offset.y + y - obj.sections[10].y, w+10, h, x, y)
          morph_data[d].drawback = nil
        end
        --gfx.a = 0.8
        gfx.blit(skin.morph_pop, 1, 0, 0, 0, w, h, x+xoff, y)

        gfx.a = 1
        if morph_data[d].morph_loop == 2 then
          if morph_data[d].dir == 1 then
            gfx.blit(skin.morph_lp, 1, 0, lw*1, 0, lw, h, x+xoff+97, y+33)
          else
            gfx.blit(skin.morph_lp, 1, 0, lw*0, 0, lw, h, x+xoff+97, y+33)
          end
        elseif morph_data[d].morph_loop == 3 then
          gfx.blit(skin.morph_lp, 1, 0, lw*2, 0, lw, h, x+xoff+97, y+33)
        else
          if morph_data[d].dir == 1 then
            gfx.blit(skin.morph_lp, 1, 0, lw*1, 0, lw, h, x+xoff+97, y+33)
          else
            gfx.blit(skin.morph_lp, 1, 0, lw*0, 0, lw, h, x+xoff+97, y+33)
          end
        end
        if morph_data[d].paused then
          gfx.blit(skin.morph_popbarr, 1, 0, 0, 0, math.floor(w*p), h, x+xoff+1, y)
          f_Get_SSV('255 0 0')
          gfx.rect(x + 75, y + 33, 6, 14, 1)
          gfx.rect(x + 84, y + 33, 6, 14, 1)
        else
          gfx.blit(skin.morph_popbar, 1, 0, 0, 0, math.floor(w*p), h, x+xoff+1, y)
        end

        gfx.a = 1
        local txt = 'PAGE'
        if sstype > 1 then
          txt = string.upper(snapshots[strip][page][sstype].subsetname)
        end
        xywh.x = x+xoff
        GUI_textC(gui, xywh, txt, gui.color.black, -5, 1, -14)
        xywhsc.x = x+xoff
        GUI_textC(gui, xywhsc, string.upper(lvar.macroscale_sm_table[morph_data[d].morph_scale]), gui.color.black, -8, 1, 11)

        y = y + h
        xywh.y = y
        xywhsc.y = y
      end
    end

  end

  function GUI_DrawKeyboardOverlay(obj, gui)

    local keys = lvar.kb.keys
    local wkeys = lvar.kb.wkeys
    local wkey_w = lvar.kb.wkey_w
    local bkey_w = lvar.kb.bkey_w
    local wkey_h = lvar.kb.wkey_h
    local bkey_h = lvar.kb.bkey_h

    local kstart = math.floor(lvar.kb.kstart) or -1
    local kend = math.floor(lvar.kb.kend) or -1

    gfx.dest = 908
    --gfx.setimgdim(908,-1,-1)
    Img_SetDim(908,wkey_w*wkeys,wkey_h)

    local key = -1
    f_Get_SSV(gui.color.green)

    local ph = 20
    local ph_b = 20
    local pcol = '153 153 255'
    local pcol_b = '153 153 255'
    local py = wkey_h-ph
    local py_b = bkey_h-ph_b-1
    local pkey = 72 + lvar.rs.pitch

    for k = 0, wkeys do
      gfx.a = 1

      local b = k % 7
      if b == 1 or b == 2 or b == 4 or b == 5 or b == 6 then

        key = key + 2
        if key >= kstart and key <= kend then
          gfx.rect(k*wkey_w+1,
                   0,
                   wkey_w-1,
                   wkey_h, 1)
        end

        --black key
        if key == kstart or key-2 == kend then
          f_Get_SSV(gui.color.black)
          gfx.a = 1
          gfx.rect(k*wkey_w - math.floor(bkey_w/2),
                   0,
                   bkey_w,
                   bkey_h, 1)
          f_Get_SSV(gui.color.green)
        else
          if key-1 >= kstart and key-1 <= kend then
            f_Get_SSV(gui.color.black)
            gfx.a = 1
            gfx.rect(k*wkey_w - math.floor(bkey_w/2),
                     0,
                     bkey_w,
                     bkey_h, 1)
            f_Get_SSV(gui.color.green)
            gfx.a = 0.5
            gfx.rect(k*wkey_w - math.floor(bkey_w/2)+1,
                     0,
                     bkey_w-2,
                     bkey_h-1, 1)
            gfx.a = 1

          end

        end

        if key == pkey then

          local tl = k*wkey_w
          f_Get_SSV(pcol)
          gfx.rect(tl+1,
                   py,
                   wkey_w-1,
                   ph, 1)
          --[[f_Get_SSV(gui.color.black)
          gfx.line(tl,
                   py,
                   tl + wkey_w,
                   py)]]
          f_Get_SSV(gui.color.green)

        elseif key-1 == pkey then

          local tl = k*wkey_w - math.floor(bkey_w/2)
          f_Get_SSV(pcol_b)
          gfx.rect(tl+1,
                   py_b,
                   bkey_w-2,
                   ph_b, 1)
          --[[f_Get_SSV(gui.color.black)
          gfx.line(tl,
                   py_b,
                   tl + bkey_w-1,
                   py_b)]]
          f_Get_SSV(gui.color.green)

        end

      else

        key = key + 1

        if key >= kstart and key <= kend then
          gfx.rect(k*wkey_w+1,
                   0,
                   wkey_w-1,
                   wkey_h, 1)
          if b == 0 then
            local xywh = {x = 0, y = wkey_h - 20, w = wkey_w, h = 20}
            xywh.x = (k) * wkey_w
            local o = math.floor(k / 7)-1
            GUI_textC(gui, xywh, 'C'..o, gui.color.black, -5, 1)
            f_Get_SSV(gui.color.green)

          end
        end

        if key == pkey then

          local tl = k*wkey_w
          f_Get_SSV(pcol)
          gfx.rect(tl+1,
                   py,
                   wkey_w-1,
                   ph, 1)
          --[[f_Get_SSV(gui.color.black)
          gfx.line(tl,
                   py,
                   tl + wkey_w,
                   py)]]

          if b == 0 then
            local xywh = {x = 0, y = wkey_h - 20, w = wkey_w, h = 20}
            xywh.x = (k) * wkey_w
            local o = math.floor(k / 7)-1
            GUI_textC(gui, xywh, 'C'..o, gui.color.black, -5, 1)
          end
          f_Get_SSV(gui.color.green)
        end


      end

    end

    gfx.a = 1
    gfx.dest = 1

  end

  function GUI_DrawKeyboard(obj, gui)

    local keys = 128
    local wkeys = 75
    local wkey_w = 18
    local bkey_w = 10
    local wkey_h = 80
    local bkey_h = 55

    gfx.dest = 909
    gfx.a = 1

    Img_SetDim(909,wkey_w*wkeys,wkey_h*2, true)

    f_Get_SSV(gui.color.white)
    gfx.rect(0,
             0,
             wkey_w*wkeys,
             wkey_h, 1)

    local kcol = -1
    for k = 0, wkeys do

      f_Get_SSV(gui.color.black)
      gfx.line(k*wkey_w,0,k*wkey_w,wkey_h)
      local b = k % 7
      local o = math.floor(k / 7)-1
      if b == 1 or b == 2 or b == 4 or b == 5 or b == 6 then
        gfx.rect(k*wkey_w - math.floor(bkey_w/2),
                 0,
                 bkey_w,
                 bkey_h, 1)
      end
      if b == 1 then
        local xywh = {x = 0, y = wkey_h - 20, w = wkey_w, h = 20}
        xywh.x = (k-1) * wkey_w
        GUI_textC(gui, xywh, 'C'..o, gui.color.black, -5, 1)
      end

      --colmask
      gfx.g = 0
      gfx.b = 0

      if b == 1 or b == 2 or b == 4 or b == 5 or b == 6 then

        kcol = kcol + 2
        gfx.r = kcol/255

        gfx.rect(k*wkey_w,
                 wkey_h,
                 wkey_w,
                 wkey_h, 1)

        --black key
        gfx.r = (kcol - 1)/255
        gfx.rect(k*wkey_w - math.floor(bkey_w/2),
                 wkey_h,
                 bkey_w,
                 bkey_h, 1)

      else

        kcol = kcol + 1
        gfx.r = kcol/255
        gfx.rect(k*wkey_w,
                 wkey_h,
                 wkey_w,
                 wkey_h, 1)

      end

    end

    lvar.kb = {keys = keys, wkeys = wkeys, wkey_w = wkey_w, bkey_w = bkey_w, wkey_h = wkey_h, bkey_h = bkey_h, offset = 21*wkey_w}

    gfx.dest = 1

  end

  function GUI_DrawSampleManager(obj, gui)

    gfx.dest = 986
    --gfx.setimgdim(986,-1,-1)
    Img_SetDim(986,obj.sections[1300].w,obj.sections[1300].h)

    gfx.a = 1

    if rs5k_select then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[rs5k_select]

      local butt_h = tb_butt_h

      GUI_DrawPanel(obj.sections[1300],false,'RS5K SAMPLE MANAGER ('..ctl.param_info.paramname..')')

      GUI_DrawButton(gui, ctl.rsdata.samplefolder or '[No folder selected]', obj.sections[1301], gui.color.white, gui.skol.butt1_txt, true, 'FOLDER',false,gui.fontsz.butt)
      GUI_DrawButton(gui, lvar.rs.out, obj.sections[1305], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)

      GUI_DrawButton(gui, 'ADD', obj.sections[1306], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
      GUI_DrawButton(gui, 'REPLACE', obj.sections[1307], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
      GUI_DrawButton(gui, 'CLEAR', obj.sections[1308], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
      local bc = gui.color.white
      if smshowfavs then
        bc = -4
      end

      GUI_DrawButton(gui, 'SORT FAVS', obj.sections[1309], bc, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)

      f_Get_SSV(gui.skol.lst_bg)
      gfx.rect(obj.sections[1302].x,
               obj.sections[1302].y,
               obj.sections[1302].w,
               obj.sections[1302].h, 1)
      f_Get_SSV(gui.skol.mod_baroutline)
      gfx.rect(obj.sections[1302].x,
               obj.sections[1302].y,
               obj.sections[1302].w,
               obj.sections[1302].h, 0)

      local rsdata
      if smshowfavs then
        rsdata = samplefavs
      else
        rsdata = ctl.rsdata
      end
      SM_butt_cnt = math.floor(obj.sections[1302].h / butt_h)
      local sbobj = obj.sections[1303]

      local starw, starh = gfx.getimgdim(skin.star)
      if rsdata then
        for i = 1, SM_butt_cnt do

          if rsdata.samples[i+smlist_offset] then

            local xywh = {x = obj.sections[1302].x +2,
                          y = obj.sections[1302].y +2 + (i-1) * butt_h,
                          w = 50,
                          h = butt_h-2}
            local c = gui.skol.lst_txt
            local c2 = gui.skol.modhighcol
            local col2 = math.floor(40*((lst_fontscale/20)+1))

            if (not smshowfavs and sample_select == i + smlist_offset) or (smshowfavs and sample_select == rsdata.samples[i+smlist_offset].idx) then
              f_Get_SSV(gui.skol.lst_barhl)
              gfx.rect(xywh.x + col2,
                       xywh.y,
                       obj.sections[1302].w -(xywh.x+col2) - 2,
                       xywh.h, 1, 1)

              c = gui.skol.lst_txthl
            end
            xywh.x = xywh.x + 2

            local n = i+smlist_offset
            if smshowfavs then
              n = rsdata.samples[i+smlist_offset].idx
            end
            GUI_Str(gui, xywh, string.format("%03d",n), 4, c2, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

            xywh.x = xywh.x + col2
            xywh.w = obj.sections[1302].w -xywh.x - 2 - starw

            if not rsdata.samples[i+smlist_offset].fn then
              c = '128 128 128'
            end
            GUI_Str(gui, xywh, rsdata.samples[i+smlist_offset].fn or '[No sample]', 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

            --FAVS
            xywh.w = xywh.w + starw
            if rsdata.samples[i+smlist_offset].fn and rsdata.samples[i+smlist_offset].fav == true then
              gfx.blit(skin.star,1,0,0,0,starw,starh,xywh.x+xywh.w-starw,xywh.y+xywh.h/2-starh/2)
            else
              gfx.blit(skin.starout,1,0,0,0,starw,starh,xywh.x+xywh.w-starw,xywh.y+xywh.h/2-starh/2)
            end


          end

        end

        if SM_butt_cnt < #rsdata.samples then
          local msbh = sbobj.h
          local p1 = 1 / #rsdata.samples
          local sbh = math.ceil(F_limit(p1*SM_butt_cnt * msbh,20,msbh))
          local p2 = p1*msbh
          local sby = math.floor(smlist_offset * p2)
          GUI_DrawSB(sbobj, sby, msbh, sbh, gui.skol.mod_baroutline, 1)
          if mouse.context == contexts.scrollsamples then
            GUI_DrawSB(sbobj, sby, msbh, sbh, lvar.scrollbar_hl, 0, true)
          end
        end

      end
    end

    --keyboard
    gfx.blit(909,1,0,lvar.kb.offset,0,obj.sections[1304].w,obj.sections[1304].h,obj.sections[1304].x, obj.sections[1304].y)
    gfx.blit(908,1,0,lvar.kb.offset,0,obj.sections[1304].w,obj.sections[1304].h,obj.sections[1304].x, obj.sections[1304].y)

    gfx.dest = 1

  end

  function PopSampleFavIdx()

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[rs5k_select]
    local samples = ctl.rsdata.samples

    samplefavs = {samples = {}, idx = {}}

    for s = 1, #samples do
      if samples[s].fav == true then

        local sidx = #samplefavs.samples + 1
        samplefavs.samples[sidx] = samples[s]
        samplefavs.samples[sidx].idx = s
        samplefavs.idx[s] = sidx
      end
    end
    for s = 1, #samples do
      if samples[s].fav ~= true then

        local sidx = #samplefavs.samples + 1
        samplefavs.samples[sidx] = samples[s]
        samplefavs.samples[sidx].idx = s
        samplefavs.idx[s] = sidx
      end
    end

  end

  function GUI_DrawSB_Strips(obj, gui)

    gfx.dest = 906
    --gfx.setimgdim(906,-1,-1)
    Img_SetDim(906,obj.sections[1352].w,obj.sections[1352].h)
    gfx.a = 1

    f_Get_SSV(gui.skol.lst_bg)
    gfx.rect(0,
             0,
             obj.sections[1352].w,
             obj.sections[1352].h,1)
    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,0,obj.sections[1352].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[1352].w-pnlcnr_w,obj.sections[1352].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,0,0)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[1352].w-pnlcnr_w,0)
    end

    --[[if lvar.resize_stripbrowser then
      gfx.dest = 1
      return
    end]]

    local dx, dy = math.max(math.floor((lvar.stripbrowser.imgw-lvar.stripbrowser.minw)/2),math.floor(5*pnl_scale)),
                   math.max(math.floor((lvar.stripbrowser.imgh-lvar.stripbrowser.minh)/2),math.floor(5*pnl_scale))

    local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page
    if lvar.stripbrowser.search == true then
      if not strip_search[offset+1] then
        lvar.stripbrowser.page = 0
        offset = 0
      end
    elseif lvar.stripbrowser.favs == true then
      if not strip_favs[offset+1] then
        lvar.stripbrowser.page = 0
        offset = 0
      end
    else
      if not strip_files[offset] then
        lvar.stripbrowser.page = 0
        offset = 0
      end
    end

    local pw = lvar.stripbrowser.minw
    local ph = lvar.stripbrowser.minh
    local sw,sh = gfx.getimgdim(skin.star)
    local htxt

    --load image
    if lvar.reloadsbimages then
      lvar.reloadsbimages = nil

      --[[gfx.setimgdim(911,-1,-1)
      gfx.setimgdim(912,-1,-1)
      gfx.setimgdim(913,-1,-1)
      gfx.setimgdim(914,-1,-1)
      gfx.setimgdim(911,lvar.maxdim,lvar.maxdim)
      gfx.setimgdim(912,lvar.maxdim,lvar.maxdim)
      gfx.setimgdim(913,lvar.maxdim,lvar.maxdim)
      gfx.setimgdim(914,lvar.maxdim,lvar.maxdim)]]
      Img_SetDim(911, lvar.maxdim, lvar.maxdim)
      Img_SetDim(912, lvar.maxdim, lvar.maxdim)
      Img_SetDim(913, lvar.maxdim, lvar.maxdim)
      Img_SetDim(914, lvar.maxdim, lvar.maxdim)
      
      local cnt
      if lvar.stripbrowser.search == true then
        cnt = #strip_search-1
      elseif lvar.stripbrowser.favs == true then
        cnt = #strip_favs-1
      else
        cnt = #strip_files
      end

      lvar.stripbrowser.store_cols = math.floor(lvar.maxdim/lvar.stripbrowser.minw)
      lvar.stripbrowser.store_rows = math.floor(lvar.maxdim/lvar.stripbrowser.minh)

      local sb_tfn = {}
      local sb_ffn = {}
      for n = 0, cnt do
        local ffn, fn, tfn

        local x = n % lvar.stripbrowser.store_cols
        local y = math.floor(n / lvar.stripbrowser.store_cols) % lvar.stripbrowser.store_rows
        local pg = math.min(math.floor(math.floor(n / lvar.stripbrowser.store_cols) / lvar.stripbrowser.store_rows),3)
        gfx.dest = 911+pg

        
        if lvar.stripbrowser.search == true then
          if strip_search[n+1] then
            ffn = strip_search[n+1]
            fn = string.match(strip_search[n+1],'(.+)%..*')..'.png'
            tfn = string.match(strip_search[n+1],'.+[\\/](.+)%..*')
            --strip_favs_n[n+1] = n
          end
        elseif lvar.stripbrowser.favs == true then
          if strip_favs[n+1] then
            ffn = strip_favs[n+1]
            fn = string.match(strip_favs[n+1],'(.+)%..*')..'.png'
            tfn = string.match(strip_favs[n+1],'.+[\\/](.+)%..*')
            strip_favs_n[n+1] = n
          end
        else
          if strip_files[n] then
            ffn = strip_folders[stripfol_select].fn..'/'..strip_files[n].fn
            fn = strip_folders[stripfol_select].fn..'/'..string.match(strip_files[n].fn,'(.+)%..*')..'.png'
            tfn = string.match(strip_files[n].fn,'(.+)%..*')
          end
        end

        if fn then

          sb_tfn[n] = tfn
          sb_ffn[n] = ffn

          local px = math.floor(x*(lvar.stripbrowser.minw))
          local py = math.floor(y*(lvar.stripbrowser.minh))
          local iidx = -1
          if reaper.file_exists(paths.strips_path..fn) then
            iidx = gfx.loadimg(985,paths.strips_path..fn)
            if iidx == -1 then
              iidx = skin.sbicon
            end
          else
            iidx = skin.sbicon
          end

          local w,h = gfx.getimgdim(iidx)
          local scale = math.min(pw/w,ph/h)
          if lvar.stripbrowser.type2 then
            scale = math.min(scale, 1)
          end
          local xoff = math.floor((pw-(w*scale))/2)
          local yoff = math.floor((ph-(h*scale))/2)

          gfx.blit(iidx,scale,0,0,0,w,h,px+xoff,py+yoff)

        end

      end
      lvar.sb_tfn = sb_tfn
      lvar.sb_ffn = sb_ffn
      gfx.dest = 906
    end

    --Dummy to set font
    local xywh = {x = 0, y = 0, w = 0, h = 0}
    local tsz = lvar.stripbrowser.tsz or 0
    GUI_DrawButton(gui, '', xywh, -5, gui.skol.butt1_txt, true, '', false, tsz, false, 4)

    local ppw = lvar.stripbrowser.imgw+10
    for y = 0, lvar.stripbrowser.ynum-1 do
      for x = 0, lvar.stripbrowser.xnum-1 do

        local nn = y*lvar.stripbrowser.xnum + x + offset
        local n
        if lvar.stripbrowser.favs == true and lvar.stripbrowser.search ~= true then
          n = strip_favs_n[nn+1]
        else
          n = nn
        end

        if lvar.sb_tfn[n] then

          local px = math.floor(x*(lvar.stripbrowser.imgw+10)+15+dx)
          local py = math.floor(y*(lvar.stripbrowser.imgh+10)+5+dy)

          local xoff = math.floor((pw-(lvar.stripbrowser.imgw))/2)
          local yoff = math.floor((ph-(lvar.stripbrowser.imgh))/2)

          local n_x = n % lvar.stripbrowser.store_cols
          local n_y = math.floor(n / lvar.stripbrowser.store_cols) % lvar.stripbrowser.store_rows
          local n_pg = math.min(math.floor(math.floor(n / lvar.stripbrowser.store_cols) / lvar.stripbrowser.store_rows),3)

          if not lvar.stripbrowser.type2 then
            gfx.blit(911+n_pg,1,0,n_x*pw,n_y*ph,pw,ph,px--[[+xoff]],py--[[+yoff]])
          end
          
          if lvar.stripbrowser.showlabel == true or lvar.stripbrowser.type2 then
            if lvar.stripbrowser.type2 then
              local tfn = lvar.sb_tfn[n]
              local xywh = {x = math.floor(px+pw/2-ppw/2)+1, y = py+ph,
                            w = ppw-2, h = 20}
              local tw, th = gfx.measurestr(tfn)
              local just = 5
              if tw > xywh.w-8 then
                just = 4
              end
              
              xywh.y = py-10
              xywh.h = ph+30
              local bt = -1
              local tc = gui.skol.butt1_txt
              if lvar.stripbrowser.select and lvar.stripbrowser.select == nn then
                bt = -4
                tc = gui.color.black
              end
              GUI_DrawButton(gui, '', xywh, bt, gui.skol.butt1_txt, true, '', 4, tsz, false, just)
              gfx.blit(911+n_pg,1,0,n_x*pw,n_y*ph,pw,ph,px--[[+xoff]],py--[[+yoff]])
              if lvar.stripbrowser.showlabel == true then
                xywh.y = py+ph - 2
                xywh.h = 20
                GUI_Str(gui,xywh,tfn,just,tc,tsz,1,gui.skol.butt_shad,gui.fontnm.butt,gui.fontflag.butt)
              end
              --GUI_DrawButton(gui, tfn, xywh, -1, gui.skol.butt1_txt, true, '', 4, tsz, false, just)
            else
              local tfn = lvar.sb_tfn[n]
              local xywh = {x = math.floor(px+pw/2-ppw/2)+1, y = py+ph,
                            w = ppw-2, h = 20}
              local tw, th = gfx.measurestr(tfn)
              local just = 5
              if tw > xywh.w-8 then
                just = 4
              end
              if lvar.stripbrowser.select and lvar.stripbrowser.select == nn then
                --f_Get_SSV(gui.color.yellow)
                --gfx.rect(px+xoff,py+yoff,math.floor(w*scale),math.floor(h*scale),0)
  
                local tw, th = gfx.measurestr(tfn)
                htxt = {x = px+(pw/2)-(tw/2)-6, y = py+ph,
                        w = tw+12, h = 20, txt = tfn}
              else
                GUI_DrawButton(gui, tfn, xywh, -1, gui.skol.butt1_txt, true, '', 4, tsz, false, just)
              end
            end
          end

          if InFavs(lvar.sb_ffn[n]) then
            gfx.blit(skin.star,1,0,0,0,sw,sh,px+math.floor(pw/2)-math.floor(sw/2),py-math.floor(sh/2))
          else
            gfx.blit(skin.starout,1,0,0,0,sw,sh,px+math.floor(pw/2)-math.floor(sw/2),py-math.floor(sh/2))
          end

        else
          break
        end
      end
    end

    if htxt then
      if htxt.x+htxt.w > obj.sections[1352].w then
        htxt.x = obj.sections[1352].w - htxt.w
      end
      if htxt.x < 0 then
        htxt.x = 0
      end
      GUI_DrawButton(gui, htxt.txt, htxt, -4, gui.skol.butt1_txt, true, '', false, tsz, false, 5)
    end

    gfx.dest = 1

  end

  function GUI_DrawStripBrowser(obj, gui)

    gfx.dest = 907
    --gfx.setimgdim(907,-1,-1)
    Img_SetDim(907,obj.sections[1350].w,obj.sections[1350].h)

    gfx.a = 1

    local butt_h = math.floor(butt_h*pnl_scale)
    local t = ''
    if lvar.sb_folbtn_c <= 1 or not lvar.sb_folbtn_show then
      t = 'STRIPS'
    end
    GUI_DrawPanel(obj.sections[1350],false,t)

    local b
    if settings_sbdock == true then
      b = gui.color.white
    else
      b = -5
    end
    GUI_DrawButton(gui, 'DOCK', obj.sections[1357], b, gui.skol.butt1_txt, true, '', false, -2, true)

    --if not lvar.resize_stripbrowser then
      GUI_DrawSB_Strips(obj, gui)
    --end

    gfx.dest = 907
    local w,h = gfx.getimgdim(906)
    gfx.blit(906,1,0,0,0,w,h,obj.sections[1352].x,obj.sections[1352].y)

    local c = gui.color.white
    local t = ''
    if lvar.stripbrowser.search == true then
      t = "'".. lvar.stripbrowser.searchstr .."'"
    elseif lvar.stripbrowser.favs == true then
      t = 'FAVS'
    else
      t = strip_folders[stripfol_select].fn
    end
    GUI_DrawButton(gui, t, obj.sections[1353], c, gui.skol.butt1_txt, true, '', false)

    if lvar.sb_folbtn_show and lvar.sb_folbtn_c > 1 then

      local c = gui.color.white
      if settings_sbdock then
        GUI_DrawButton(gui, '<', obj.sections[1359], c, gui.skol.butt1_txt, true, '', false)
        GUI_DrawButton(gui, '>', obj.sections[1360], c, gui.skol.butt1_txt, true, '', false)
      end

      local xywh = {x = obj.sections[1358].x,
                    y = obj.sections[1358].y,
                    w = lvar.sb_folbtn_w-2,
                    h = obj.sections[1358].h}
      for i = 0, lvar.sb_folbtn_c-1 do
        local idx = i+lvar.sb_folbtn_offs
        local t
        local c = gui.color.white
        if (lvar.stripbrowser.favs == true and idx == 0) or (lvar.stripbrowser.favs ~= true and idx == stripfol_select+1) then
          c = -1
        end
        if idx == 0 then
          t = 'FAVS'
        elseif strip_folders[idx-1] then
          t = strip_folders[idx-1].fn
        end
        if t then
          GUI_DrawButton(gui, t, xywh, c, gui.skol.butt1_txt, true, '', false)
          xywh.x = xywh.x + lvar.sb_folbtn_w
        else
          break
        end
      end
    end

    if lvar.stripbrowser.showlist == true then

      local cnt = #strip_folders + 2

      f_Get_SSV(gui.skol.lst_bg)
      gfx.rect(obj.sections[1351].x-2,
               obj.sections[1351].y-2,
               obj.sections[1351].w+4,
               math.min(cnt*butt_h+4,obj.sections[1351].h+4),1)

      local xywh = {x = obj.sections[1351].x,
                    y = obj.sections[1351].y,
                    w = obj.sections[1351].w,
                    h = butt_h}
      SBSF_butt_cnt = math.floor(obj.sections[1351].h/butt_h)

      for i = -1, SBSF_butt_cnt do

        if i ~= -1 then
          local c = gui.color.white
          local ii = i+sbsflist_offset
          if strip_folders[ii] then
            if lvar.stripbrowser.favs ~= true and ii == stripfol_select then
              c = -4
            end
            GUI_DrawButton(gui, strip_folders[ii].fn, xywh, c, gui.skol.butt1_txt, true, '', false)
            xywh.y = xywh.y + butt_h
          end
        else
          if lvar.stripbrowser.favs == true then
            c = -4
          end
          GUI_DrawButton(gui, 'FAVS', xywh, c, gui.skol.butt1_txt, true, '', false)
          xywh.y = xywh.y + butt_h
        end
        if xywh.y + xywh.h > obj.sections[1351].y + obj.sections[1351].h then
          break
        end
      end
    end

    gfx.dest = 1

  end

  function GUI_DrawMutate(obj, gui)

    local mutate_settings = lvar.mutate_settings

    gfx.dest = 989
    Img_SetDim(989,obj.sections[1120].w,obj.sections[1120].h, true)

    GUI_DrawPanel(obj.sections[1120],false,'MUTATE SETTINGS')

    GUI_DrawButton(gui, mutate_settings.mutate_max..' %', obj.sections[1121], gui.color.white, gui.skol.butt1_txt, true, 'AMOUNT',false,gui.fontsz.butt)
    local dir = '+ / -'
    if mutate_settings.dir == 1 then
      dir = '+'
    elseif mutate_settings.dir == 2 then
      dir = '-'
    end
    GUI_DrawButton(gui, dir, obj.sections[1122], gui.color.white, gui.skol.butt1_txt, true, 'DIRECTION',false,gui.fontsz.butt)

    gfx.dest = 1

  end

  function GUI_DrawRandomOpts(obj, gui)

    gfx.dest = 988

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls

    local subname
    subname = ctls[randomopts_select.parent].ctlname_override
    if (subname or '') == '' then
      subname = 'SUBSET '..randomopts_select.sst-1
    end
    --subname = ctls[randomopts_select.parent].param_info.paramname
    --subname = snapshots[strip][page][randomopts_select.sst].subsetname

    local useadv = false
    local sso = false
    if randomopts_select and randomopts_select.useadv == true then
      useadv = true
    end
    if randomopts_select and randomopts_select.snapshotsonly == true then
      sso = true
    end

    if useadv ~= true or sso == true then
      obj.sections[1130].h = math.floor(78 * pnl_scale)
    else
      obj.sections[1130].h = math.floor(300*pnl_scale)
    end
    RedrawGUIBitmap()
    if obj.sections[1130].y + obj.sections[1130].h > obj.sections[10].y+obj.sections[10].h then
      obj.sections[1130].y = math.max(obj.sections[10].y+obj.sections[10].h - obj.sections[1130].h,obj.sections[10].y)
    end
    Img_SetDim(988,obj.sections[1130].w,obj.sections[1130].h, true)

    local txt = 'RANDOMIZE OPTS - '..subname

    local xywh = {x = obj.sections[1130].x,
                  y = obj.sections[1130].y,
                  w = obj.sections[1130].w,
                  h = obj.sections[1130].h}
    GUI_DrawPanel(xywh,false,txt)

    f_Get_SSV(gui.skol.lst_bg)
    local ind = 6
    local x = ind
    local y = 30*pnl_scale
    local w = obj.sections[1130].w-ind*2
    local h = 40*pnl_scale
    gfx.rect(x,y,w,h)
    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y+h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y+h-pnlcnr_h)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y)
    end

    GUI_DrawTick(gui, 'Use advanced', obj.sections[1131], gui.skol.pnl_txt, useadv, gui.fontsz.butt)

    if useadv == true then

      GUI_DrawTick(gui, 'Randomize snapshot only', obj.sections[1132], gui.skol.pnl_txt, randomopts_select.snapshotsonly, gui.fontsz.butt)

      if randomopts_select.snapshotsonly == false then

        if not randomopts_select.param then
          randomopts_select.param = 1
        end
        local ctlsel = randomopts_select.ctls[randomopts_select.param]

        local lgtype, lg
        if ctlsel then
          lg = ctlsel.linkgrp
          if lg and randomopts_select.linkgrps[lg] then
            lgtype = randomopts_select.linkgrps[lg].type
          end
        end

        if not ctlsel or (snapshots[strip][page][randomopts_select.sst] and snapshots[strip][page][randomopts_select.sst].ctls[randomopts_select.param] and ctlsel.c_id ~= snapshots[strip][page][randomopts_select.sst].ctls[randomopts_select.param].c_id) then
          ctlsel = nil
          RandomOpts_RefreshCtlNos(strip, page, randomopts_select)
          ctlsel = randomopts_select.ctls[randomopts_select.param]
        elseif snapshots[strip][page][randomopts_select.sst] and not snapshots[strip][page][randomopts_select.sst].ctls[randomopts_select.param] then
          ctlsel = nil
        end
        local txt, ctl
        if ctlsel then
          --local c = ctlsel.ctl
          ctl = ctls[ctlsel.ctl]
          local fxnum = ''
          if ctl.ctlcat == ctlcats.fxparam then
            fxnum = string.format('%i',ctl.fxnum)
            txt = 'FX '..fxnum..' : '..nz(ctl.ctlname_override,'') .. ' (' ..ctl.param_info.paramname ..')'
          elseif ctl.ctlcat == ctlcats.trackparam or ctl.ctlcat == ctlcats.tracksend then
            local trn = ctl.tracknum or tracks[track_select].tracknum
            local trtxt = 'TR '..trn+1 ..' : '
            if trn == -1 then
              trtxt = 'TR MASTER : '
            end
            txt = trtxt..nz(ctl.ctlname_override,'') .. ' (' .. ctl.param_info.paramname ..')'
          else
            txt = nz(ctl.ctlname_override,'') .. ' (' .. ctl.param_info.paramname ..')'
          end
        else
          txt = 'No parameter'
        end
        GUI_DrawButton(gui, txt, obj.sections[1133], gui.color.white, gui.skol.butt1_txt, true, 'PARAM',false,gui.fontsz.butt)
        GUI_DrawButton(gui, '<  >', obj.sections[1145], gui.color.white, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)

        if ctlsel and lgtype ~= 2 and lgtype ~= 3 then
          if ctlsel.wild == 0 then
            txt = 'Off'
          else
            txt = round(ctlsel.wild*100,1)..'%'
          end
          GUI_DrawButton(gui, txt, obj.sections[1146], gui.color.white, gui.skol.butt1_txt, true, 'WILD',false,gui.fontsz.butt)

          local min, max
          if ctl and ctl.ctlcat == ctlcats.takeswitcher then
            min = math.floor(ctlsel.min * takeswitch_max)
            max = math.floor(ctlsel.max * takeswitch_max)
          else
            min = round(ctlsel.min,8)
            max = round(ctlsel.max,8)
          end
          GUI_DrawButton(gui, min, obj.sections[1134], gui.color.white, gui.skol.butt1_txt, true, 'MIN',false,gui.fontsz.butt)
          GUI_DrawButton(gui, max, obj.sections[1135], gui.color.white, gui.skol.butt1_txt, true, 'MAX',false,gui.fontsz.butt)
        end

        if ctlsel then
          local txt = ctlsel.linkgrp
          if not txt then
            txt = 'None'
          end
          GUI_DrawButton(gui, txt, obj.sections[1136], gui.color.white, gui.skol.butt1_txt, true, 'LINK GRP',false,gui.fontsz.butt)

          if not lgtype then
            GUI_DrawButton(gui, math.floor(ctlsel.rprob*100)..'%', obj.sections[1137], gui.color.white, gui.skol.butt1_txt, true, 'PROBABILITY',false,gui.fontsz.butt)
          end
          if not lgtype or lgtype == 1 then
            GUI_DrawButton(gui, math.floor(ctlsel.bias*100)..'%', obj.sections[1138], gui.color.white, gui.skol.butt1_txt, true, '+ve BIAS',false,gui.fontsz.butt)
          end

          if ctlsel.linkgrp and randomopts_select.linkgrps[lg].type == 4 then
            if ctlsel.inverted == true then
              txt = 'Invert'
            else
              txt = 'Match'
            end
            GUI_DrawButton(gui, txt, obj.sections[1139], gui.color.white, gui.skol.butt1_txt, true, 'MATCH/INVERT',false,gui.fontsz.butt)
          end

          if not lgtype or lgtype == 1 then
            if not ctlsel.amount then
              txt = 'Off'
            else
              txt = round(ctlsel.amount*100,8)..'%'
            end
            GUI_DrawButton(gui, txt, obj.sections[1140], gui.color.white, gui.skol.butt1_txt, true, 'RANGE',false,gui.fontsz.butt)
            if ctlsel.amount and ctlsel.amount > 0 then
              local b = gui.color.white
              if ctlsel.snap == true then
                b = -4
              end
              GUI_DrawButton(gui, 'Snap', obj.sections[1147], b, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
            end
          end
        end

        local grph = (obj.sections[1140].y+obj.sections[1140].h+10)
        f_Get_SSV(gui.skol.lst_bg)
        local ind = 6
        local x = obj.sections[1141].x
        local y = obj.sections[1141].y
        local w = obj.sections[1141].w
        local h = obj.sections[1141].h
        gfx.rect(x,y,w,h)
        if skin.panela_cnrbl ~= -1 then
          local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
          gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y+h-pnlcnr_h)
          gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y+h-pnlcnr_h)
          gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y)
          gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y)
        end

        if ctlsel then
          local txt = ctlsel.linkgrp
          if not txt then
            txt = 'None'
          end
          GUI_DrawButton(gui, txt, obj.sections[1142], gui.color.white, gui.skol.butt1_txt, true, 'LINK GRP',false,gui.fontsz.butt)

          local lgsel = randomopts_select.linkgrps[lg]
          if lgtype then
            GUI_DrawButton(gui, lvar.linkgrp_table[lgsel.type], obj.sections[1143], gui.color.white, gui.skol.butt1_txt, true, 'TYPE',false,gui.fontsz.butt)
            if lgtype <= 3 then
              GUI_DrawButton(gui, string.format('%i',round(lgsel.X*128)), obj.sections[1144], gui.color.white, gui.skol.butt1_txt, true, 'X',false,gui.fontsz.butt)
            else
              --if lgsel.X > 0 then
                txt = round(lgsel.X*100,8)..'%'
              --else
              --  txt = 'Off'
              --end
              GUI_DrawButton(gui, txt, obj.sections[1144], gui.color.white, gui.skol.butt1_txt, true, 'RANGE',false,gui.fontsz.butt)

              if lgsel.X > 0 then
                local b = gui.color.white
                if lgsel.snap == true then
                  b = -4
                end
                GUI_DrawButton(gui, 'Snap', obj.sections[1148], b, gui.skol.butt1_txt, true, '',false,gui.fontsz.butt)
              end
            end
          end
        end
      end

    end

    gfx.dest = 1

  end

  function PinMatrix_CalcDim()

    local xx, yy = 0, 0

    local pinw, pinh = math.floor(22*pinmatrix_zoom), math.floor(22*pinmatrix_zoom)
    local pinadj = math.floor(2*pinmatrix_zoom)
    local fxoffs_x, fxoffs_y, fxspacer = math.floor(50*pinmatrix_zoom), 0, math.floor(30*pinmatrix_zoom)

    local tr
    if lvar.livemode == 2 then
      tr = GetTrack(lvar.dynamicmode_trn)
    else
      tr = GetTrack(tracks[track_select].tracknum)
    end
    local chans = math.min(reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN"))
    local fxn = reaper.TrackFX_GetCount(tr)
    fxoff = fxoffs_x

    for i = 0, fxn-1 do

      local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,i)
      local pn = reaper.TrackFX_GetNumParams(tr,i)
      local fxw = math.max((inpins + outpins +1) * (pinw),60)
      if pn == lvar.offline_paramcnt then
        fxw = 60
      end

      fxoff = fxoff + fxw + fxspacer

    end
    xx = fxoff + pinw
    yy = fxoffs_y + pinh*2 + pinh*chans

    return xx, yy

  end

  function GUI_DrawPinMatrix(obj, gui)

    local w, h = obj.sections[1200].w, obj.sections[1200].h
    local lcol = '96 96 96'
    Img_SetDim(987,w,h, true)
    gfx.dest = 987
    f_Get_SSV(gui.color.black)
    gfx.rect(0,0,w,h)

    pinmatrix_data = {}
    pinmatrix_data.updatetime = reaper.time_precise()
    local pinw, pinh = math.floor(22*pinmatrix_zoom), math.floor(22*pinmatrix_zoom)
    local pinadj = math.floor(2*pinmatrix_zoom)
    local fxoffs_x, fxoffs_y, fxspacer = math.floor(50*pinmatrix_zoom), 0, math.floor(30*pinmatrix_zoom)
    if pinmatrix_scrollpos == nil then
      pinmatrix_scrollpos = {x = 0, y = 0}
    end

    if lvar.livemode == 2 then
      tr = GetTrack(lvar.dynamicmode_trn)
    else
      tr = GetTrack(tracks[track_select].tracknum)
    end
    local chans = math.min(reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN"))
    pinmatrix_data.chans = chans

    --fx header section
    obj.sections[1201] = {x = fxoffs_x, y = fxoffs_y, w = obj.sections[1200].w, h = pinh-2}

    --Track chans
    local cw = pinw*1.5
    local cy = obj.sections[1201].y + math.floor((pinh-2)*0.7)
    obj.sections[1203] = {x = math.floor(-((cw-pinw)/2))+pinmatrix_scrollpos.x, y = cy+pinmatrix_scrollpos.y, w = math.floor(cw), h = pinh}

    --pin section
    obj.sections[1202] = {x = fxoffs_x, y = fxoffs_y+pinh +pinh, w = obj.sections[1200].w, h = (pinh)*chans}
    local fxy = obj.sections[1201].y + obj.sections[1201].h + pinmatrix_scrollpos.y
    local arrowsz = pinadj --math.floor(3*pinmatrix_zoom)

    last_in = {}
    last_cy = {}

    local xywh = {x = obj.sections[1203].x-50,
                  y = obj.sections[1203].y - pinh*0.8,
                  w = obj.sections[1203].w+100,
                  h = pinh}
    GUI_Str(gui, xywh, 'CHANNELS', 5, gui.skol.butt1_txt, -12+pinmatrix_zoom*10, 1, nil, gui.fontnm.sb, 1)
    GUI_DrawButton(gui, string.format('%i',chans), obj.sections[1203], -2, gui.skol.butt1_txt, true, nil, false, -12+pinmatrix_zoom*10, true, 5)

    local x = 0 + pinmatrix_scrollpos.x
    local y = obj.sections[1201].y + pinmatrix_scrollpos.y + pinh*2

    for c = 0, chans-1 do

      local pin_rect = {x = x, y = y + c*(pinh), w = pinw-pinadj, h = pinh-pinadj}
      GUI_DrawButton(gui, c+1, pin_rect, -1, gui.skol.butt1_txt, true, nil, false, -7+pinmatrix_zoom*10, true, 5)

      last_in[c] = x
    end

    local fxn = reaper.TrackFX_GetCount(tr)
    pinmatrix = {}
    pinmatrix.fx_rect = {}
    fxoff = 0

    for i = 0, fxn-1 do

      local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,i)
      pinmatrix_data[i] = {incnt = inpins, outcnt = outpins, inpins = {}, outpins = {}}
      local pn = reaper.TrackFX_GetNumParams(tr,i)
      local fxw = math.max((inpins + outpins +1) * (pinw),60)

      if pn ~= lvar.offline_paramcnt then
        if outpins==-1 and inpins~=-1 then
          outpins=inpins--in some JS outs ret "-1"
        end
      else
        fxw = 60
      end
      local _, fxname = reaper.TrackFX_GetFXName(tr,i,'')
      fxname = CropFXName(fxname)

      --draw header
      local x = obj.sections[1201].x + fxoff + pinmatrix_scrollpos.x
      local y = obj.sections[1201].y + pinmatrix_scrollpos.y
      local fx_rect = {x = x, y = y, w = fxw, h = pinh}
      pinmatrix.fx_rect[i] = fx_rect
      pinmatrix.fx_rect[i].inpins = inpins
      pinmatrix.fx_rect[i].outpins = outpins

      local vis = true
      if fx_rect.x+fx_rect.w < 0 or fx_rect.x > obj.sections[1200].w then
        vis = false
      end

      if vis then
        GUI_DrawButton(gui, '  '..fxname, fx_rect, -1, gui.skol.butt1_txt, true, nil, false, -6+pinmatrix_zoom*10, true, 4)
      end

      if vis or (not vis and matrixoff == nil) then
      if pn ~= 2 then
        y = y + pinh*2
        --draw in pins
        for ip = 0, inpins-1 do
          local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, i, 0, ip)
          pinmatrix_data[i].inpins[ip] = {lo = Low32, hi = Hi32}

          local bit,val
          local last_cy = {}
          local sel32 = Low32
          for c = 0, chans-1 do

            bit = 2^(c%32)
            if c >= 32 then
              sel32 = Hi32
            end
            val = (sel32&bit)>0
            local butt_act = -1
            local txt = ''
            if val == true then
              butt_act = -4
              txt = ip+1
            end

            local pin_rect = {x = x + ip*(pinw), y = y + c*(pinh), w = pinw-pinadj, h = pinh-pinadj}
            if vis then
              GUI_DrawButton(gui, txt, pin_rect, butt_act, gui.skol.butt1_txt, true, nil, false, -7+pinmatrix_zoom*10, true, 5)
            end
            if val and matrixoff == nil then
              local y2 = pin_rect.y
              if vis or last_in[c] < obj.sections[1200].w then
                f_Get_SSV(lcol)
                local x1 = last_in[c]+pin_rect.w
                local y1 = pin_rect.y+pin_rect.h/2
                local x2 = pin_rect.x
                gfx.line(x1,y1,x2-1,y1)
                gfx.triangle(x2-arrowsz,y1-arrowsz,x2-arrowsz,y1+arrowsz,x2-1,y1)

                local x1 = pin_rect.x+pin_rect.w/2
                local y1 = last_cy[ip] or fxy
                gfx.line(x1,y1,x1,y2)
                if not last_cy[ip] then
                  gfx.triangle(x1-arrowsz,y1+arrowsz,x1+arrowsz,y1+arrowsz,x1,y1)
                end
              end
              last_in[c] = pin_rect.x
              last_cy[ip] = y2+pin_rect.h
            end

          end
        end

        --draw out pins
        local xo = x + (inpins+1)*(pinw)
        for op = 0, outpins-1 do
          local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, i, 1, op)
          pinmatrix_data[i].outpins[op] = {lo = Low32, hi = Hi32}

          local bit,val
          local last_cy = {}
          local sel32 = Low32
          for c = 0, chans-1 do

            bit = 2^(c%32)
            if c >= 32 then
              sel32 = Hi32
            end
            val = (sel32&bit)>0
            local butt_act = -1
            local txt = ''
            if val == true then
              butt_act = -4
              txt = op+1
            end

            local pin_rect = {x = xo + op*(pinw), y = y + c*(pinh), w = pinw-pinadj, h = pinh-pinadj}
            if vis then
              GUI_DrawButton(gui, txt, pin_rect, butt_act, gui.skol.butt1_txt, true, nil, false, -7+pinmatrix_zoom*10, true, 5)
            end
            if val and matrixoff == nil then
              local y2 = pin_rect.y
              if vis then
                f_Get_SSV(lcol)

                local x1 = pin_rect.x+pin_rect.w/2
                local y1 = last_cy[op] or fxy
                gfx.line(x1,y1,x1,y2)
                gfx.triangle(x1-arrowsz,y2-arrowsz,x1+arrowsz,y2-arrowsz,x1,y2)
              end

              last_in[c] = pin_rect.x
              last_cy[op] = y2+pin_rect.h
            end
          end
        end
      end

      end

      fxoff = fxoff + fxw + fxspacer
    end

    local x = obj.sections[1201].x + fxoff + pinmatrix_scrollpos.x
    local y = obj.sections[1201].y + pinmatrix_scrollpos.y + pinh*2

    for c = 0, chans-1 do

      local pin_rect = {x = x, y = y + c*(pinh), w = pinw-pinadj, h = pinh-pinadj}
      GUI_DrawButton(gui, c+1, pin_rect, -1, gui.skol.butt1_txt, true, nil, false, -7+pinmatrix_zoom*10, false, 5)
      if matrixoff == nil then
        f_Get_SSV(lcol)
        local x1 = last_in[c]+pin_rect.w
        local y1 = pin_rect.y+pin_rect.h/2
        local x2 = pin_rect.x
        gfx.line(x1,y1,x2,y1)
        gfx.triangle(x2-arrowsz,y1-arrowsz,x2-arrowsz,y1+arrowsz,x2,y1)
      end

    end

    gfx.dest = 1


  end

  function StripAssoc_GetDefaults()

    local tabdef = {}
    for pd = 1, #plugdefstrips do

      tabdef[plugdefstrips[pd].plug] = {fil = plugdefstrips[pd].stripfile, fol = plugdefstrips[pd].stripfol}

    end
    return tabdef

  end

  function StripAssoc_GetAssoc(stripfn, stripfol)

    local tab = {}
    local tabidx = {}
    local cnt = 1
    for pd = 1, #plugdefstrips do

      if plugdefstrips[pd].stripfol == stripfol and plugdefstrips[pd].stripfile == stripfn then
        tab[cnt] = plugdefstrips[pd].plug
        --tabidx[plugdefstrips[pd].plug] = cnt
        cnt=cnt+1
      end

    end
    table.sort(tab)
    for t = 1, #tab do
      tabidx[tab[t]] = t
    end
    return tab, tabidx

  end

  function StripAssoc_GetData()

    local sapd = {}
    local cnt = 1

    local i = 0
    local fol = reaper.EnumerateSubdirectories(paths.strips_path,i)
    while fol ~= nil do

      local j = 0
      local sfil = reaper.EnumerateFiles(paths.strips_path..fol,j)
      while sfil ~= nil do

        if string.match(sfil,'.*%.strip$') then
          sapd[cnt] = {fil = sfil,
                       fol = fol,
                       sort = fol..'/'..sfil}
          cnt = cnt + 1
        end

        j = j+1
        sfil = reaper.EnumerateFiles(paths.strips_path..fol,j)
      end
      i=i+1
      fol = reaper.EnumerateSubdirectories(paths.strips_path,i)
    end

    lvar.sapd = table_slowsort_gen2(sapd,'sort')

    lvar.sapd.defaults = StripAssoc_GetDefaults()
    for s = 1, #lvar.sapd do
      local tab, tabidx = StripAssoc_GetAssoc(lvar.sapd[s].fil, lvar.sapd[s].fol)
      lvar.sapd[s].assoc = tab
      lvar.sapd[s].associdx = tabidx
    end
    lvar.sapd.offset = 0

  end

  function StripAssoc_RefreshAssData()

    lvar.sapd.defaults = StripAssoc_GetDefaults()
    for s = 1, #lvar.sapd do
      local tab, tabidx = StripAssoc_GetAssoc(lvar.sapd[s].fil, lvar.sapd[s].fol)
      lvar.sapd[s].assoc = tab
      lvar.sapd[s].associdx = tabidx
    end

  end

  function GUI_DrawStripAssocDialog(obj, gui)

    gfx.dest = 977
    if lupd.update_gfx or resize_display then
      Img_SetDim(977,obj.sections[4500].w,obj.sections[4500].h, true)
    end

    GUI_DrawPanel(obj.sections[4500],false,'STRIP ASSOCIATION MANAGER')

    f_Get_SSV(gui.skol.ss_bg)
    gfx.a = 1
    local pnl = 4501
    gfx.rect(obj.sections[pnl].x-2,
             obj.sections[pnl].y-2,
             obj.sections[pnl].w+4,
             obj.sections[pnl].h,1)

    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
    end

    local pnl = 4502
    gfx.rect(obj.sections[pnl].x-2,
             obj.sections[pnl].y-2,
             obj.sections[pnl].w+4,
             obj.sections[pnl].h,1)

    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
    end

    local pnl = 4503
    gfx.rect(obj.sections[pnl].x-2,
             obj.sections[pnl].y-2,
             obj.sections[pnl].w+4,
             obj.sections[pnl].h,1)

    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[pnl].x-2+obj.sections[pnl].w+4-pnlcnr_w,obj.sections[pnl].y-2+obj.sections[pnl].h-pnlcnr_h)
    end

    local xywh = {x = obj.sections[4501].x+4,
                  y = obj.sections[4504].y,
                  w = obj.sections[4501].w-8,
                  h = obj.sections[4504].h}
    GUI_Str(gui, xywh, 'Strip Files', 5, gui.color.white, -1 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
    local xywh = {x = obj.sections[4502].x+4,
                  y = obj.sections[4504].y,
                  w = obj.sections[4502].w-8,
                  h = obj.sections[4504].h}
    GUI_Str(gui, xywh, 'Plugin Name/Module Associations', 5, gui.color.white, -1 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)


    --plugin ident list
    local butt_h = tb_butt_h
    local rowcnt = math.floor(obj.sections[4501].h / butt_h)
    local xywh = {x = obj.sections[4501].x+4,
                  y = obj.sections[4501].y,
                  w = 120,
                  h = butt_h}
    local xywh2 = {x = obj.sections[4501].x+130,
                   y = obj.sections[4501].y,
                   w = obj.sections[4501].w-134,
                   h = butt_h}
    local d = math.floor(22*pnl_scale)
    local xywh3 = {x = obj.sections[4501].x+obj.sections[4501].w - d,
                   y = obj.sections[4501].y+2,
                   w = d-3,
                   h = butt_h-4}
    for r = 1, rowcnt do

      local idx = r+lvar.sapd.offset
      if lvar.sapd[idx] then

        local c = gui.skol.lst_txt
        if lvar.sapd.selected == idx then
          f_Get_SSV(gui.skol.lst_barhl)
          gfx.rect(xywh.x-2,xywh.y+1,obj.sections[4501].w-4,xywh.h-2,1)
          c = gui.skol.lst_txthl
          if lvar.sapd.selected and lvar.sapd.assselected and lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected] then
            local plug = lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected]
            if (lvar.sapd.defaults[plug].fil == lvar.sapd[idx].fil and lvar.sapd.defaults[plug].fol == lvar.sapd[idx].fol) then
              xywh3.y = xywh.y+2
              f_Get_SSV(gui.color.black)
              gfx.rect(xywh3.x,xywh3.y,xywh3.w,xywh3.h,1)
              GUI_Str(gui, xywh3, 'D', 5, gui.skol.lst_txt, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
            end
          end
        elseif lvar.sapd.selected and lvar.sapd.assselected and lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected] then
          local plug = lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected]
          if lvar.sapd[idx].associdx[plug] then
            f_Get_SSV('64 64 64')
            gfx.rect(xywh.x-2,xywh.y+1,obj.sections[4501].w-4,xywh.h-2,1)
            c = gui.color.white
          end
          if (lvar.sapd.defaults[plug].fil == lvar.sapd[idx].fil and lvar.sapd.defaults[plug].fol == lvar.sapd[idx].fol) then
            xywh3.y = xywh.y+2
            f_Get_SSV(gui.color.black)
            gfx.rect(xywh3.x,xywh3.y,xywh3.w,xywh3.h,1)
            GUI_Str(gui, xywh3, 'D', 5, gui.skol.lst_txt, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          end
        end
        GUI_Str(gui, xywh, lvar.sapd[idx].fol, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        GUI_Str(gui, xywh2, lvar.sapd[idx].fil, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end
      xywh.y = xywh.y + butt_h
      xywh2.y = xywh.y
    end

    if lvar.sapd.selected then

      local rowcnt = math.floor(obj.sections[4502].h / butt_h)
      local xywh = {x = obj.sections[4502].x+4,
                    y = obj.sections[4502].y,
                    w = obj.sections[4502].w-8,
                    h = butt_h}
      for r = 1, rowcnt do
        local def

        local idx = r+lvar.sapd.assoffset
        if lvar.sapd[lvar.sapd.selected].assoc[idx] then
          local plug = lvar.sapd[lvar.sapd.selected].assoc[idx]
          if (lvar.sapd.defaults[plug].fil == lvar.sapd[lvar.sapd.selected].fil and lvar.sapd.defaults[plug].fol == lvar.sapd[lvar.sapd.selected].fol) then
            def = '(DEFAULT)'
          end

          local c = gui.skol.lst_txt --gui.color.white
          if lvar.sapd.assselected == idx then
            f_Get_SSV(gui.skol.lst_barhl)
            gfx.rect(xywh.x-2,xywh.y,xywh.w+4,xywh.h,1)
            c = gui.skol.lst_txthl
          end

          GUI_Str(gui, xywh, plug, 4, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          if def then
            GUI_Str(gui, xywh, def, 6, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          end
        end
        xywh.y = xywh.y + butt_h
      end

      if lvar.sapd.preview then

        local w, h = gfx.getimgdim(lvar.sapd.preview)
        local scale = math.min(math.min((obj.sections[4503].w-20)/w,(obj.sections[4503].h-20)/h),1)
        local x = math.floor(obj.sections[4503].x + obj.sections[4503].w/2 - (w*scale)/2)
        local y = math.floor(obj.sections[4503].y + obj.sections[4503].h/2 - (h*scale)/2)
        gfx.blit(lvar.sapd.preview, scale, 0, 0, 0, w, h, x, y)

      else

        local c = gui.color.white
        GUI_Str(gui, obj.sections[4503], 'No preview', 5, c, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)

      end

      if lvar.sapd.selected and lvar.sapd.stripdata and #lvar.sapd.stripdata.fx == 1 then
        GUI_DrawButton(gui, '+ MODULE', obj.sections[4505], gui.color.white, gui.skol.butt1_txt, true, '', false)
        GUI_DrawButton(gui, '+ FX NAME', obj.sections[4506], gui.color.white, gui.skol.butt1_txt, true, '', false)
        GUI_DrawButton(gui, '+ MANUAL', obj.sections[4507], gui.color.white, gui.skol.butt1_txt, true, '', false)
        local c = -1
        if lvar.sapd.assselected then
          c = gui.color.white
        end
        GUI_DrawButton(gui, 'SET DEFAULT', obj.sections[4508], c, gui.skol.butt1_txt, true, '', false)
      elseif lvar.sapd.selected and lvar.sapd.stripdata and #lvar.sapd.stripdata.fx ~= 1 then
        local xywh = {x = obj.sections[4505].x, y = obj.sections[4505].y, w = obj.sections[4508].x+obj.sections[4508].w - obj.sections[4505].x, h = obj.sections[4505].h}
        GUI_Str(gui, xywh, 'Strip cannot be associated with a plugin', 5, gui.color.red, -4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
      end
      local c = gui.color.white
      if lvar.sapd.stripdata and lvar.sapd.stripdata.quickload then
        c = -4
      end
      GUI_DrawButton(gui, 'QUICK LOAD', obj.sections[4509], c, gui.skol.butt1_txt, true, '', false)
    end

    gfx.dest = 1

  end

  function GUI_DrawAddStripDialog(obj, gui, dest)

    gfx.dest = dest or 1

    GUI_DrawPanel(obj.sections[4000],true,'ADD/REPLACE STRIP')

    f_Get_SSV('16 16 16')
    gfx.rect(obj.sections[4001].x,
             obj.sections[4001].y,
             obj.sections[4001].w,
             obj.sections[4001].h, 1)

    gfx.rect(obj.sections[4002].x,
             obj.sections[4002].y,
             obj.sections[4002].w,
             obj.sections[4002].h, 1)

    local butt_h = math.floor(butt_h*pnl_scale)
    local colcnt = math.floor((obj.sections[4001].h-4) / butt_h)-1

    local xywh = {x = obj.sections[4001].x,
                  y = obj.sections[4001].y-butt_h-4,
                  w = obj.sections[4001].w,
                  h = butt_h}

    GUI_DrawButton(gui, 'STRIP FX', xywh, -1, gui.skol.butt1_txt, true, '', false)
    --xywh.x = obj.sections[4002].x

    local tr = GetTrack(lvar.addstripdialog_tracknum)

    local trnm = ''
    if tr then
      trnm = reaper.GetTrackState(tr)
      if trnm == '' then
        trnm = string.format('%i',lvar.addstripdialog_tracknum+1)..': Untitled Track'
      end
    end
    local b = -1
    if lvar.livemode == 0 then
      b = gui.color.white
      GUI_DrawButton(gui, '<', obj.sections[4006], b, gui.skol.butt1_txt, true, '', false)
      GUI_DrawButton(gui, '>', obj.sections[4007], b, gui.skol.butt1_txt, true, '', false)
    end
    GUI_DrawButton(gui, 'TRACK FX: '..trnm, obj.sections[4005], b, gui.skol.butt1_txt, true, '', false)

    local fxdata = lvar.fxdata
    if fxdata then

      local xywh = {x = obj.sections[4001].x+8,
                    y = obj.sections[4001].y+2,
                    w = 20,
                    h = butt_h}
      local xywh2 = {x = obj.sections[4001].x+28,
                    y = obj.sections[4001].y+2,
                    w = obj.sections[4001].w-76,
                    h = butt_h}

      local xywh3 = {x = obj.sections[4001].x+obj.sections[4001].w-40,
                    y = obj.sections[4001].y+2,
                    w = 40,
                    h = butt_h}

      local assignedtfx = fxdata.assigned

      for f = 0, colcnt do
        local idx = f+1 + afxdialogS_offset
        if fxdata[idx] then
          local c = gui.skol.lst_txt
          local matchfx = fxdata[idx].fxnum
          if idx == fxdata.sel then
            f_Get_SSV(gui.color.white)

            gfx.rect(obj.sections[4001].x+2,
                     xywh2.y,
                     obj.sections[4001].w-4,
                     xywh2.h, 1)

            c = gui.skol.lst_txthl
          elseif matchfx then
            f_Get_SSV('64 64 64')

            gfx.rect(obj.sections[4001].x+2,
                     xywh2.y,
                     obj.sections[4001].w-4,
                     xywh2.h, 1)

          end
          if matchfx then
            GUI_Str(gui, xywh3, string.format('%i',matchfx+1), 5, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          else
            GUI_Str(gui, xywh3, 'NEW', 5, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          end
          GUI_Str(gui, xywh, string.format('%i',idx), 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          GUI_Str(gui, xywh2, CropFXName(fxdata[idx].fxnm), 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        end
        xywh.y = xywh.y + butt_h
        xywh2.y = xywh.y
        xywh3.y = xywh.y
      end

      xywh.x = obj.sections[4002].x+8
      xywh.y = obj.sections[4002].y+2
      xywh2.x = obj.sections[4002].x+28
      xywh2.y = obj.sections[4002].y+2

      for f = 0, colcnt do
        local idx = f+afxdialogT_offset
        if fxdata.tfxi[idx] and fxdata.tfxi[idx].fxname then
          local c = gui.skol.lst_txt
          if fxdata[fxdata.sel].fxguid == fxdata.tfxi[idx].fxguid then
            f_Get_SSV(gui.color.white)

            gfx.rect(obj.sections[4002].x+2,
                     xywh2.y,
                     obj.sections[4002].w-4,
                     xywh2.h, 1)

            c = gui.skol.lst_txthl

          elseif assignedtfx[idx] then
            f_Get_SSV('64 64 64')

            gfx.rect(obj.sections[4002].x+2,
                     xywh2.y,
                     obj.sections[4002].w-4,
                     xywh2.h, 1)
          end
          if fxdata.tfxi[idx].stripinfo then
            c = '240 0 0'
          end
          GUI_Str(gui, xywh, string.format('%i',idx+1), 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
          GUI_Str(gui, xywh2, CropFXName(fxdata.tfxi[idx].fxname), 4, c, -4 + gui.fontsz.lst+ lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        end
        xywh.y = xywh.y + butt_h
        xywh2.y = xywh.y
      end

      GUI_DrawButton(gui, 'LINK', obj.sections[4003], gui.color.white, gui.skol.butt1_txt, true, '', false)
      GUI_DrawButton(gui, 'CANCEL', obj.sections[4004], gui.color.white, gui.skol.butt1_txt, true, '', false)
    end

  end

  function GUI_DrawTemplateChooser(obj, gui)

    --gfx.setimgdim(952, -1, -1)
    Img_SetDim(952, obj.sections[5050].w,obj.sections[5050].h)

    gfx.dest = 952
    gfx.a = 1
    GUI_DrawPanel(obj.sections[5050],false,'SELECT TEMPLATE')

    local butt_h = butt_h*pnl_scale

    local hh = math.floor((lvar.tempchooser.th-4))
    local xywh = {x = 20,
                  y = butt_h + 10,
                  w = obj.sections[5050].w - 50 - hh,
                  h = hh}
    local xywh2 = {x = 10,
                   y = math.floor(butt_h + 10),
                   w = obj.sections[5050].w - 20,
                   h = hh}

    for i = 0, lvar.tempchooser.tmpc-1 do

      local p = i+lvar.template_strips_offs

      if lvar.template_strips[p] then

        local b = gui.color.white
        local c = gui.skol.butt1_txt
        if i == lvar.tempchooser.sel then
          b = -4
          c = gui.skol.butt4_txt
        end
        GUI_DrawButton(gui, '', xywh2, b, c, true, nil, nil, 4)
        f_Get_SSV('8 8 8')
        gfx.rect(xywh.x+xywh.w-6,xywh.y+6,hh+12,hh-12,1)

        local tmpnm = string.match(lvar.template_strips[p].fn,'(.+)%.strip') or lvar.template_strips[p].fn
        GUI_Str(gui, xywh, tmpnm, 5, c, 4 + gui.fontsz.lst + lst_fontscale, 1, nil, gui.fontnm.lst, gui.fontflag.lst)
        local fn = paths.strips_path..paths.templates_folder..'/'..tmpnm..'.png'
        if reaper.file_exists(fn) then
          local iidx = gfx.loadimg(953,fn)
          if iidx then
            local iw, ih = gfx.getimgdim(iidx)
            local scale = math.min((hh-16)/iw,(hh-16)/ih)
            local ox, oy = 0, 0
            if iw*scale < hh-16 then
              ox = (hh-12) - iw*scale
            end
            gfx.blit(iidx,scale,0,0,0,iw,ih,xywh.x+xywh.w + hh/2 - (iw*scale)/2,xywh.y + hh/2 - (ih*scale)/2)
          end
        end

        --[[if i == lvar.tempchooser.sel then
          f_Get_SSV(gui.color.yellow)
          gfx.roundrect(xywh2.x,xywh2.y,xywh2.w,xywh2.h,4,1)
        end]]

      end

      xywh.y = xywh.y + lvar.template_h*pnl_scale
      xywh2.y = xywh.y
    end

    gfx.dest = 1


  end

  function DM_Flash_Refresh()
    lvar.dm_refresh_timer = reaper.time_precise()+0.4
    lupd.update_trbtns = true

    --GUI_draw(obj, gui)

    --[[bc = -2
    gfx.dest = -1
    GUI_DrawButton(gui,'REFRESH',obj.sections[5000],bc,gui.color.white,true,nil,nil,4)
    gfx.update()]]

  end

  function HighlightBox(box_x, box_y, box_w, box_h, col, time)
    gfx.dest = -1
    f_Get_SSV(col)
    gfx.rect(box_x,box_y,box_w,box_h,0)
    gfx.update()
    lvar.highbox[#lvar.highbox+1] = {x = box_x, y = box_y, w = box_w, h = box_h, col = col, time = reaper.time_precise()+time}
  end

  function HighlightBox2(box_x, box_y, box_w, box_h, col, time)
    gfx.dest = -1
    if not col then
      col = 205 + (205 << 8) + (205 << 16)
    end
    gfx.r = (col & 255)/255
    gfx.g = ((col >> 8) & 255)/255
    gfx.b = ((col >> 16) & 255)/255
    gfx.rect(box_x,box_y,box_w,box_h,0)
    gfx.update()
    lvar.highbox[#lvar.highbox+1] = {x = box_x, y = box_y, w = box_w, h = box_h, col = col, time = reaper.time_precise()+time}
  end

  ------------------------------------------------------------

  function GUI_draw(obj, gui)
    gfx.mode = gmode
    local lupd = lupd
    local next = next
    local gfx = gfx
    local math = math

    if lvar.surface_fade then
      if lvar.surface_fade.start == 0 then
        gfx.dest = 826
        gfx.setimgdim(826, gfx1.main_w,gfx1.main_h)
        gfx.blit(-1, 1, 0,
          0,0, gfx1.main_w,gfx1.main_h,
          0,0, gfx1.main_w,gfx1.main_h, 0,0)
          
        lvar.surface_fade.start = 1
      end
    end
    
    --local shadows = lvar.shadows
    local fullscreen_open
    if show_eqcontrol == true or macro_edit_mode == true or snap_edit_mode == true or show_pinmatrix == true or show_xxy or macro_lrn_mode --[[or snaplearn]] or snaplrn_mode then
      fullscreen_open = true
    end

    lvar.blittbl = {}
    lvar.blittbl_cnt = 1
    local blittbl = lvar.blittbl
    local drawn_mm

    --if not lvar.surface_fade or lvar.surface_fade.start == 1 then 
    if lvar.livemode > 0 and mode == 0 then

      GUI_DrawMixModePopUp(obj, gui)

    end
    local p = 0

    if show_xxy == false and next(lupd) ~= nil or (lvar.dragswitcher and not (lvar.showpop and lvar.popout_autoarrange)) then
      --for a,b in pairs(lupd) do if b == true then DBG(a) end end

      gfx.dest = 1

      if lupd.update_gfx or resize_display then
        --gfx.setimgdim(1, -1, -1)
        --gfx.setimgdim(1, gfx1.main_w,gfx1.main_h)
        Img_SetDim(1, gfx1.main_w,gfx1.main_h)
      end

      if resize_display then
        --gfx.setimgdim(1003,-1,-1)
        --gfx.setimgdim(1005,-1,-1)
        --gfx.setimgdim(1006,-1,-1)
        --gfx.setimgdim(1007,-1,-1)
        --gfx.setimgdim(1011,-1,-1)
        Img_SetDim(1003,obj.sections[160].w, obj.sections[160].h)
        Img_SetDim(1005,obj.sections[180].w, obj.sections[180].h)
        Img_SetDim(1006,obj.sections[221].w, obj.sections[221].h)
        Img_SetDim(1007,obj.sections[220].w, obj.sections[220].h)
        Img_SetDim(1011,obj.sections[45].w, obj.sections[45].h)
        --lupd.update_gfx = true

      elseif resize_snaps then
        --gfx.setimgdim(1003,-1,-1)
        Img_SetDim(1003,obj.sections[160].w, obj.sections[160].h)
      elseif resize_fsnaps then
        Img_SetDim(1005,obj.sections[180].w, obj.sections[180].h, true)
      end

      if mode == 0 then

        --Live
        lvar.blitmmov = nil
        if (macro_edit_mode ~= true or macro_lrn_mode == true) and snap_edit_mode ~= true and show_pinmatrix ~= true then
          if lupd.update_gfx --[[or lupd.update_gfxctls]] then
            GUI_DrawControlBackG(obj, gui)
            GUI_DrawControls(obj, gui)
            if show_snapshots then
              GUI_DrawSnapshots(obj, gui)
            end
            if show_fsnapshots or show_xysnapshots then
              GUI_DrawFSnapshots(obj, gui)
            end
          elseif lupd.update_snaps or resize_display or (lupd.update_msnaps and resize_snaps) then
            GUI_DrawSnapshots(obj, gui)
            if lupd.update_fsnaps then
              GUI_DrawFSnapshots(obj, gui)
            end
            if lupd.update_ctls then
              GUI_DrawControls(obj, gui)
            end
          elseif lupd.update_fsnaps or (lupd.update_mfsnaps and resize_fsnaps) then
            GUI_DrawFSnapshots(obj, gui)
            if lupd.update_ctls then
              GUI_DrawControls(obj, gui)
            end
          elseif lupd.update_snapmorph then
            GUI_DrawSnapshots_Morph(obj, gui)
            if lupd.update_ctls then
              GUI_DrawControls(obj, gui)
            end
          elseif lupd.update_ctls then
            GUI_DrawControls(obj, gui)
          end
          if lupd.update_gfx or lupd.update_sidebar or resize_display then
            --GUI_DrawTracks(obj, gui)
            GUI_DrawSidebar(obj, gui)
          end
        end

        gfx.dest = 1
        if (macro_edit_mode == false or macro_lrn_mode == true) and show_striplayout == false and (lupd.update_gfx or lupd.update_surface
           or lupd.update_bg or lupd.update_msnaps or lupd.update_mfsnaps or ((stripgallery_view ~= 0 or lvar.livemode >= 1) and lupd.update_ctls)) then
          if show_bitmap == false then
            if striplayout_mt then

              GUI_DrawStripLayout()

            else
              if (lvar.livemode == 0 and stripgallery_view == 0) or macro_lrn_mode == true or snaplrn_mode == true then
                gfx.blit(strip_image,lvar.zoom,0,surface_offset.x,
                                  surface_offset.y,
                                  math.min(math.ceil(obj.sections[10].w/lvar.zoom),lvar.maxdim),
                                  math.min(math.ceil(obj.sections[10].h/lvar.zoom),lvar.maxdim),
                                  math.floor(obj.sections[10].x),
                                  math.floor(obj.sections[10].y))
              elseif lvar.livemode >= 1 and (stripgallery_view == 0 or macro_lrn_mode == true or snaplrn_mode == true) then
                gfx.a=1
                if not lvar.mixmode_fastdraw or lupd.update_gfx or lupd.update_surface then

                  GUI_DrawMixMode(obj, gui)
                  drawn_mm = 1

                elseif lvar.mixmode_fastdraw == 1 and lupd.update_ctls and lvar.showpop --[[and lvar.redrawpopup]] then

                  --GUI_DrawMixModePopUp(obj, gui)
                  drawn_mm = 1

                elseif lvar.mixmode_fastdraw == 1 and lupd.update_ctls and lvar.mmov_show == true then
                  if not lvar.mmov_scale then
                    GUI_DrawMMOV(obj, gui)
                  end
                  --GUI_BlitMMOV(obj, gui)
                  --lvar.blitmmov = true
                elseif lvar.mixmode_fastdraw == 2 then
                  GUI_DrawMixMode(obj, gui)
                  drawn_mm = 1
                end

              elseif lvar.livemode == 0 then

                GUI_DrawGallery()

              elseif lvar.livemode >= 1 then

                --GUI_DrawGallery()

              end
            end

          else
            
            f_Get_SSV(gui.color.white)
            gfx.rect(obj.sections[10000].x,
                     obj.sections[10000].y,
                     obj.sections[10000].w,
                     obj.sections[10000].h)

            if stripgallery_view == 0 and lvar.livemode == 0 then
              gfx.blit(ctl_bitmap,1,0,surface_offset.x,
                                surface_offset.y,
                                obj.sections[10].w,
                                obj.sections[10].h,
                                obj.sections[10].x,
                                obj.sections[10].y)
            else
              gfx.blit(ctl_bitmap2,1,0,0,
                                0,
                                obj.sections[10000].w,
                                obj.sections[10000].h,
                                obj.sections[10000].x,
                                obj.sections[10000].y)
            end
          end

        elseif show_striplayout == true and (lupd.update_gfx or lupd.update_surface or lupd.update_bg) then

          GUI_DrawStripLayout()

        end

        --[[if plist_w > 0 then
          gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,butt_h)
        end]]

        if lasso ~= nil then
          gfx.a = 0.2
          f_Get_SSV(gui.color.blue)
          local l = {l = lasso.l, r = lasso.r, t = lasso.t, b = lasso.b}
          if lasso.r < lasso.l then
            l.l = lasso.r
            l.r = lasso.l
          end
          if lasso.b < lasso.t then
            l.b = lasso.t
            l.t = lasso.b
          end
          gfx.rect(l.l,
                   l.t,
                   l.r-l.l,
                   l.b-l.t, 1, 1)
          if ctl_select ~= nil then

            gfx.a = 0.8
            f_Get_SSV(gui.color.green)
            local ls = 4
            for c = 1, #ctl_select do

              local cx = ctl_select[c].ctl
              local sctl = strips[tracks[track_select].strip][page].controls[cx]
              if sctl.ctlcat == ctlcats.fxparam or
                 sctl.ctlcat == ctlcats.gr_meter or
                 sctl.ctlcat == ctlcats.trackparam or
                 sctl.ctlcat == ctlcats.tracksend or
                 sctl.ctlcat == ctlcats.fxoffline or
                 sctl.ctlcat == ctlcats.rs5k or
                 sctl.ctlcat == ctlcats.midictl or
                 (sctl.ctlcat == ctlcats.macro and macroedittype_select == 1) then

                local x = sctl.xsc*lvar.zoom+4
                local y = sctl.ysc*lvar.zoom+4
                local w = sctl.wsc*lvar.zoom-8
                local h = sctl.hsc*lvar.zoom-8
                x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
                y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
                gfx.line(x,y,x+ls,y,1)
                gfx.line(x,y,x,y+ls,1)

                gfx.line(x+w,y,x+w-ls,y,1)
                gfx.line(x+w,y,x+w,y+ls,1)

                gfx.line(x+w,y+h-ls,x+w,y+h,1)
                gfx.line(x+w,y+h,x+w-ls,y+h,1)

                gfx.line(x,y+h-ls,x,y+h,1)
                gfx.line(x,y+h,x+ls,y+h,1)
              end
            end
          end
        end

        if snaplrn_mode == true then
          local strip = tracks[track_select].strip
          if snapshots[strip] and snapshots[strip][page][sstype_select] then
            local scnt = #snapshots[strip][page][sstype_select].ctls
            if scnt > 0 then
              for ssc = 1, scnt do
                local ctl = snapshots[strip][page][sstype_select].ctls[ssc].ctl
                if ctl then
                  if (snapshots[strip][page][sstype_select].ctls[ssc].delete or false) == false then
                    local cctl = strips[strip][page].controls[ctl]
                    local hidden = Switcher_CtlsHidden(cctl.switcher, cctl.grpid)
                    if hidden ~= true then
                      local floor = math.floor
                      local x = cctl.xsc*lvar.zoom
                      local y = cctl.ysc*lvar.zoom
                      local w = cctl.wsc*lvar.zoom
                      local h = cctl.hsc*lvar.zoom
                      x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
                      y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
                      f_Get_SSV(gui.color.green)
                      gfx.a = 1
                      gfx.roundrect(floor(x), floor(y), floor(w), floor(h), 5, 1)
                    end
                  end
                end
              end
            end
          end
        end

        if lupd.update_gfx or lupd.update_surface or lupd.update_msnaps then
          if ((lockh > 0 or lockw > 0) and lvar.livemode == 0) or surface_size.exceed == true then
            UpdateLEdges()
          end
        end

        if insertstrip ~= nil and CheckOver10() then

          local istrip = insertstrip

          if lvar.livemode >= 1 and sb_drag then
            local locs = sb_drag.drags.locs
            local t_swid = istrip.target
            if t_swid then
              --local pady = 20
              local x,y,w,h,gap = 0,0,0,0,20
              local o10y = obj.sections[10].y
              local o10b = obj.sections[10].y + obj.sections[10].h - 1
              local o10x = obj.sections[10].x + 1
              local o10r = obj.sections[10].x + obj.sections[10].w
              if lvar.mmov_show then
                if lvar.mixmodedir == 0 then
                  o10x = o10x + (lvar.mmov_vsize + lvar.mmov_pad*2)
                else
                  o10y = o10y + (lvar.mmov_vsize + lvar.mmov_pad*2)
                end
              end


              if lvar.livemode == 0 then
                x = locs[t_swid].l - surface_offset.x + obj.sections[10].x
                y = locs[t_swid].t - surface_offset.y + obj.sections[10].y
                w = (locs[t_swid].r - locs[t_swid].l)
                h = (locs[t_swid].b - locs[t_swid].t)
              else
                if lvar.showpop and lvar.popout_autoarrange then
                  --[[local pop = istrip.pop
                  if pop then
                    local swdata = lvar.stripdim.swdata
                    local rect10 = obj.sections[10]
                    local xoff, yoff = 0,0
                    x = rect10.x + pop.x + xoff
                    y = rect10.y + pop.y+(sh+gap)*lvar.zoom + yoff
                    w = swdata[t_swid].r - swdata[t_swid].l
                    h = swdata[t_swid].b - swdata[t_swid].t
                  end]]
                else
                  if lvar.mixmodedir == 0 then
                    local spos = lvar.spos[t_swid]
                    if spos then
                      x = spos.x
                      y = spos.y
                      w = spos.w*lvar.zoom
                      if w == 0 then
                        w = spos.sw*lvar.zoom
                        x = spos.sx
                      end
                      h = spos.h*lvar.zoom
                      gap = spos.gap*lvar.zoom
                    end
                  else
                    local spos = lvar.spos[t_swid]
                    if spos then
                      x = spos.x
                      --y = (spos.y + spos.sh)*lvar.zoom
                      --y = obj.sections[10].y + math.floor(obj.sections[10].h/2) - math.floor(((spos.h+spos.sh)/2)*lvar.zoom) +spos.sh*lvar.zoom +lvar.mmov_offs
                      y = spos.y + (spos.sh-spos.h) + spos.h
                      w = spos.w*lvar.zoom
                      if w == 0 then
                        w = spos.sw*lvar.zoom
                        x = spos.sx
                      end
                      h = spos.h*lvar.zoom
                    end
                  end
                  local spos = lvar.spos[t_swid]
  
                  if lvar.mixmodedir == 0 then
                    x, y, w, h = CropToRect(x,y+spos.sh*lvar.zoom,w-lvar.shadowmax*lvar.zoom,h-spos.sh*lvar.zoom,o10x,o10y,o10r,o10b)
                  else
                    x, y, w, h = CropToRect(x,y,w,h,o10x,o10y,o10r,o10b)
                    --x, y, w, h = CropToRect(x,y+spos.sh*lvar.zoom,w-lvar.shadowmax*lvar.zoom,h-spos.sh*lvar.zoom,o10x,o10y,o10r,o10b)
                  end
                end
              end
             
              gfx.a = 1
              f_Get_SSV(gui.color.yellow)
              if lvar.showpop and lvar.popout_autoarrange then
                
                --[[local pop = istrip.pop
                if pop then
                  local swdata = lvar.stripdim.swdata
                  local rect10 = obj.sections[10]
                  local xoff, yoff = 0,0
                  x = rect10.x + pop.x + xoff
                  y = rect10.y + pop.y+(sh+gap)*lvar.zoom + yoff
                  w = swdata[t_swid].r - swdata[t_swid].l
                  h = swdata[t_swid].b - swdata[t_swid].t
                end
                
                local ident = 2
                local midy = y+lvar.mmgap*lvar.zoom + h/2

                if not mouse.shift and not mouse.alt then
                  local barw = math.min(math.floor(w/2),40)
                  local sz = barw/2
                  if istrip.before == true then
                    gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,0)
                    gfx.triangle(x+ident,midy,x+barw-ident*2,midy-sz,x+barw-ident*2,midy+sz)
                  else
                    gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,0)
                    gfx.triangle(x+w-ident,midy,x+w-barw+ident*2,midy-sz,x+w-barw+ident*2,midy+sz)
                  end
                end]]
              
              else
                if lvar.mixmodedir == 0 then
                  local ident = 2
                  local midx = x+ w/2
  
                  if not mouse.shift and not mouse.alt then
                    local barh = --[[math.max(pady-4,10)]] math.min(math.floor(h/2),40)
                    local pad = math.floor(gap)
                    local sz = barh/2
                    if istrip.before == true then
                      gfx.rect(x,y,w,barh+1,1)
                      f_Get_SSV('0 0 0')
                      gfx.rect(x,y,w,barh+1,0)
                      gfx.triangle(midx,y+ident,midx-sz,y+barh-ident*2,midx+sz,y+barh-ident*2)
                    else
                      gfx.rect(x,y+h-barh-1,w,barh+1,1)
                      f_Get_SSV('0 0 0')
                      gfx.rect(x,y+h-barh-1,w,barh+1,0)
                      gfx.triangle(midx,y+h-ident*2,midx-sz,y+h-barh+ident,midx+sz,y+h-barh+ident)
                    end
                  end
                  gfx.a = 1
                  if mouse.shift or mouse.alt then
                    local spos = lvar.spos[t_swid]
                    if spos then
                      --x,y,w,h = CropToRect(spos.x,y,w,h,o10x,o10y,o10r,o10b)
                      if mouse.alt then
                        f_Get_SSV(gui.color.green)
                        GUI_Str(gui,{x=x+4,y=y,w=40,h=20},'LINK',4,gui.color.green,2,1,gui.color.black,nil,nil)
                      else
                        GUI_Str(gui,{x=x+4,y=y,w=60,h=20},'REPLACE',4,gui.color.yellow,2,1,gui.color.black,nil,nil)
                      end
                      gfx.rect(x,y,w,h,0)
                    end
                  end
                else
                  
                  local ident = 2
                  local midy = y+lvar.mmgap*lvar.zoom + h/2
  
                  if not mouse.shift and not mouse.alt then
                    local barw = math.min(math.floor(w/2),40)
                    local sz = barw/2
                    if istrip.before == true then
                      gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,1)
                      f_Get_SSV('0 0 0')
                      gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,0)
                      gfx.triangle(x+ident,midy,x+barw-ident*2,midy-sz,x+barw-ident*2,midy+sz)
                    else
                      gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,1)
                      f_Get_SSV('0 0 0')
                      gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,0)
                      gfx.triangle(x+w-ident,midy,x+w-barw+ident*2,midy-sz,x+w-barw+ident*2,midy+sz)
                    end
                  end
                  gfx.a = 1
                  if mouse.shift or mouse.alt then
                    local spos = lvar.spos[t_swid]
                    if spos then
                      if mouse.alt then
                        f_Get_SSV(gui.color.green)
                        GUI_Str(gui,{x=x+4,y=y,w=40,h=20},'LINK',5,gui.color.green,2,1,gui.color.black,nil,nil)
                      else
                        GUI_Str(gui,{x=x+4,y=y,w=60,h=20},'REPLACE',4,gui.color.yellow,2,1,gui.color.black,nil,nil)
                      end
                      gfx.rect(x,y,w,h+lvar.mmgap*lvar.zoom,0)
                    end
                  end
                end
              end
            end

          end

          --[[local x, y = istrip.x, istrip.y+math.floor(istrip.dy/settings_gridsize)*settings_gridsize
          local w, h = gfx.getimgdim(1022)
          if lvar.livemode >= 1 then
            gfx.a = (istrip.alpha or 0.8) * 0.7
            gfx.blit(1022,lvar.zoom,0,0,0,w,h,x-istrip.xoff,y)
            gfx.a = 1
            f_Get_SSV(gui.color.yellow)
            gfx.rect(x-istrip.xoff,y,w*lvar.zoom,h*lvar.zoom,0)
          else
            gfx.a = (istrip.alpha or 0.8)
            gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)
          end]]
          gfx.a = 1

        elseif cbdragstrip ~= nil --[[and CheckOver10()]] then

          local istrip = cbdragstrip
          local x, y = istrip.nx --[[+ istrip.dx - surface_offset.x]] + obj.sections[10].x,
                       istrip.ny --[[+ istrip.dy - surface_offset.y]] + obj.sections[10].y
          local w, h = gfx.getimgdim(1022)
          gfx.a = 1
          gfx.blit(1022,lvar.zoom,0,0,0,w,h,x-(b_sz*lvar.zoom),y-(b_sz*lvar.zoom))
          gfx.a = 1

        elseif lvar.dragswitcher and not (lvar.showpop and lvar.popout_autoarrange) then

          --local locs = lvar.dragswitcher.locs
          local locs = lvar.stripdim.swdata
          local t_swid = lvar.dragswitcher.target
          local s_swid = lvar.dragswitcher.selected
          local swdata = lvar.stripdim.swdata[s_swid]
          local strip = tracks[track_select].strip

          if s_swid then
            if lvar.livemode == 0 then

              --local x = locs[s_swid].l - surface_offset.x + obj.sections[10].x
              --local y = locs[s_swid].t - surface_offset.y + obj.sections[10].y
              local x = (locs[s_swid].l - surface_offset.x)*lvar.zoom + obj.sections[10].x
              local y = (locs[s_swid].t - surface_offset.y)*lvar.zoom + obj.sections[10].y
              local w = (locs[s_swid].r - locs[s_swid].l)
              local h = (locs[s_swid].b - locs[s_swid].t)
              if --[[lvar.livemode ~= 1 and]] not lupd.update_gfx and not lupd.update_surface then
                local gpage = lvar.stripdim.swdata[s_swid].gfxpage or 0
                gfx.blit(strip_image+gpage, 1, 0, locs[s_swid].l, locs[s_swid].t, w*lvar.zoom, h*lvar.zoom, x, y)
              end

              x = (locs[s_swid].l - surface_offset.x)*lvar.zoom + obj.sections[10].x
              y = (locs[s_swid].t - surface_offset.y)*lvar.zoom + obj.sections[10].y
              f_Get_SSV(backcol)
              gfx.a = 0.9
              gfx.rect(x,y,w*lvar.zoom,h*lvar.zoom,1)
              f_Get_SSV(gui.color.red)
              gfx.a = 1
              gfx.rect(x,y,w*lvar.zoom,h*lvar.zoom,0)
            else
              
            end
          end
          if t_swid and t_swid ~= s_swid then

            if lvar.livemode == 0 then
              x = (locs[t_swid].l - surface_offset.x)*lvar.zoom + obj.sections[10].x
              y = (locs[t_swid].t - surface_offset.y)*lvar.zoom + obj.sections[10].y
              local w = (locs[t_swid].r - locs[t_swid].l)
              local h = (locs[t_swid].b - locs[t_swid].t)
              local pady = 20
              f_Get_SSV(backcol2 or backcol)
              gfx.a = 1
              --gfx.rect(x,y,w,h,1)
              f_Get_SSV(gui.color.yellow)
              local barh = --[[math.max(pady-4,10)]] math.min(math.floor(h/2),40)
              if lvar.dragswitcher.before == true then
                gfx.rect(x,y,w*lvar.zoom,barh,1)
              else
                gfx.rect(x,y+h*lvar.zoom-barh,w*lvar.zoom,barh,1)
              end
              gfx.a = 1
              --gfx.rect(x,y,w,h,0)
            else
              local spos = lvar.spos[t_swid]
              if spos then
                if lvar.mixmodedir == 0 then
                  local x = spos.x
                  local y = spos.y
                  local w = spos.w*lvar.zoom
                  if w == 0 then
                    w = spos.sw*lvar.zoom
                    x = spos.sx
                  end
                  local h = spos.h*lvar.zoom
                  f_Get_SSV(backcol2 or backcol)
                  gfx.a = 1
                  f_Get_SSV(gui.color.yellow)
                  local barh = math.min(math.floor(h/2),40)

                  local o10y = obj.sections[10].y
                  local o10b = obj.sections[10].y + obj.sections[10].h - 1
                  local o10x = obj.sections[10].x + 1
                  local o10r = obj.sections[10].x + obj.sections[10].w
                  if lvar.mmov_show then
                    o10x = o10x + (lvar.mmov_vsize + lvar.mmov_pad*2)
                  end

                  if lvar.dragswitcher.before == true then
                    x,y,w,h = CropToRect(x,y,w-lvar.shadowmax*lvar.zoom,barh,o10x,o10y,o10r,o10b)
                    local sz = h/2
                    local ident = 2
                    local midx = x + w/2
                    gfx.rect(x,y,w,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x,y,w,h,0)
                    gfx.triangle(midx,y+ident,midx-sz,y+h-ident*2,midx+sz,y+h-ident*2)
                  else
                    x,y,w,h = CropToRect(x,y+h-barh,w-lvar.shadowmax*lvar.zoom,barh,o10x,o10y,o10r,o10b)
                    gfx.rect(x,y,w,h,1)
                    local sz = h/2
                    local ident = 2
                    local midx = x + w/2
                    gfx.rect(x,y,w,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x,y,w,h,0)
                    gfx.triangle(midx,y+h-ident*2,midx-sz,y+ident,midx+sz,y+ident)
                  end
                else
                  local x = spos.x
                  local y = spos.y
                  local w = spos.w*lvar.zoom
                  if w == 0 then
                    h = spos.sh*lvar.zoom
                    y = spos.sy
                  end
                  local h = spos.h*lvar.zoom
                  f_Get_SSV(backcol2 or backcol)
                  gfx.a = 1
                  f_Get_SSV(gui.color.yellow)
                  local barw = math.min(math.floor(w/2),40)
                  
                  local o10y = obj.sections[10].y
                  local o10b = obj.sections[10].y + obj.sections[10].h - 1
                  local o10x = obj.sections[10].x
                  local o10r = obj.sections[10].x + obj.sections[10].w
                  if lvar.mmov_show then
                    o10y = o10y + lvar.mmov_vsize + lvar.mmov_pad*2
                  end

                  if lvar.dragswitcher.before == true then
                    x,y,w,h = CropToRect(x,y + (spos.sh+lvar.mmgap)*lvar.zoom,barw,h,o10x,o10y,o10r,o10b)
                    local sz = w/2
                    local ident = 2
                    local midy = y + h/2
                    gfx.rect(x,y,w,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x,y,w,h,0)
                    gfx.triangle(x+ident,midy,x+w-ident*2,midy-sz,x+w-ident*2,midy+sz)
                  else
                    x,y,w,h = CropToRect(x+w-barw,y + (spos.sh+lvar.mmgap)*lvar.zoom,barw,h,o10x,o10y,o10r,o10b)
                    local sz = w/2
                    local ident = 2
                    local midy = y + h/2
                    gfx.rect(x,y,w,h,1)
                    f_Get_SSV('0 0 0')
                    gfx.rect(x,y,w,h,0)
                    gfx.triangle(x+w-ident*2,midy,x+ident,midy-sz,x+ident,midy+sz)
                  end
                end
                gfx.a = 1
              end
            end
          end

          if lvar.livemode >= 1 and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[s_swid] then
          else
            local a = 0.9
            if t_swid and t_swid ~= s_swid then
              a = 0.5
            --else
            --  gfx.a = 0.9
            end
            local gpage = lvar.stripdim.swdata[s_swid].gfxpage or 0
            --local swdata = lvar.stripdim.swdata[s_swid]
            local sh = swdata.sb-swdata.st
            local sw = swdata.sr-swdata.sl
            local xw = math.floor(-sw/2)
            if swdata.stripl then
              local gap = 0
              if lvar.livemode >= 1 then
                if lvar.mixmodealign == 0 or lvar.mixmodedir == 1 then
                  xw = math.floor((swdata.stripr-swdata.stripl)/2 - sw/2)*lvar.zoom
                else
                  xw = 0
                end
                gap = lvar.mmgap
              else
                xw = 0

                --[[if not lupd.update_gfx and not lupd.update_surface then
                  gfx.a = 1
                  gfx.blit(strip_image+gpage,1,0,mouse.mx-lvar.dragswitcher.offx,mouse.my-lvar.dragswitcher.offy+sh, swdata.stripr-swdata.stripl,swdata.stripb-swdata.stript,mouse.mx-lvar.dragswitcher.offx,mouse.my-lvar.dragswitcher.offy+sh)
                  gfx.blit(strip_image+gpage,1,0,mouse.mx-lvar.dragswitcher.offx+xw,mouse.my-lvar.dragswitcher.offy,sw,sh,mouse.mx-lvar.dragswitcher.offx+xw,mouse.my-lvar.dragswitcher.offy)
                end]]
              end
              gfx.a = 1--a

              --crop to obj10
              local mmx = mouse.mx-lvar.dragswitcher.offx
              local mmy = mouse.my-lvar.dragswitcher.offy+(sh+gap)*lvar.zoom
              local yoff = 0
              --[[if lvar.showpop and lvar.popout_autoarrange then
                yoff = mmy + lvar.pop_yoff
              end]]

              if lvar.livemode > 0 then
                blittbl[lvar.blittbl_cnt] = {strip_image+gpage,lvar.zoom,0,
                         swdata.stripl--[[-cutw/lvar.zoom]],
                         swdata.stript--[[-cuth2/lvar.zoom]],
                         math.max(swdata.stripr-swdata.stripl+lvar.shadowmax--[[+cutw/lvar.zoom]],0),
                         math.max(swdata.stripb-swdata.stript+lvar.shadowmax--[[+cuth/lvar.zoom+cuth2/lvar.zoom]],0),
                         mmx, mmy}
                blittbl[lvar.blittbl_cnt+1] = {strip_image+gpage,lvar.zoom,0,
                         swdata.sl,swdata.st,sw,sh,
                         mouse.mx-lvar.dragswitcher.offx+xw,mouse.my-lvar.dragswitcher.offy}
                lvar.blittbl_cnt = lvar.blittbl_cnt + 2
              else
                mmx = mouse.mx-lvar.dragswitcher.offx
                mmy = mouse.my-lvar.dragswitcher.offy+(sh+gap)*lvar.zoom
                gfx.blit(strip_image+gpage,lvar.zoom,0,
                         swdata.stripl--[[-cutw/lvar.zoom]],
                         swdata.stript--[[-cuth2/lvar.zoom]],
                         math.max(swdata.stripr-swdata.stripl--[[+cutw/lvar.zoom]],0),
                         math.max(swdata.stripb-swdata.stript--[[+cuth/lvar.zoom+cuth2/lvar.zoom]],0),
                         mmx, mmy)
              end
              --gfx.blit(strip_image+gpage,lvar.zoom,0,swdata.sl,swdata.st,sw,sh,mouse.mx-lvar.dragswitcher.offx+xw,mouse.my-lvar.dragswitcher.offy)
            else
              gfx.a = a
              if lvar.livemode >= 1 then
                gfx.blit(strip_image+gpage,1,0,swdata.sl,swdata.st,sw,sh,mouse.mx-lvar.dragswitcher.offx+xw,mouse.my-lvar.dragswitcher.offy)
              else
                gfx.blit(strip_image+gpage,1,0,swdata.sl,swdata.st,sw,sh,mouse.mx-lvar.dragswitcher.offx,mouse.my-lvar.dragswitcher.offy)
              end
            end
            if lvar.livemode >= 1 then
              local strip = tracks[track_select].strip
              if lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[s_swid] then
                f_Get_SSV(gui.color.white)
                gfx.rect(mouse.mx-lvar.dragswitcher.offx,mouse.my-lvar.dragswitcher.offy+sh,swdata.stripr-swdata.stripl,swdata.stripb-swdata.stript,0)
              end
            end
          end
          --gfx.blit(strip_image+gpage,1,0,locs[s_swid].l,locs[s_swid].t,locs[s_swid].r-locs[s_swid].l,locs[s_swid].b-locs[s_swid].t,mouse.mx-lvar.dragswitcher.offx,mouse.my-lvar.dragswitcher.offy)
          gfx.a = 1
        end

        if macro_lrn_mode == true and (lupd.update_gfx or lupd.update_surface or lupd.update_ctls) then
          gfx.a = 1
          GUI_DrawButton(gui,'EXIT MACRO LRN',obj.sections[250],-2,gui.color.white,true)

          local strip = tracks[track_select].strip
          if strips and strips[strip] and strips[strip][page].controls[macroctl_select] then
            if strips[strip][page].controls[macroctl_select].macroctl then
              local mcnt = #strips[strip][page].controls[macroctl_select].macroctl
              if mcnt > 0 then
                for mc = 1, mcnt do
                  local ctl = strips[strip][page].controls[macroctl_select].macroctl[mc].ctl
                  if ctl then
                    if nz(strips[strip][page].controls[macroctl_select].macroctl[mc].delete,false) == false then
                      local x = strips[strip][page].controls[ctl].xsc*lvar.zoom
                      local y = strips[strip][page].controls[ctl].ysc*lvar.zoom
                      local w = strips[strip][page].controls[ctl].wsc*lvar.zoom
                      local h = strips[strip][page].controls[ctl].hsc*lvar.zoom
                      x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
                      y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
                      f_Get_SSV(gui.color.blue)
                      gfx.a = 1
                      local floor = math.floor
                      gfx.roundrect(floor(x), floor(y), floor(w), floor(h), 5, 1)
                      --gfx.roundrect(x+1, y+1, w-2, h-2, 5, 1)
                    end
                  end
                end
              end
            end
          end
        end

        if lvar.stripctlbox.idx then
          gfx.a = 1
          local dx, dy = 0, 0
          if stripgallery_view == 0 then
            if cbdragstrip then
              dx, dy = surface_offset.x - (cbdragstrip.dx or 0), surface_offset.y - (cbdragstrip.dy or 0)
            else
              dx, dy = surface_offset.x, surface_offset.y
            end
          else
            dx = stlay_data.xpos
          end
          if stripgallery_view == 0 then
            local x = obj.sections[10].x+lvar.stripctlbox.x-math.floor(dx*lvar.zoom)
            local y = obj.sections[10].y+lvar.stripctlbox.y-math.floor(dy*lvar.zoom)
            local iw, ih = gfx.getimgdim(skin.stripctlbtns)
            gfx.blit(skin.stripctlbtns,1,0,0,0,iw,ih,x,y)
          end
          local x = obj.sections[10].x+lvar.stripctlboxX.x-math.floor(dx*lvar.zoom)
          local y = obj.sections[10].y+lvar.stripctlboxX.y-math.floor(dy*lvar.zoom)
          local iw, ih = gfx.getimgdim(skin.stripctlbtnsX)
          gfx.blit(skin.stripctlbtnsX,1,0,0,0,iw,ih,x,y)

          if stripgallery_view == 0 and lvar.stripctlbox.ctl then
            local iw, ih = gfx.getimgdim(skin.stripctlbtnslock)
            local x = obj.sections[10].x+(lvar.stripctlbox.ctl.x)-math.floor(dx*lvar.zoom) --+math.floor(lvar.stripctlbox.ctl.w/2-iw/2)
            local y = obj.sections[10].y+(lvar.stripctlbox.ctl.y)-math.floor(dy*lvar.zoom) --+lvar.stripctlbox.ctl.h-2
            gfx.blit(skin.stripctlbtnslock,1,0,0,0,iw,ih,x,y)
          end
        end

        if cbdragstrip == nil and show_striplayout ~= true then
          if lvar.showtakeover and lvar.mousefadermode == 0 and lvar.mofader_takeover and lupd.update_surface then
            gfx.a = 1
            --local xywh = {x = lvar.mofader_takeover.mx - 30, y = lvar.mofader_takeover.my - 20, w = 60, h = 15}
            if not lvar.mofader_takeover.to then
              --local xywh = lvar.mofader_takeover.xywh
              --f_Get_SSV('0 255 0')
              --gfx.roundrect(math.floor(xywh.x),math.floor(xywh.y),math.floor(xywh.w),math.floor(xywh.h),4,1)
            --else
              local p = lvar.mofader_takeover.pos*100
              local t = lvar.mofader_takeover.target*100
              local d = math.floor(math.abs(p-t)/2)
              local xywh = lvar.mofader_takeover.xywh
              local x = math.floor(xywh.x+xywh.w/2-math.floor(d/2))
              local y = xywh.y - 20
              local r = math.floor(d*5.12)
              local g = math.floor((50-d)*5.12)
              f_Get_SSV(tostring(r)..' '..tostring(g)..' 0')
              gfx.rect(x-1,y,3,16,1)
              gfx.rect(x+d-1,y,3,16,1)
              f_Get_SSV('255 0 0')
              gfx.roundrect(math.floor(xywh.x),math.floor(xywh.y),math.floor(xywh.w),math.floor(xywh.h),4,1)
            end
          elseif lvar.showtakeover and lvar.mofader_takeover and lvar.mofader_takeover.to then
            gfx.a = 1
            --local xywh = {x = lvar.mofader_takeover.mx - 30, y = lvar.mofader_takeover.my - 20, w = 60, h = 15}
            if lvar.mofader_takeover.to then
              local xywh = lvar.mofader_takeover.xywh
              f_Get_SSV('0 255 0')
              gfx.roundrect(math.floor(xywh.x),math.floor(xywh.y),math.floor(xywh.w),math.floor(xywh.h),4,1)
            end
          end
        end

        if lvar.blitmmov then
          GUI_BlitMMOV(obj, gui)
          --lvar.blitmmov = nil
        elseif lvar.mmov_show then
          --[[f_Get_SSV(backcol2 or backcol)
          if lvar.mixmodedir == 0 then
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,lvar.mmov_vsize+lvar.mmov_pad*2,obj.sections[10000].h+1,1)
            f_Get_SSV('0 0 0')
            gfx.a = 0.2
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,lvar.mmov_vsize+lvar.mmov_pad*2,obj.sections[10000].h+1,1)
            gfx.a = 1
            gfx.rect(obj.sections[10000].x+lvar.mmov_vsize+lvar.mmov_pad*2,obj.sections[10000].y-1,1,obj.sections[10000].h+1,1)
          else
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,lvar.mmov_vsize+lvar.mmov_pad*2,1)
            f_Get_SSV('0 0 0')
            gfx.a = 0.2
            gfx.rect(obj.sections[10000].x,obj.sections[10000].y-1,obj.sections[10000].w,lvar.mmov_vsize+lvar.mmov_pad*2,1)
          end]]
        end

        if lvar.blitmmov then
          lvar.blitmmov = nil
        end

        if lvar.livemode == 2 and (lupd.update_gfx or lupd.update_surface or lvar.blitmmov or lupd.update_trbtns) and not fullscreen_open then
          if lvar.dm_showtrackname and lvar.dm_trname then
            GUI_Str(gui,obj.sections[5001],lvar.dm_trname,4,gui.color.white,18,1,gui.color.black,nil,105)
          end

          if lvar.trbtns_show then

            local pof = 0
            if lvar.trmix_show then
              pof = lvar.trmix_h
            end
            if obj.sections[4999].y ~= obj.sections[10].y+obj.sections[10].h+pof then
              --repos
              obj = PosTrBtns(obj)
            end

            gfx.a = 1
            if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
              gfx.blit(lvar.bgloaded,1,0,-(lvar.bgoffx or 0),obj.sections[4999].y-pof-obj.sections[10].y-(lvar.bgoffy or 0),
                       obj.sections[4999].w,obj.sections[4999].h+pof,obj.sections[4999].x,obj.sections[4999].y-pof)
            else
              f_Get_SSV(backcol2 or backcol)
              gfx.rect(obj.sections[4999].x, obj.sections[4999].y-pof, obj.sections[4999].w, obj.sections[4999].h+pof, 1)
            end
            gfx.a = lvar.mmov_tint
            f_Get_SSV(gui.color.black)
            gfx.rect(obj.sections[4999].x,
                     obj.sections[4999].y-pof,
                     obj.sections[4999].w,
                     obj.sections[4999].h+pof, 1)
            gfx.a = 1

            local mmov = 0
            if lvar.mmov_show and lvar.mixmodedir == 0 then
              mmov = lvar.mmov_vsize +lvar.mmov_pad*2
            end
            local mmovx = obj.sections[10000].x + mmov
            if lvar.trmix_show then
              gfx.a = lvar.trmix_pnl_tbar_alpha
              gfx.rect(mmovx, obj.sections[4999].y-pof, obj.sections[4999].w, lvar.trmix_pnl_tbar, 1)
            end
            gfx.a = 1
            gfx.rect(mmovx, obj.sections[4999].y-1-pof, obj.sections[4999].w, 1, 1)
          end

          if lvar.trbtns_show then
            local txt = ''
            if lvar.dm_tbidx > 0 and lvar.dm_trackbtns[lvar.dm_tbidx] then
              if lvar.dm_tbidx == lvar.trbtns_autoidx then
                txt = ' [AUTO]'
              else
                txt = ' ['..(lvar.dm_trackbtns[lvar.dm_tbidx].name or ('Set '..string.format('%i',lvar.dm_tbidx)))..']'
              end
            end

            GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
            local tab, th = GetWWData('TRACKS SELECTOR'..txt, obj.sections[5041].w-10)
            if not tab[#tab].t then
              tab[#tab] = nil
            end
            GUI_DrawButtonWW(gui, tab, th, 4, obj.sections[5041], -1, gui.color.white, true, nil, nil, 0)

            if LBX_GTRACK and obj.sections[5007] then
              GUI_DrawButton(gui,'GLOBAL',obj.sections[5007],-1,gui.color.white,true,nil,nil,4)
            end
            GUI_DrawButton(gui,'<',obj.sections[5002],-1,gui.color.white,true,nil,nil,4)
            GUI_DrawButton(gui,'>',obj.sections[5003],-1,gui.color.white,true,nil,nil,4)
            if lvar.dm_backtrack then
              local trname = '-'
              local track = GetTrack(lvar.dm_backtrack.trn)
              if GetTrackGUID(track) ~= lvar.dm_backtrack.guid then
                local trn = GetTRNfromGUID(lvar.dm_backtrack.guid)
                if trn then
                  lvar.dm_backtrack.trn = trn
                  track = GetTrack(trn)
                else
                  track = nil
                end
              end
              if track then
                _, trname = reaper.GetTrackName(track)
                if trname == '' then
                  trname = 'Track '..string.format('%i',dm_trackbtns[tb].trn+1)
                  GUI_DrawButton(gui,trname,obj.sections[5006],bc,gui.color.white,true,nil,nil,4)
                else
                  local tab, th = GetWWData(trname, obj.sections[5006].w-8)
                  if not tab[#tab].t then
                    tab[#tab] = nil
                  end
                  GUI_DrawButtonWW(gui, tab, th, 4, obj.sections[5006], bc, gui.color.white, true, nil, nil, 4)
                end
              end
            else
              GUI_DrawButton(gui,'BACK',obj.sections[5006],-1,gui.color.white,true,nil,nil,4)
            end

            if lupd.update_gfx or lupd.update_trbtns or resize_display then

              xywh = {x = 6, y = 0, w = obj.sections[5004].w, h = obj.sections[5004].h-6}
              local cnt = math.min(--[[#lvar.dm_trackbtns[lvar.dm_tbidx]+1,]] lvar.trov_maxrows, lvar.dm_maxvistracks+1)
              local w = (xywh.w + 10)*(cnt+1)

              gfx.dest = 951
              --[[gfx.setimgdim(951, -1,-1)
              gfx.setimgdim(951, w,obj.sections[5004].h)]]
              Img_SetDim(951, w,obj.sections[5004].h, nil, true) --No idea why but need to use mthod2 to clear or graphics goes squiffy.

              local ts = 3
              local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
              if dm_trackbtns then
                for tb2 = 1, cnt do
                  if tb2 ~= cnt then
                    local tb = tb2 + lvar.trbtns_offs
                    if dm_trackbtns[tb] then
                      local tr = GetTrack(dm_trackbtns[tb].trn)
                      if tr then
                        if GetTrackGUID(tr) ~= dm_trackbtns[tb].guid and dm_trackbtns[tb].trn ~= -1 then
                          tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtns[tb].guid)
                          if tr then
                            dm_trackbtns[tb].trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                          end
                        end
                      end
                      if tr then
                        local trname = reaper.GetTrackState(tr)
                        local bc = -1
                        if GetTrackGUID(tr) == lvar.dynamicmode_guid then
                          bc = -8
                        elseif reaper.IsTrackSelected(tr) then
                          bc = -10                      
                        end
                        if trname == '' then
                          trname = 'Track '..string.format('%i',dm_trackbtns[tb].trn+1)
                          GUI_DrawButton(gui,trname,xywh,bc,gui.color.white,true,nil,nil,ts)
                        else
                          --gfx.setfont(1, gui.fontnm.butt, -4 + gui.fontsz.butt, gui.fontflag.butt)
                          local tab, th = GetWWData(trname, obj.sections[5004].w-10)
                          if not tab[#tab].t then
                            tab[#tab] = nil
                          end
                          local tnum = ''
                          if dm_trackbtns[tb].trn > -1 then
                            tnum = string.format('%i',dm_trackbtns[tb].trn+1)
                          end
                          GUI_DrawButtonWW(gui, tab, th-2, 4, xywh, bc, gui.color.white, true, nil, nil, ts, nil, nil, nil, tnum, ts-4)
                        end
                        if dm_trackbtns[tb].solo and dm_trackbtns[tb].solo > 0 then
                          f_Get_SSV(lvar.trbtns_solocolor)
                          --if dm_trackbtns[tb].mute == 0 then
                            gfx.rect(xywh.x + 4, xywh.y + 4, 14, 8, 1)
                            f_Get_SSV(gui.color.black)
                            gfx.rect(xywh.x + 4, xywh.y + 4, 14, 8, 0)
                          --else
                          --  gfx.rect(xywh.x + 4, xywh.y + 4, math.floor(xywh.w/2) - 6, 10, 1)
                          --end
                        end
                        if dm_trackbtns[tb].mute and dm_trackbtns[tb].mute > 0 then
                          f_Get_SSV(lvar.trbtns_mutecolor)
                          --if dm_trackbtns[tb].solo == 0 then
                            gfx.rect(xywh.x + xywh.w - 18, xywh.y + 4, 14, 8, 1)
                            f_Get_SSV(gui.color.black)
                            gfx.rect(xywh.x + xywh.w - 18, xywh.y + 4, 14, 8, 0)
                          --else
                          --  gfx.rect(xywh.x+math.floor(xywh.w/2) + 2, xywh.y + 4, math.floor(xywh.w/2) - 6, 10, 1)
                          --end
                        end
                        --[[if reaper.BR_GetMediaTrackFreezeCount(tr) > 0 then
                          f_Get_SSV(lvar.trbtns_freezecolor)
                          gfx.rect(xywh.x + 4, xywh.y + xywh.h - 13, 14, 8, 1)
                          f_Get_SSV(gui.color.black)
                          gfx.rect(xywh.x + 4, xywh.y + xywh.h - 13, 14, 8, 0)                        
                        end]]
                        local col = reaper.GetMediaTrackInfo_Value(tr, 'I_CUSTOMCOLOR')
                        dm_trackbtns[tb].col = col
                        if col and (col & 0x1000000 == 0x1000000) then
                          local r,g,b = reaper.ColorFromNative(col)
                          local colx = tostring(r)..' '..tostring(g)..' '..tostring(b)
                          f_Get_SSV(colx)
                          gfx.rect(xywh.x + 4, xywh.y+xywh.h + 1, xywh.w - 8, 10, 1)
                        end
                      else
                        local tab, th = GetWWData('TRACK NOT FOUND', obj.sections[5004].w-10)
                        if not tab[#tab].t then
                          tab[#tab] = nil
                        end
                        GUI_DrawButtonWW(gui, tab, th, 4, xywh, bc, gui.color.white, true, nil, nil, ts)
                      end
                    end
                  else
                    xywh.w = xywh.w - 5
                    GUI_DrawButton(gui,'+',xywh,-6,'128 128 128',true,nil,nil,20)
                  end
  
                  xywh.x = xywh.x + xywh.w + 10
                end
              end
            end
            gfx.dest = 1
            gfx.a = 1
            gfx.blit(951, 1, 0, 0, 0, obj.sections[5005].w, obj.sections[5005].h, obj.sections[5005].x, obj.sections[5005].y)

            if lvar.trmix_show and not lvar.mixerscroll_time then
              if lupd.update_gfx or lupd.update_trbtns or lupd.update_mixer or resize_display then

                GUI_DrawMixerPanel(obj, gui)

              end

              GUI_BlitMixerPanel(obj, gui, 0, 0)

            end

          end

          gfx.a = 1
          local bc = -1
          if lvar.dm_refresh == true or lvar.dm_refresh_timer then
            bc = -2
          end
          GUI_DrawButton(gui,'REFRESH',obj.sections[5000],bc,gui.color.white,true,nil,nil,4)

        elseif track_select == LBX_GTRACK and (lupd.update_gfx or lupd.update_surface) then

          local txt = 'EXIT GLOBAL'
          local tab, th = GetWWData(txt, obj.sections[5007].w-10)
          if not tab[#tab].t then
            tab[#tab] = nil
          end
          GUI_DrawButtonWW(gui,tab,th,4,obj.sections[5007],-1,gui.color.white,true,nil,nil,4)

        end

        if lvar.mixerscroll_time and lvar.livemode == 2 and not fullscreen_open then

          local y = lvar.mixerscroll_y
          local h = lvar.mixerscroll_h

          gfx.mode = 2
          gfx.blit(825,1,0,0,0,obj.sections[5024].w,h,obj.sections[5024].x,y)
          gfx.mode = gmode

        else
          if lvar.livemode == 2 and lvar.trbtns_show and lvar.trmix_show and (lupd.update_trmix or lupd.update_trmix2) and not fullscreen_open then
            --update mixer track only
            if #lvar.trmix_dirty > 0 then
              local cnt = math.min(lvar.dm_maxvistracks,lvar.trov_maxrows-1) --math.min(#lvar.dm_trackbtns[lvar.dm_tbidx], lvar.trov_maxrows-1, lvar.dm_maxvistracks)
              for i = 1, #lvar.trmix_dirty do
                local tb = lvar.trmix_dirty[i]
                --DBG(tb..'  '..cnt)
                if tb-lvar.trbtns_offs <= cnt then
                  local x, tb2
                  if not lupd.update_trmix then
                    x, tb2 = GUI_DrawMixerChannel2(obj, gui, tb)
                  else
                    x, tb2 = GUI_DrawMixerChannel(obj, gui, tb)
                  end
                  gfx.dest = 1
                  if lvar.analyzer.active ~= true then
                    local x = (tb2-1)*(obj.sections[5025].w+10)
                    gfx.mode = 2
                    gfx.blit(954, 1, 0, x, 0, obj.sections[5025].w+10, obj.sections[5025].h, obj.sections[5025].x + x, obj.sections[5024].y)
                    gfx.mode = gmode
                  end
                end
              end
              lvar.trmix_dirty = {}
            end
            if #lvar.trmix_sndpnl_dirty > 0 then
              for i = 1, #lvar.trmix_sndpnl_dirty do
                local tb = lvar.trmix_sndpnl_dirty[i]
                local x, tb2 = GUI_DrawSendChannel(obj, gui, tb)
                gfx.dest = 1
                local x = (tb2)*(lvar.sndpnl_cwidth+10)
                gfx.mode = 2
                gfx.blit(955, 1, 0, x, 0, lvar.sndpnl_cwidth+10, obj.sections[5030].h, obj.sections[5030].x + x, obj.sections[5024].y)
                gfx.mode = gmode
              end
              lvar.trmix_sndpnl_dirty = {}
            end
            if lvar.btnpnl_dirty then
              gfx.dest = 1
              gfx.blit(956, 1, 0, 0, 0, obj.sections[5040].w, obj.sections[5040].h, obj.sections[5040].x, obj.sections[5040].y)
              lvar.btnpnl_dirty = nil
            end
            if lvar.btnpnl2_dirty then
              gfx.dest = 1
              if not (lvar.trmix_sndpnl_show > 0) then
                gfx.blit(957, 1, 0, 0, 0, obj.sections[5042].w, obj.sections[5042].h, obj.sections[5042].x, obj.sections[5042].y)
              end
              lvar.btnpnl2_dirty = nil
            end
            if lupd.update_analyzerctls and lvar.analyzer.active then
              GUI_DrawAnalyzerControls(obj, gui)
              gfx.blit(962, 1, 0, 0, 0, obj.sections[5047].w, obj.sections[5047].h,
                                  obj.sections[5047].x, obj.sections[5047].y)
            end
            if lupd.update_analyzertracks and lvar.analyzer.active and lvar.analyzer.pos == 0 then
              GUI_DrawAnalyzerTracks(obj, gui)
              gfx.blit(963, 1, 0, 0, 0, obj.sections[5048].w, obj.sections[5048].h,
                                  obj.sections[5048].x, obj.sections[5048].y)
            end
          end
        end

        if plist_w > 0 and not matrixoff and (lupd.update_gfx or lupd.update_surface or lupd.update_sidebar) then

          --gfx.blit(skin.shadow,1,0,sw-50,100,50,50,obj.sections[43].w,0,50,obj.sections[43].h)
          gfx.a = 1
          gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,0)
        end

        --[[if settings_showmorphpop then
          if #morph_data > 0 then
            GUI_DrawMorph(obj, gui)
          end
        end

        if show_mutate then
          if lupd.update_gfx or lupd.update_mutate then
            GUI_DrawMutate(obj, gui)
          end
          gfx.blit(989,1,0,0,0,obj.sections[1120].w,obj.sections[1120].h,obj.sections[1120].x,obj.sections[1120].y)
        end

        if show_randomopts then
          if lupd.update_gfx or lupd.update_randomopts then
            GUI_DrawRandomOpts(obj, gui)
          end
          gfx.blit(988,1,0,0,0,obj.sections[1130].w,obj.sections[1130].h,obj.sections[1130].x,obj.sections[1130].y)
        end]]

        if settings_ssdock and show_snapshots and macro_lrn_mode ~= true then

          gfx.blit(1003,1,0,0,0,obj.sections[160].w,obj.sections[160].h,obj.sections[160].x,obj.sections[160].y)

          if dragparam ~= nil then
            local x, y = dragparam.x, dragparam.y
            gfx.a = dragparam.alpha or 0.7
            local iidx = ctl_files[knob_select].imageidx
            if iidx == nil and ksel_loaded == false then
              ksel_loaded = true
              gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
              iidx = 1023
            elseif iidx == nil then
              iidx = 1023
            end
            local w, _ = gfx.getimgdim(iidx)
            local h = ctl_files[knob_select].cellh
            dragparam.iw, dragparam.ih = w, h
            gfx.blit(iidx,scale_select*lvar.zoom,0,0,p*h,w,ctl_files[knob_select].cellh,x,y)
            if dragparam.alpha and dragparam.alpha < 1 then
              f_Get_SSV(gui.color.red)
            else
              f_Get_SSV(gui.color.yellow)
            end
            gfx.a = 1
            gfx.roundrect(x, y ,w*lvar.zoom, h*lvar.zoom, 8, 1, 0)
          end
        end

        --[[if show_fsnapshots or show_xysnapshots then
          gfx.blit(1005,1,0,0,0,obj.sections[180].w,obj.sections[180].h,obj.sections[180].x,obj.sections[180].y)
        end]]

        if show_eqcontrol then
          if lupd.update_gfx or lupd.update_surface then
            GUI_DrawEQControl(obj, gui)
          end
          gfx.a=1

          gfx.blit(1009,1,0,0,0,obj.sections[300].w,obj.sections[300].h,obj.sections[300].x,obj.sections[300].y)
          GUI_DrawEQBands(obj, gui)

        elseif show_pinmatrix then

          if (matrixoff and matrixoff.update == true) or (not matrixoff and (lupd.update_gfx or lupd.update_surface)) then
            GUI_DrawPinMatrix(obj, gui)
          end
          gfx.a=1
          if matrixoff then
            f_Get_SSV(gui.color.black)
            if matrixoff.x > 0 then
              gfx.rect(obj.sections[10].x, topbarheight, matrixoff.x, obj.sections[1200].h)
            else
              gfx.rect(gfx1.main_w+matrixoff.x, topbarheight, -matrixoff.x, obj.sections[1200].h)
            end
            if matrixoff.y > 0 then
              gfx.rect(obj.sections[10].x, topbarheight, obj.sections[1200].w, matrixoff.y)
            else
              gfx.rect(obj.sections[10].x, gfx1.main_h+matrixoff.y, obj.sections[1200].w, -matrixoff.y)
            end
            gfx.blit(987,1,0,0,0,obj.sections[1200].w,obj.sections[1200].h,obj.sections[10].x+(matrixoff.x),topbarheight+(matrixoff.y))

            if plist_w > 0 then
              gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,0)
            end
          else
            gfx.blit(987,1,0,0,0,obj.sections[1200].w,obj.sections[1200].h,obj.sections[10].x,topbarheight)
          end

        elseif macro_edit_mode == true and macro_lrn_mode == false then
          if lupd.update_surface or lupd.update_gfx or lupd.update_macrobutt or lupd.update_macroedit then
            GUI_DrawMacroEdit(obj, gui)
          end
          gfx.a=1

          gfx.blit(1008,1,0,0,0,obj.sections[300].w,obj.sections[300].h,obj.sections[300].x,obj.sections[300].y)

        elseif snap_edit_mode == true and snaplrn_mode ~= true then
          if lupd.update_gfx or lupd.update_macrobutt or lupd.update_macroedit or resize_display then
            GUI_DrawSnapEdit(obj, gui)
          end
          gfx.a=1

          gfx.blit(1008,1,0,0,0,obj.sections[300].w,obj.sections[300].h,obj.sections[300].x,obj.sections[300].y)

          if snapparamdrag then
            local w,h = gfx.getimgdim(snapparamdrag.iidx)
            local x = mouse.mx - snapparamdrag.xoff
            local y = mouse.my - snapparamdrag.yoff
            gfx.blit(snapparamdrag.iidx,1,0,0,0,w,h,x,y)
          end

        elseif settings_moddock == true and show_lfoedit and not fullscreen_open then
          if lupd.update_gfx or lupd.update_lfoedit or resize_display then
            GUI_DrawLFOEdit(obj, gui)
          elseif lupd.update_lfoeditbar then
            GUI_DrawLFOBar(obj, gui)
          end
          if lupd.update_lfopos then
            GUI_DrawLFOPos(obj, gui)
          end
          gfx.blit(992,1,0,0,0,obj.sections[1100].w,obj.sections[1100].h,obj.sections[1100].x-2,obj.sections[1100].y)
        end

        --[[if show_samplemanager and not fullscreen_open then
          if lupd.update_gfx or lupd.update_samplemanager or resize_display then
            GUI_DrawSampleManager(obj, gui)
          end
          gfx.blit(986,1,0,0,0,obj.sections[1300].w,obj.sections[1300].h,obj.sections[1300].x,obj.sections[1300].y)
        end]]

        if settings_sbdock and show_stripbrowser and not fullscreen_open then
          if lupd.update_gfx or lupd.update_stripbrowser or resize_display then
            GUI_DrawStripBrowser(obj, gui)
          end
          if not settings_sbdock or lupd.update_gfx or lupd.update_surface or lupd.update_stripbrowser or (sb_drag and mouse.context ~= contexts.sb_dragstrip2) --[[or mouse.context == "dragsurface"]] then
            gfx.blit(907,1,0,0,0,obj.sections[1350].w,obj.sections[1350].h,obj.sections[1350].x,obj.sections[1350].y)
          end
          if sb_drag and mouse.context ~= contexts.sb_dragstrip2 then
            gfx.a = sb_drag.alpha
            local w,h = gfx.getimgdim(sb_drag.img)
            gfx.blit(sb_drag.img,sb_drag.scale,0,0,0,sb_drag.w,sb_drag.h,sb_drag.x-sb_drag.xoff,sb_drag.y-sb_drag.yoff)
            gfx.a = 1
          end
        end

        if show_modass and not fullscreen_open then
          if lupd.update_gfx or lupd.update_surface then
            GUI_DrawModAssign(obj, gui)
          end
          --if --[[not settings_moddock or]] lupd.update_gfx then
            gfx.blit(983,1,0,0,0,obj.sections[1125].w,obj.sections[1125].h,obj.sections[1125].x,obj.sections[1125].y)
          --end
        end

        --[[if dragfader then
          local sz = 30
          local xywh = {x = dragfader.x-sz, y = dragfader.y-butt_h/2, w = sz*2, h = butt_h}
          if dragfader.ctl == nil then
            f_Get_SSV(faderselcol)
            gfx.a = 1
          elseif dragfader.ctl == -1 then
            f_Get_SSV('255 0 0')
            gfx.a = 0.3
          else
            f_Get_SSV('0 255 0')
            gfx.a = 0.3
          end
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
          f_Get_SSV(gui.color.black)
          gfx.a = 1
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
          GUI_textC(gui,xywh,'FADER ' ..string.format('%i',fader_select),gui.color.black,-2,1,0)
        elseif dragmod then
          local sz = 30
          local xywh = {x = dragmod.x-sz, y = dragmod.y-butt_h/2, w = sz*2, h = butt_h}
          if dragmod.ctl == nil then
            f_Get_SSV(modselcol)
            gfx.a = 1
          elseif dragmod.ctl == -1 then
            f_Get_SSV('255 0 0')
            gfx.a = 0.3
          else
            f_Get_SSV('0 255 0')
            gfx.a = 0.3
          end
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
          f_Get_SSV(gui.color.black)
          gfx.a = 1
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
          GUI_textC(gui,xywh,'MOD ' ..string.format('%i',mod_select),gui.color.black,-2,1,0)

        elseif lvar.infoclick and lvar.infoclick.active == true then

          local i = lvar.infoclick.src
          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls
          local sz = math.floor(ctls[i].wsc/2)
          local val = ctls[i].info_val
          local xywh = {x = mouse.mx-sz, y = mouse.my-math.floor(butt_h/2), w = sz*2, h = butt_h}

          gfx.a = 0.5
          f_Get_SSV(gui.color.black)
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

          GUI_Str(gui,xywh,val,5,ctls[i].textcolv,-4+ctls[i].textsizev,1)
          gfx.a = 1

        elseif lvar.switchdrag then

          local i = lvar.switchdrag.c
          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls
          local sz = math.floor(ctls[i].wsc/2)
          local val = ctls[i].param_info.paramname
          local xywh = {x = mouse.mx-sz, y = mouse.my-math.floor(butt_h/2), w = sz*2, h = butt_h}

          gfx.a = 0.5
          f_Get_SSV(gui.color.black)
          gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

          GUI_Str(gui,xywh,val,5,ctls[i].textcolv,-4+ctls[i].textsizev,1)
          gfx.a = 1

          if lvar.switchdrag.targetc and lvar.switchdrag.targetc ~= lvar.switchdrag.c then
            local ctl = ctls[lvar.switchdrag.targetc]
            if ctl then
              if lvar.switchdrag.before == true then
                local x = ctl.xsc - surface_offset.x + obj.sections[10].x
                local y = ctl.ysc - surface_offset.y + obj.sections[10].y
                f_Get_SSV(gui.color.green)
                gfx.a = 0.5
                gfx.rect(x,y,ctl.wsc,4,1,1)
              else
                local x = ctl.xsc - surface_offset.x + obj.sections[10].x
                local y = ctl.ysc+ctl.hsc -4 - surface_offset.y + obj.sections[10].y
                f_Get_SSV(gui.color.green)
                gfx.a = 0.5
                gfx.rect(x,y,ctl.wsc,4,1,1)
              end
            end
          end
        end]]

      elseif mode == 1 then
        --Edit

        if submode == 0 then

          --DRAW SUBMODE 0

          if lupd.update_gfx or lupd.update_bg then
            GUI_DrawControlBackG(obj, gui)
            GUI_DrawControls(obj, gui)
          elseif lupd.update_ctls then
            GUI_DrawControls(obj, gui)
          end
          if lupd.update_gfx or lupd.update_sidebar or resize_display then
            --GUI_DrawFXParams(obj, gui)
            GUI_DrawSidebar(obj, gui)
          end

          if show_ctloptions and ctl_select ~= nil and (lupd.update_gfx or lupd.update_ctlopts or resize_display) then
            GUI_DrawCtlOptions(obj, gui)
          end

          gfx.dest = 1
          gfx.a = 1
          gfx.blit(strip_image,lvar.zoom,0,surface_offset.x,
                            surface_offset.y,
                            math.ceil(obj.sections[10].w/lvar.zoom),
                            math.ceil(obj.sections[10].h/lvar.zoom),
                            obj.sections[10].x,
                            obj.sections[10].y)
          if ctl_select ~= nil then
            selrect, selrect_sc = CalcSelRect()
            local rc
            if movefrom_sc == nil or ctlscaling then
              movefrom_sc = table.copy(selrect_sc)
            end
            if dragctl ~= nil then
            
              local x, y = selrect.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x -b_sz*lvar.zoom,
                            selrect.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y-b_sz*lvar.zoom
              local w, h = gfx.getimgdim(1022)
              gfx.a = 0.5
              if dragoff then
                gfx.a = dragoff.alpha or 0.5
              end
              gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)
              rc = gui.color.bryellow1
            end

            if newgrp ~= nil then
              local cx = newgrp.switchid
              local sctl = strips[tracks[track_select].strip][page].controls[cx]
              local x = sctl.x*lvar.zoom+1
              local y = sctl.y*lvar.zoom+1
              local w = sctl.w*lvar.zoom-2
              local h = sctl.ctl_info.cellh*lvar.zoom-2

              gfx.a = 0.5
              f_Get_SSV(gui.color.red)
              gfx.rect(x - surface_offset.x*lvar.zoom + obj.sections[10].x, y - surface_offset.y*lvar.zoom + obj.sections[10].y, w, h, 1, 1)
            end

            --selrect = CalcSelRect()
            if selrect then
              f_Get_SSV(gui.color.blue)

              gfx.a = 0.8
              local ls = 4
              for c = 1, #ctl_select do
                local cx = ctl_select[c].ctl
                local sctl = strips[tracks[track_select].strip][page].controls[cx]
                local x = sctl.xsc*lvar.zoom+4
                local y = sctl.ysc*lvar.zoom+4
                local w = sctl.wsc*lvar.zoom-8
                local h = sctl.hsc*lvar.zoom-8
                x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
                y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
                if cx == lvar.ctlpreview_sel then
                  f_Get_SSV(gui.color.white)
                end

                gfx.line(x,y,x+ls,y,1)
                gfx.line(x,y,x,y+ls,1)

                gfx.line(x+w,y,x+w-ls,y,1)
                gfx.line(x+w,y,x+w,y+ls,1)

                gfx.line(x+w,y+h-ls,x+w,y+h,1)
                gfx.line(x+w,y+h,x+w-ls,y+h,1)

                gfx.line(x,y+h-ls,x,y+h,1)
                gfx.line(x,y+h,x+ls,y+h,1)
                if cx == lvar.ctlpreview_sel then
                  f_Get_SSV(gui.color.blue)
                end

              end

              if gfx3_select then
                for c = 1, #gfx3_select do
                  local cx = gfx3_select[c].ctl
                  local sctl = strips[tracks[track_select].strip][page].graphics[cx]
                  local x = sctl.x*lvar.zoom+4
                  local y = sctl.y*lvar.zoom+4
                  local w = sctl.stretchw*lvar.zoom-8
                  local h = sctl.stretchh*lvar.zoom-8
                  x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
                  y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
                  gfx.line(x,y,x+ls,y,1)
                  gfx.line(x,y,x,y+ls,1)

                  gfx.line(x+w,y,x+w-ls,y,1)
                  gfx.line(x+w,y,x+w,y+ls,1)

                  gfx.line(x+w,y+h-ls,x+w,y+h,1)
                  gfx.line(x+w,y+h,x+w-ls,y+h,1)

                  gfx.line(x,y+h-ls,x,y+h,1)
                  gfx.line(x,y+h,x+ls,y+h,1)

                end
              end

              gfx.a = 1
              f_Get_SSV(gui.color.red)
              gfx.roundrect(math.floor(movefrom_sc.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x),
                            math.floor(movefrom_sc.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y),
                            math.floor(movefrom_sc.w*lvar.zoom), math.floor(movefrom_sc.h*lvar.zoom), 8, 1, 0)

              f_Get_SSV(rc or gui.color.yellow)
              gfx.roundrect(math.floor(selrect_sc.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x),
                            math.floor(selrect_sc.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y),
                            math.floor(selrect_sc.w*lvar.zoom), math.floor(selrect_sc.h*lvar.zoom), 8, 1, 0)

              f_Get_SSV(rc or '50 50 0')
              gfx.roundrect(math.floor(selrect_sc.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x)-1,
                            math.floor(selrect_sc.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y)-1,
                            math.floor(selrect_sc.w*lvar.zoom)+2, math.floor(selrect_sc.h*lvar.zoom)+2, 8, 1, 0)

            end
          end

          gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,0)

          if lasso ~= nil then
            gfx.a = 0.2
            f_Get_SSV(gui.color.blue)
            local l = {l = lasso.l, r = lasso.r, t = lasso.t, b = lasso.b}
            if lasso.r < lasso.l then
              l.l = lasso.r
              l.r = lasso.l
            end
            if lasso.b < lasso.t then
              l.b = lasso.t
              l.t = lasso.b
            end
            gfx.rect(l.l,
                     l.t,
                     l.r-l.l,
                     l.b-l.t, 1, 1)
          end

          if lupd.update_gfx or lupd.update_surface or lasso ~= nil then
            if lockh > 0 or lockw > 0 or surface_size.exceed == true then
              UpdateLEdges()
            end
          end

          if show_ctloptions and ctl_select ~= nil then
            local w,h = gfx.getimgdim(1021)
            gfx.a = 0.5
            gfx.blit(1021,1,0,0,0,w,h,obj.sections[60].x,obj.sections[60].y)
            --GUI_DrawCtlOptions(obj, gui)

            gfx.a = 1
            local w,h = gfx.getimgdim(1011)
            gfx.blit(1011,1,0,0,0,w,h,obj.sections[45].x,obj.sections[45].y)

            if show_cycleoptions then
              GUI_DrawCycleOptions(obj, gui)
            end
          end

          if show_paramlearn and fxmode == 0 then
            GUI_DrawParamLearn(obj,gui)
          end

          if dragparam ~= nil then
            if reass_param == nil then
              local x, y = dragparam.x, dragparam.y
              gfx.a = 0.7
              local iidx,w,h,bc
              if dragparam.type == 'reassplugin' then
                iidx = 998
                w,h = gfx.getimgdim(iidx)
                if w == 0 or h == 0 then
                  w, h = ksel_size.w*2, ksel_size.h*2
                end
                bc = '160 160 160'
                gfx.a=0.6
                f_Get_SSV(gui.color.black)
                gfx.rect(x,y,w,h,1)
                --local xywh = {x=x+w/2,y=y+h/2-butt_h,w=1,h=1}
                local xywh = {x=x+(w/2),y=y+h/2-butt_h*lvar.zoom,w=1,h=1}
                GUI_textC(gui,xywh,'Reassign Plugin',bc,-2 +((lvar.zoom-1)*8))
                xywh.y = xywh.y + butt_h*lvar.zoom
                GUI_textC(gui,xywh,CropFXName(trackfx[trackfx_select].name),bc,-4+((lvar.zoom-1)*8))
              else
                iidx = ctl_files[knob_select].imageidx
                if iidx == nil and ksel_loaded == false then
                  ksel_loaded = true
                  gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
                  iidx = 1023
                elseif iidx == nil then
                  iidx = 1023
                end
                w, _ = gfx.getimgdim(iidx)
                h = ctl_files[knob_select].cellh
                bc = gui.color.yellow
              end
              gfx.blit(iidx,scale_select*lvar.zoom,0,0,p*h,w,--[[ctl_files[knob_select].cellh]] h,
                       x+ (w/2)*lvar.zoom-(w*scale_select/2)*lvar.zoom,
                       y+ (h/2)*lvar.zoom-(h*scale_select/2)*lvar.zoom )
              f_Get_SSV(bc)
              gfx.a = 1
              if dragparam.type ~= 'reassplugin' then
                w = w*lvar.zoom
                h = h*lvar.zoom
              end
              gfx.roundrect(x, y ,w, h, 8, 1, 0)
            else
              local x, y = dragparam.x, dragparam.y
              local iidx,w,h,bc
              if dragparam.type == 'reassplugin' then
                iidx = 998
                w,h = gfx.getimgdim(iidx)
                if w == 0 or h == 0 then
                  w, h = ksel_size.w*2, ksel_size.h*2
                end
                bc = dragparam.bc
                gfx.a=0.6
                f_Get_SSV(gui.color.black)
                gfx.rect(x,y,w,h,1)
                local xywh = {x=x+(w/2),y=y+h/2-butt_h*lvar.zoom,w=1,h=1}
                GUI_textC(gui,xywh,'Reassign Plugin',bc,-2+((lvar.zoom-1)*8))
                xywh.y = xywh.y + butt_h*lvar.zoom
                --DBG(-4+((lvar.zoom-1)*4))
                GUI_textC(gui,xywh,CropFXName(trackfx[trackfx_select].name),bc,-4+((lvar.zoom-1)*8))
              else
                local iidx = ctl_files[knob_select].imageidx
                if iidx == nil and ksel_loaded == false then
                  ksel_loaded = true
                  gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
                  iidx = 1023
                elseif iidx == nil then
                  iidx = 1023
                end
                w, _ = gfx.getimgdim(iidx)
                h = ctl_files[knob_select].cellh
                w, h = w*lvar.zoom, h*lvar.zoom
                bc = gui.color.red
              end
              f_Get_SSV(bc)
              gfx.a = 1
              gfx.roundrect(x, y ,w, h, 8, 1, 0)
            end
          end

          if dragstrip ~= nil then
            local x, y = dragstrip.x, dragstrip.y
            local w, h = gfx.getimgdim(1022)
            gfx.a = 0.5

            if show_striplayout == true then
              if settings_stripautosnap == true and stripgallery_view == 0 then
                local scale = striplayout_data.w / surface_size.w
                local px = striplayout_data.x+obj.sections[10].x
                local py = striplayout_data.y+obj.sections[10].y
                gfx.blit(1022,scale,0,0,0,w,h,px+dragstrip.xx*scale,py+dragstrip.yy*scale)

              elseif stripgallery_view == 1 then
                local scale = striplayout_data.w / surface_size.w
                local ww, hh = gfx.getimgdim(993)
                local px = obj.sections[10].x + (obj.sections[10].w/2 - (w*scale)/2)
                local py = obj.sections[10].y + (obj.sections[10].h/2 + hh/2) + 20

                gfx.blit(1022,scale,0,0,0,w,h,px,py)
              else
                local scale = striplayout_data.w / surface_size.w
                gfx.blit(1022,scale,0,0,0,w,h,dragstrip.xx,dragstrip.yy)
              end
            else
              gfx.blit(1022,1,0,0,0,w,h,x,y)
            end
          end

          if show_actionchooser then
            GUI_DrawActionChooser(obj, gui)
          end

          if show_ctlbrowser then
            GUI_DrawCtlBrowser(obj, gui)
          end

          gfx.dest = 1
          gfx.a = 1
          if show_gaugeedit == true then
            GUI_DrawGaugeEdit(obj, gui)
          end

          if (lvar.ctlpreview_img or (dragparam and dragparam.type ~= 'reassplugin')) and lvar.ctlpreview == true then --and (lupd.update_surface or lupd.update_gfx or lupd.update_sidebar) then

            local fxn, prm
            if fxmode == 0 then
              if trackfx[trackfx_select] then
                fxn = CropFXName(trackfx[trackfx_select].name)
              end
              if fxn then

                if trackfxparams[lvar.ctlpreview_i or -1] then
                  prm = trackfxparams[lvar.ctlpreview_i].paramname
                end
              end
            elseif fxmode == 1 then
              local i = lvar.ctlpreview_i+1
              fxn = lvar.trctltype_table[trctltype_select+1]
              if trctltype_select == 0 then
                if trctls_table[i] then
                  prm = trctls_table[i].name
                end
              elseif trctltype_select == 1 then

                local a = math.floor((i-1)/3)
                local b = (i-1) % 3 +1

                if trsends_table[a] then
                  prm = trsends_table[a][b].name
                end

              elseif trctltype_select == 2 then
                if lvar.special_table[i] then
                  prm = lvar.special_table[i]
                end

              elseif trctltype_select == 3 then
                if lvar.otherctl_table[i] then
                  prm = lvar.otherctl_table[i]
                end
              end
            end
            if prm then
              GUI_DrawCtlPreview(obj, gui, nil, fxn or '', prm or '')
            end
          elseif lvar.ctlpreview_sel and lvar.ctlpreview == true --[[and (lupd.update_surface or lupd.update_gfx or lupd.update_sidebar or lupd.update_ctlopts)]] then
            if ctl_select then
              GUI_DrawCtlPreview(obj, gui, lvar.ctlpreview_sel)
            else
              lvar.ctlpreview_sel = nil
            end
          end

          if stripswitch_droploc then
            local bs = lvar.swdropsz*lvar.zoom
            f_Get_SSV('100 100 0')
            local x = (stripswitch_droploc.x - obj.sections[10].x + surface_offset.x)*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x
            local y = (stripswitch_droploc.y - obj.sections[10].y + surface_offset.y)*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y
            gfx.triangle(x,y,x+bs,y,x,y+bs)
            f_Get_SSV(gui.color.yellow)

            gfx.line(x,y,x,y+bs)
            gfx.line(x,y,x+bs,y)

          elseif lvar.selctl and lvar.selctl.switchsel then

            if switchers[lvar.selctl.switchsel] and switchers[lvar.selctl.switchsel].switchmode == 1 then
              local ctl = strips[tracks[track_select].strip][page].controls[lvar.selctl.ctl]
              local x = ctl.xsc*lvar.zoom + (switchers[lvar.selctl.switchsel].dropx or 0)*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x
              local y = ctl.ysc*lvar.zoom + (switchers[lvar.selctl.switchsel].dropy or ctl.hsc)*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y
              local bs = lvar.swdropsz*lvar.zoom
              f_Get_SSV('128 0 0')
              gfx.triangle(x,y,x+bs,y,x,y+bs)
              f_Get_SSV(gui.color.red)
              gfx.line(x,y,x,y+bs)
              gfx.line(x,y,x+bs,y)
            end
          end

          if lupd.update_gfx or lupd.update_cbox or resize_display then
            GUI_DrawCBox(gui, obj)
          end
          local x,y = gfx.getimgdim(981)
          gfx.blit(981,1,0,0,0,obj.sections[3000].w,obj.sections[3000].h,obj.sections[3000].x,obj.sections[3000].y)

          if show_midiout then
            GUI_DrawMIDIOut(gui, obj)
          end
      
        elseif submode == 1 then

          --DRAW SUBMODE 1

          if lupd.update_gfx or lupd.update_bg then
            GUI_DrawControlBackG(obj, gui)
            GUI_DrawControls(obj, gui)
          elseif lupd.update_ctls then
            GUI_DrawControls(obj, gui)
          end

          if lupd.update_gfx or lupd.update_sidebar or resize_display then
            --GUI_DrawGraphicsChooser(obj, gui)
            GUI_DrawSidebar(obj, gui)
          end

          gfx.dest = 1
          gfx.a = 1
          gfx.blit(strip_image,lvar.zoom,0,surface_offset.x,
                                            surface_offset.y,
                                            math.ceil(obj.sections[10].w/lvar.zoom),
                                            math.ceil(obj.sections[10].h/lvar.zoom),
                                            obj.sections[10].x,
                                            obj.sections[10].y)
          --[[gfx.blit(strip_image,1,0,surface_offset.x,
                            surface_offset.y,
                            obj.sections[10].w,
                            obj.sections[10].h,
                            obj.sections[10].x,
                            obj.sections[10].y)]]

          --gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,butt_h)

          if lupd.update_gfx or lupd.update_surface then
            if lockh > 0 or lockw > 0 or surface_size.exceed == true then
              UpdateLEdges()
            end
          end

          if draggfx ~= nil then
            local x, y = draggfx.x, draggfx.y
            local w, h = gfx.getimgdim(1023)
            gfx.a = 0.5
            gfx.blit(1023,lvar.zoom,0,0,0,w,h,x,y)
          end

          if gfx4_select ~= nil then
            selrect = table.copy(glob_gfxselrect) --CalcGFX4SelRect()
            if selrect then
              local rc
              if draggfx2 ~= nil then
                local x, y = selrect.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x+4*lvar.zoom, selrect.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y+4*lvar.zoom
                local w, h = gfx.getimgdim(1022)
                gfx.a = 1
                gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)
                rc = gui.color.bryellow1
              end

              local lc
              if poslock_select == true then
                lc = gui.color.red
              else
                lc = gui.color.yellow
              end
              gfx.a = 1
              local sx, sy, sw, sh = selrect.x, selrect.y, selrect.w*lvar.zoom, selrect.h*lvar.zoom
              sx = sx*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x
              sy = sy*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y
              --sx = selrect.x -- surface_offset.x + obj.sections[10].x
              --sy = selrect.y -- surface_offset.y + obj.sections[10].y
              f_Get_SSV('50 50 0')
              gfx.roundrect(sx-1, sy-1, sw+2, sh+2, 8, 1, 0)
              
              f_Get_SSV(rc or lc)
              gfx.roundrect(sx, sy, sw, sh, 8, 1, 0)
              --gfx.roundrect(sx+1, sy+1, sw-2, sh-2, 8, 1, 0)
              if show_lbloptions == false and show_gfxoptions == true then
                gfx.circle(sx+sw,sy+sh/2,4,1,1)
                gfx.circle(sx+sw,sy+sh,4,1,1)
                gfx.circle(sx+sw/2,sy+sh,4,1,1)
                gfx.circle(sx,sy,4,1,1)
                gfx.circle(sx+sw,sy,4,1,1)
                gfx.circle(sx+sw/2,sy,4,1,1)
                gfx.circle(sx,sy+sh/2,4,1,1)
                gfx.circle(sx,sy+sh,4,1,1)
                f_Get_SSV('50 50 0')
                gfx.circle(sx+sw,sy+sh/2,5,0,1)
                gfx.circle(sx+sw,sy+sh,5,0,1)
                gfx.circle(sx+sw/2,sy+sh,5,0,1)
                gfx.circle(sx,sy,5,0,1)
                gfx.circle(sx+sw,sy,5,0,1)
                gfx.circle(sx+sw/2,sy,5,0,1)
                gfx.circle(sx,sy+sh/2,5,0,1)
                gfx.circle(sx,sy+sh,5,0,1)
              end
            end

            local strip = tracks[track_select].strip
            f_Get_SSV(gui.color.blue)

            gfx.a = 0.8
            local ls = 4
            for c = 1, #gfx4_select do
              local cx = gfx4_select[c]
              local gfxx = strips[strip][page].graphics[cx]
              local x = gfxx.x*lvar.zoom+4
              local y = gfxx.y*lvar.zoom+4
              local w = gfxx.stretchw*lvar.zoom-8
              local h = gfxx.stretchh*lvar.zoom-8
              x=x-surface_offset.x*lvar.zoom+obj.sections[10].x
              y=y-surface_offset.y*lvar.zoom+obj.sections[10].y
              if cx == lvar.gfxpreview_sel then
                f_Get_SSV(gui.color.white)
              end
              gfx.line(x,y,x+ls,y,1)
              gfx.line(x,y,x,y+ls,1)

              gfx.line(x+w,y,x+w-ls,y,1)
              gfx.line(x+w,y,x+w,y+ls,1)

              gfx.line(x+w,y+h-ls,x+w,y+h,1)
              gfx.line(x+w,y+h,x+w-ls,y+h,1)

              gfx.line(x,y+h-ls,x,y+h,1)
              gfx.line(x,y+h,x+ls,y+h,1)
              if cx == lvar.gfxpreview_sel then
                f_Get_SSV(gui.color.blue)
              end

            end
            gfx.a = 1
          end

          if lasso ~= nil then
            gfx.a = 0.2
            f_Get_SSV(gui.color.blue)
            local l = {l = lasso.l, r = lasso.r, t = lasso.t, b = lasso.b}
            if lasso.r < lasso.l then
              l.l = lasso.r
              l.r = lasso.l
            end
            if lasso.b < lasso.t then
              l.b = lasso.t
              l.t = lasso.b
            end
            gfx.rect(l.l,
                     l.t,
                     l.r-l.l,
                     l.b-l.t, 1, 1)
          end

          gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,0)

          if show_lbloptions and gfx4_select ~= nil then
            GUI_DrawLblOptions(obj, gui)
          end

          if show_gfxoptions and gfx4_select ~= nil then
            GUI_DrawGFXOptions(obj, gui)
          end

          if gfx_select ~= nil then
            local w,h = gfx.getimgdim(1021)
            gfx.a = 0.5
            gfx.blit(1021,1,0,0,0,w,h,obj.sections[60].x,obj.sections[60].y)
          end

          if lvar.gfxpreview_img and lvar.gfxpreview == true then --and (lupd.update_surface or lupd.update_gfx or lupd.update_sidebar) then

            GUI_DrawGFXPreview(obj, gui)

          end

          if lupd.update_gfx or lupd.update_cbox or resize_display then
            GUI_DrawCBox(gui, obj)
          end
          gfx.a = 1
          local x,y = gfx.getimgdim(981)
          gfx.blit(981,1,0,0,0,obj.sections[3000].w,obj.sections[3000].h,obj.sections[3000].x,obj.sections[3000].y)

        elseif submode == 2 then

          if lupd.update_gfx or lupd.update_bg then
            GUI_DrawControlBackG(obj, gui)
            GUI_DrawControls(obj, gui)
          elseif lupd.update_ctls then
            GUI_DrawControls(obj, gui)
          end
          --GUI_DrawStripChooser(obj, gui)
          GUI_DrawSidebar(obj, gui)

          gfx.dest = 1
          gfx.a = 1
          if show_striplayout == false then

            if striplayout_mt then

              GUI_DrawStripLayout()

            else

              gfx.blit(strip_image,lvar.zoom,0,surface_offset.x,
                                surface_offset.y,
                                math.ceil(obj.sections[10].w/lvar.zoom),
                                math.ceil(obj.sections[10].h/lvar.zoom),
                                obj.sections[10].x,
                                obj.sections[10].y)
            end

          elseif show_striplayout == true and (lupd.update_gfx or lupd.update_surface or lupd.update_bg) then

            GUI_DrawStripLayout()

          end

          if lupd.update_gfx or lupd.update_surface and show_striplayout == false then
            if lockh > 0 or lockw > 0 or surface_size.exceed == true then
              UpdateLEdges()
            end
          end

          if dragstrip ~= nil then
            local x, y = dragstrip.x, dragstrip.y
            local w, h = gfx.getimgdim(1022)
            gfx.a = 0.5

            if show_striplayout == true then
              if settings_stripautosnap == true and stripgallery_view == 0 then
                local scale = striplayout_data.w / surface_size.w
                local px = striplayout_data.x+obj.sections[10].x
                local py = striplayout_data.y+obj.sections[10].y
                gfx.blit(1022,scale,0,0,0,w,h,px+dragstrip.xx*scale,py+dragstrip.yy*scale)

              elseif stripgallery_view == 1 then
                local scale = striplayout_data.w / surface_size.w
                local ww, hh = gfx.getimgdim(993)
                local px = obj.sections[10].x + (obj.sections[10].w/2 - (w*scale)/2)
                local py = obj.sections[10].y + (obj.sections[10].h/2 + hh/2) + 20

                gfx.blit(1022,scale,0,0,0,w,h,px,py)
              else
                local scale = striplayout_data.w / surface_size.w
                gfx.blit(1022,scale,0,0,0,w,h,dragstrip.xx,dragstrip.yy)
              end
            else
              gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)
            end
          end

          if ctl_select ~= nil and show_striplayout == false and not striplayout_mt then
            selrect, selrectsc = CalcSelRect()
            if dragctl ~= nil then
              local x, y = selrect.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x -b_sz*lvar.zoom, selrect.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y-b_sz*lvar.zoom
              local w, h = gfx.getimgdim(1022)
              gfx.a = 1

              gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)

            end

            if newgrp ~= nil then
              local cx = newgrp.switchid
              local x = strips[tracks[track_select].strip][page].controls[cx].x+1
              local y = strips[tracks[track_select].strip][page].controls[cx].y+1
              local w = strips[tracks[track_select].strip][page].controls[cx].w-2
              local h = strips[tracks[track_select].strip][page].controls[cx].ctl_info.cellh-2

              gfx.a = 0.5
              f_Get_SSV(gui.color.red)
              gfx.rect(x - surface_offset.x + obj.sections[10].x, y - surface_offset.y + obj.sections[10].y, w, h, 1, 1)
            end

            if selrectsc then
              f_Get_SSV(gui.color.yellow)
              gfx.a = 1
              gfx.roundrect(selrectsc.x*lvar.zoom - surface_offset.x*lvar.zoom +obj.sections[10].x, selrectsc.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                            selrectsc.w*lvar.zoom, selrectsc.h*lvar.zoom, 8, 1, 0)
            end
          end

          gfx.blit(1001,1,0,0,0,obj.sections[43].w,obj.sections[43].h,0,0)

          gfx.a=1

          if ctl_select ~= nil and show_striplayout == false then
            --gfx.dest = 1
            local w,h = gfx.getimgdim(1021)
            gfx.a = 0.5
            gfx.blit(1021,1,0,0,0,w,h,obj.sections[60].x,obj.sections[60].y)
          end
        end

        if show_settings then
          --gfx.dest = -1
          GUI_DrawSettings(gui, obj)
        end
        --[[if surface_size.exceed == true then
          if lupd.update_gfx or lupd.update_surface then
            f_Get_SSV(gui.color.red)
            gfx.rect(obj.sections[10].x,obj.sections[10].y,obj.sections[10].w+1,obj.sections[10].h+1,0)
          end
        end]]
      end

      if lvar.dm_editmode_data then --and (lupd.update_gfx or lupd.update_surface or lupd.update_ctls or lupd.update_trbtns) then
        gfx.dest = 1
        GUI_DrawButton(gui,'SAVE',obj.sections[5020],-1,gui.color.white,true,nil,nil,4)
        GUI_DrawButton(gui,'DISCARD',obj.sections[5021],-1,gui.color.white,true,nil,nil,4)
        GUI_DrawButton(gui,'CENTER',obj.sections[5022],-1,gui.color.white,true,nil,nil,4)
      end

      local ypad = math.floor(tb_butt_h)
      local xywh = {x = obj.sections[43].w-2,
                    y = obj.sections[43].y+ypad,
                    w = 1,
                    h = obj.sections[43].h-ypad}
      f_Get_SSV(gui.color.cbobg2)
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
      f_Get_SSV(gui.color.black)
      gfx.line(obj.sections[43].w-1,0,obj.sections[43].w-1,gfx1.main_h)

      if resize_display or lupd.update_gfx or lupd.update_topbar then
        --[[gfx.setimgdim(999,-1,-1)
        gfx.setimgdim(999,gfx1.main_w-plist_w, tb_butt_h+1)]]
        Img_SetDim(999,gfx1.main_w-plist_w, tb_butt_h+1)
        GUI_DrawTopBar(gui,obj)
      end
      gfx.dest=1
      if hide_topbar == false or settings_showminimaltopbar == true then
        gfx.a = 1
        if topbarheight == 0 then
          if show_eqcontrol ~= true and macro_edit_mode ~= true then
            gfx.blit(1,1,0,plist_w,--surface_offset.x,
                              0,--surface_offset.y,
                              obj.sections[18].w,
                              obj.sections[18].h,
                              obj.sections[18].x+plist_w,
                              obj.sections[18].y)
            gfx.blit(1,1,0,(obj.sections[21].x+plist_w),--surface_offset.x+(obj.sections[21].x+plist_w-obj.sections[10].x),
                              0,--surface_offset.y+(obj.sections[21].y-obj.sections[10].y),
                              obj.sections[21].w,
                              obj.sections[21].h,
                              obj.sections[21].x+plist_w,
                              obj.sections[21].y)
          end
        end
        --local w,h = gfx.getimgdim(999)
        gfx.blit(999,1,0,0,0,gfx1.main_w-plist_w,tb_butt_h+1,plist_w,0)
        gfx.dest = 1
        f_Get_SSV(gui.color.black)
        gfx.line(0,h,gfx1.main_w,h)
      end

      if lupd.update_surfaceedge and (mode ~= 0 or lvar.livemode == 0) then
        UpdateEdges()
      end

      if settings_showbars and (lupd.update_gfx or lupd.update_surface) then
        GUI_DrawBars(gui, obj)
      end

      --if show_settings then
      --  GUI_DrawSettings(gui, obj)
      --end

      --[[if lockw > 0 or lockh > 0 then
        UpdateLEdges()
      end]]

      --[[if show_trackfxorder then

        GUI_DrawTrackFXOrder(gui, obj)

      end]]

      --[[if show_midiout then
        GUI_DrawMIDIOut(gui, obj)
      end]]

      if lbx_midilrnctl then
        GUI_DrawMIDILrn(gui, obj)
      end

      --[[if show_arrowupdn then
        local sk, o = skin.updn, 2000
        if stripgallery_view == 1 or settings_pagescrolldir == 1 then
          sk = skin.lr
          o = 2001
        end
        gfx.blit(sk,1,0,0,moupdn_img*obj.sections[o].h,obj.sections[o].w,obj.sections[o].h,obj.sections[o].x,obj.sections[o].y)
      end]]

    elseif show_xxy and (lupd.update_gfx or lupd.update_xxy or lupd.update_xxypos or lupd.update_surface or lupd.update_snaps or lupd.update_msnaps or resize_snaps or resize_display) then

      gfx.dest = 1
      if lupd.update_gfx or resize_display then
        --gfx.setimgdim(1, -1, -1)
        --gfx.setimgdim(1, gfx1.main_w,gfx1.main_h)
        Img_SetDim(1, gfx1.main_w,gfx1.main_h)
      end

      if resize_display or resize_snaps then
        --gfx.setimgdim(1002,obj.sections[45].w, obj.sections[45].h)
        Img_SetDim(1003,obj.sections[160].w, obj.sections[160].h, true)
        Img_SetDim(1005,obj.sections[180].w, obj.sections[180].h, true)
        Img_SetDim(1006,obj.sections[221].w, obj.sections[221].h, true)
        Img_SetDim(1007,obj.sections[220].w, obj.sections[220].h, true)
      end

      --Edges
      if lupd.update_gfx or lupd.update_xxypos then
        f_Get_SSV(gui.color.black)
        local xywh = {x = obj.sections[220].x,
                      y = 0,
                      w = obj.sections[220].w,
                      h = obj.sections[220].y}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1, 1)
        local xywh = {x = obj.sections[220].x,
                      y = obj.sections[220].y+obj.sections[220].h,
                      w = obj.sections[220].w,
                      h = gfx1.main_h - (obj.sections[220].y+obj.sections[220].h)}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1, 1)
        local xywh = {x = 0,
                      y = obj.sections[220].y,
                      w = obj.sections[220].x,
                      h = obj.sections[220].y+obj.sections[220].h}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1, 1)
        local xywh = {x = obj.sections[220].x+obj.sections[220].w,
                      y = obj.sections[220].y,
                      w = obj.sections[221].x-(obj.sections[220].x+obj.sections[220].w),
                      h = obj.sections[220].y+obj.sections[220].h}
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1, 1)

        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[230].x,
                 obj.sections[230].y,
                 obj.sections[230].w,
                 obj.sections[230].h, 0, 1)
      end

      if lupd.update_gfx or resize_display then
        local xywh = {x = obj.sections[222].x,
                      y = obj.sections[222].y,
                      w = obj.sections[222].w,
                      h = obj.sections[222].h}
        GUI_DrawBar(gui,'EXIT',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
        --GUI_textC(gui,xywh,'EXIT',c,-2)

      end


      if lupd.update_gfx or lupd.update_xxy or lupd.update_surface then
        GUI_DrawXXY(gui,obj)
      end

      if lupd.update_gfx or lupd.update_snaps or lupd.update_surface then
        GUI_DrawXXYSnaps(gui,obj)
      end

      gfx.blit(1006,1,0,0,0,obj.sections[221].w,obj.sections[221].h,obj.sections[221].x,obj.sections[221].y)
      gfx.blit(1007,1,0,0,0,obj.sections[220].w,obj.sections[220].h,obj.sections[220].x,obj.sections[220].y)

      GUI_DrawXXYSSLabels(gui,obj)

      --POS
      local strip = tracks[track_select].strip
      if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
        local x,y = xxy[strip][page][sstype_select].x*obj.sections[220].w + obj.sections[220].x, xxy[strip][page][sstype_select].y*obj.sections[220].h + obj.sections[220].y
        f_Get_SSV(gui.color.yellow)
        gfx.line(x-16,y,x+16,y,1)
        gfx.line(x,y-16,x,y+16,1)
      end

      if dragsnap ~= nil then

        local ppw, pph = gfx.getimgdim(def_xytarget)
        gfx.blit(def_xytarget,1,0, 0, 0, ppw, pph, dragsnap.x-ppw/2, dragsnap.y-pph/2)

      end

      if show_midiout then
        GUI_DrawMIDIOut(gui, obj)
      end

    end

    --[[if mode == 0 and lvar.livemode == 2 and lvar.trbtns_show and lvar.trbtns_meters and not fullscreen_open then

      local x,y,w,h,ww,tint,pkhoff,pkhoff2
      if lvar.trmix_show then
        x = obj.sections[5005].x+obj.sections[5029].x
        y = obj.sections[5024].y+obj.sections[5029].y
        w = lvar.trbtns_size + 10
        h = obj.sections[5029].h
        ww = lvar.trmix_peak_w
        tint = lvar.mmov_tint+0.2
        pkhoff = 8
        pkhoff2 = 13
        pkhoff_tot = pkhoff+pkhoff2
      else
        x = obj.sections[5005].x+obj.sections[5004].w +8
        y = obj.sections[5005].y + 10
        w = obj.sections[5004].w + 10
        h = obj.sections[5005].h - 20
        ww = 2
        tint = lvar.mmov_tint
      end
      local c = lvar.trbtns_pkcolor
      local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
      local cnt = math.min(#dm_trackbtns+1, lvar.trov_maxrows, lvar.dm_maxvistracks+1)
      gfx.a = 1
      gfx.dest = 1
      for tb2 = 1, cnt-1 do
        local tb = tb2 + lvar.trbtns_offs
        if dm_trackbtns[tb] then

          local tr = GetTrack(dm_trackbtns[tb].trn)
          if tr then

            local peak_info_ch1 = reaper.Track_GetPeakInfo(tr, 0)
            local peak_info_ch2 = reaper.Track_GetPeakInfo(tr, 1)
            local peak_info_dB1 = 20*log10(peak_info_ch1)
            local peak_info_dB2 = 20*log10(peak_info_ch2)

            --local pk = 0
            --if peak_info_dB > 0 then
            --  pk = 1
            --end
            local v1 = normalize(-60,0,F_limit(peak_info_dB1,-60,0))
            local v2 = normalize(-60,0,F_limit(peak_info_dB2,-60,0))
            if v1 ~= dm_trackbtns[tb].v1 or v2 ~= dm_trackbtns[tb].v2 then
              --lvar.tb_v1 = v1
              --lvar.tb_v2 = v2
              dm_trackbtns[tb].v1 = v1
              dm_trackbtns[tb].v2 = v2
              --local alpha = 0.2
              if not lvar.trmix_show then
                if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
                  --local hh = math.floor(h-math.max(v1*h,v2*h))
                  gfx.blit(lvar.bgloaded,1,0,x-(lvar.bgoffx or 0)-obj.sections[10].x,y-(lvar.bgoffy or 0)-obj.sections[10].y,ww*2+2,h,x,y)
                else
                  f_Get_SSV(backcol2 or backcol)
                  gfx.rect(x, y, ww*2+2, h, 1)
                  --alpha = 0.2
                end
                f_Get_SSV(gui.color.black)
                gfx.a = tint
                gfx.rect(x, y, ww*2+2, h, 1)
              else

                gfx.mode = -2
                gfx.blit(959,1,0,obj.sections[5029].x,obj.sections[5029].y-pkhoff_tot,ww*2+2,obj.sections[5029].h+pkhoff_tot,x,y-pkhoff_tot)
                gfx.mode = gmode
              end
              gfx.a = 1
              f_Get_SSV(c)
              gfx.rect(x, y+h - math.floor(v1*h), ww, math.floor(v1*h), 1)
              gfx.rect(x+ww+2, y+h - math.floor(v2*h), ww, math.floor(v2*h), 1)
            else
              if lvar.trmix_show then

                gfx.mode = -2
                gfx.blit(959,1,0,obj.sections[5029].x,obj.sections[5029].y-pkhoff_tot,ww*2+2,obj.sections[5029].h+pkhoff_tot,x,y-pkhoff_tot)
                gfx.mode = gmode
              end
              gfx.a = 1
              f_Get_SSV(c)
              gfx.rect(x, y+h - math.floor(v1*h), ww, math.floor(v1*h), 1)
              gfx.rect(x+ww+2, y+h - math.floor(v2*h), ww, math.floor(v2*h), 1)
            end
            if lvar.trmix_show then
              gfx.a = 1

              local pkhold1 = reaper.Track_GetPeakHoldDB(tr, 0, false)
              local pkhold2 = reaper.Track_GetPeakHoldDB(tr, 1, false)
              local c = gui.color.black
              if pkhold1 > 0 then
                c = '255 0 0'
                f_Get_SSV(c)
                gfx.rect(x, y-pkhoff, ww, pkhoff-2, 1)
              end
              if pkhold2 > 0 then
                c = '255 0 0'
                f_Get_SSV(c)
                gfx.rect(x+ww+2, y-pkhoff, ww, pkhoff-2, 1)
              end
              local v = round(math.max(pkhold1*100,pkhold2*100),1)
              if v <= -150 then
                v = '-inf'
              end
              local xywh = {x = x, y = y-pkhoff_tot, w = (ww*2)+2, h = 10}
              GUI_Str(gui,xywh,v,5,'160 160 160',-4 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb)
            end
          end
        end
        x = x + w
      end
    end]]

    --if mode == 0 then
      if lvar.enablegfxshadows and not fullscreen_open and (lupd.update_gfx or lupd.update_sidebar or lupd.update_surface or resize_display) then

        local offs,offs2 = 0,0
        if mode == 0 then
          if lvar.livemode >= 1 and lvar.mixmodedir == 0 and lvar.mmov_show then
            offs = lvar.mmov_vsize + lvar.mmov_pad*2
          elseif lvar.livemode >= 1 and lvar.mixmodedir == 1 and lvar.mmov_show then
            offs2 = lvar.mmov_vsize + lvar.mmov_pad*2
          end
        end
        local shadows = {}

        if lvar.trmix_show and lvar.mmov_show and (lvar.mixmodedir == 1 and (obj.sections[5024].y < obj.sections[10].y+offs2))--[[ or
                                                  (lvar.mixmodedir == 0 and (obj.sections[5024].y < obj.sections[10].y+lvar.shadowmax)))]] then
        else

        --if lvar.enablegfxshadows then
          local shad_w, shad_h = gfx.getimgdim(skin.shadow)

          gfx.a = lvar.shadow_alpha
          local edge = 50
          local toff
          if lvar.mixmodedir == 0 then
            toff = obj.sections[10].h
          else
            toff = obj.sections[10].h-offs2
          end
          local nedge_h = math.min(lvar.shadow_offsx,toff)
          local nedge_w = lvar.shadow_offsx

          shadows[1] = {x = obj.sections[10].x+offs, y = obj.sections[10].y+offs2, w = obj.sections[10].w-offs, h = nedge_h,
                        srcx = edge*2, srcy = shad_h - edge*1.5 + (lvar.shadow_feather*1.5), srcw = edge, srch = edge}

          local offs,offs2, offs3 = 0,0,0
          if mode == 0 then
            if lvar.livemode >= 1 and lvar.mixmodedir == 0 and lvar.mmov_show then
              offs = lvar.mmov_vsize + lvar.mmov_pad*2
            elseif lvar.livemode >= 1 and lvar.mixmodedir == 1 and lvar.mmov_show then
              offs3 = lvar.mmov_vsize + lvar.mmov_pad*2
            end
            if lvar.livemode == 2 and lvar.trbtns_show then
              offs2 = obj.sections[4999].h
            end
          end

          shadows[2] = {x = obj.sections[10].x+offs, y = obj.sections[10].y+offs3, w = nedge_w, h = obj.sections[10].h-offs3, --offs2,
                        srcx = shad_w - edge*1.5 + (lvar.shadow_feather*1.5), srcy = edge*2, srcw = edge, srch = edge}
        end

        lvar.shadows = shadows
        if #shadows > 0 then
          gfx.a = lvar.shadow_alpha
          for i = 1, #shadows do
            gfx.blit(skin.shadow,1,0, shadows[i].srcx, shadows[i].srcy, shadows[i].srcw, shadows[i].srch,
                     shadows[i].x, shadows[i].y, shadows[i].w, shadows[i].h)
          end
        end
        lvar.shadowbits = nil

      elseif lvar.enablegfxshadows and not fullscreen_open and lupd.update_ctls and lvar.shadowbits then
        local shadows = lvar.shadowbits
        if #shadows > 0 then

          gfx.a = lvar.shadow_alpha
          for i = 1, #shadows do
            gfx.blit(skin.shadow,1,0, shadows[i].srcx, shadows[i].srcy, shadows[i].srcw, shadows[i].srch,
                     shadows[i].x, shadows[i].y, shadows[i].w, shadows[i].h)
          end
        end
        lvar.shadowbits = nil
      end
    --end

    --[[if show_dd == true then
      if lupd.update_gfx == true or lupd.update_dd == true or resize_display == true then
        GUI_DrawDropdown(gui, obj)
      end
      --gfx.blit(1,1,0,ddlist.x,ddlist.y,ddlist.w+6,ddlist.h+6,ddlist.x,ddlist.y)
      --if lupd.update_surface or lupd.update_gfx or lupd.update_dd then
        gfx.blit(996,1,0,0,0,ddlist.w+2,ddlist.h+2,ddlist.x,ddlist.y)
      --end
    end

    if MS_Open > 0 then
      GUI_DrawMsg(gui, obj)

    elseif EB_Open > 0 then
      editbox_draw(gui, editbox)

    end

    if show_midioutind and midimsg == true then
      f_Get_SSV(gui.color.red)
      gfx.rect(5,0,5,5,1,1)
      --f_Get_SSV(gui.color.black)
      --gfx.rect(6,6,8,8,0,1)
    end
    if touch_trigger == true then
      f_Get_SSV('0 0 255')
      gfx.rect(0,0,5,5,1)
    end
    if touch_timer then
      f_Get_SSV('255 255 255')
      gfx.rect(0,0,5,5,1)
    end]]

    --if drawn_mm == 0 then
    --  GUI_DrawMixModePopUp(obj, gui)
    --end

    --[[progg = (progg or 0) + 0.01
    if progg > 1 then progg = 0 end
    Progress('Progress',progg)]]

    --end

    local alp, dst
    if not lvar.surface_fade then
      gfx.dest = -1
      gfx.a = 1
      gfx.blit(1, 1, 0,
        0,0, gfx1.main_w,gfx1.main_h,
        0,0, gfx1.main_w,gfx1.main_h, 0,0)
    elseif lvar.surface_fade and lvar.surface_fade.start >= 1 then
      if lvar.surface_fade.start == 1 then
        local rt = reaper.time_precise()
        lvar.surface_fade.start = 2
        lvar.surface_fade.st = rt
        lvar.surface_fade.et = rt+lvar.surfacefadetime
      end
      gfx.dest = -1
      gfx.a = 1
      alp = math.min(1,(reaper.time_precise()-lvar.surface_fade.st)/(lvar.surface_fade.et - lvar.surface_fade.st))
      if alp < 1 then
        local o10 = obj.sections[10]
        local om = gfx.mode
        gfx.mode = 3
        gfx.blit(826, 1, 0,
          0,0, gfx1.main_w,gfx1.main_h,
          0,0, gfx1.main_w,gfx1.main_h, 0,0)
        gfx.a = alp
        gfx.mode = om
        gfx.blit(1, 1, 0,
          --0,0, gfx1.main_w,gfx1.main_h,
          --0,0, gfx1.main_w,gfx1.main_h, 0,0)
          o10.x, o10.y, o10.w, o10.h,
          o10.x, o10.y, o10.w, o10.h, 0,0)
        gfx.a = 1
      else
        gfx.blit(1, 1, 0,
          0,0, gfx1.main_w,gfx1.main_h,
          0,0, gfx1.main_w,gfx1.main_h, 0,0)
      end
      if alp == 1 then
        lvar.surface_fade = nil
        alp = nil
      end
    end
    
    if not fullscreen_open and mode == 0 then

      if lvar.livemode == 2 and lvar.trbtns_show and lvar.trbtns_meters and not lvar.analyzer.active and not lvar.mixerscroll_time then

        local x,y,w,h,ww,tint,pkhoff,pkhoff2
        if lvar.trmix_show then
          x = obj.sections[5005].x+obj.sections[5029].x
          y = obj.sections[5024].y+obj.sections[5029].y
          w = lvar.trbtns_size + 10
          h = obj.sections[5029].h
          ww = lvar.trmix_peak_w
          tint = lvar.mmov_tint+0.2
          pkhoff = 8
          pkhoff2 = 13
          pkhoff_tot = pkhoff+pkhoff2
        else
          x = obj.sections[5005].x-2 --+obj.sections[5004].w +8
          y = obj.sections[5005].y + 10
          w = obj.sections[5004].w + 10
          h = obj.sections[5005].h - 20
          ww = 2
          tint = lvar.mmov_tint
        end
        local c = lvar.trbtns_pkcolor
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        local cnt = math.min(--[[#dm_trackbtns+1,]] lvar.trov_maxrows, lvar.dm_maxvistracks+1)
        gfx.a = 1
        gfx.dest = -1
        for tb2 = 1, cnt-1 do
          local tb = tb2 + lvar.trbtns_offs
          if dm_trackbtns and dm_trackbtns[tb] then

            local tr = GetTrack(dm_trackbtns[tb].trn)
            if tr then

              local peak_info_ch1 = reaper.Track_GetPeakInfo(tr, 0)
              local peak_info_ch2 = reaper.Track_GetPeakInfo(tr, 1)
              local peak_info_dB1 = 20*log10(peak_info_ch1)
              local peak_info_dB2 = 20*log10(peak_info_ch2)

              local v1 = normalize(-60,0,F_limit(peak_info_dB1,-60,0))
              local v2 = normalize(-60,0,F_limit(peak_info_dB2,-60,0))
              if v1 ~= dm_trackbtns[tb].v1 or v2 ~= dm_trackbtns[tb].v2 then
                dm_trackbtns[tb].v1 = v1
                dm_trackbtns[tb].v2 = v2
                if not lvar.trmix_show then

                else


                  local rt = reaper.time_precise()
                  if v1 >= (dm_trackbtns[tb].ph1 or 0) or rt > (dm_trackbtns[tb].ph1_t or 0) then
                    dm_trackbtns[tb].ph1 = v1
                    dm_trackbtns[tb].ph1_t = rt+lvar.phtime
                  end
                  if v2 >= (dm_trackbtns[tb].ph2 or 0) or rt > (dm_trackbtns[tb].ph2_t or 0) then
                    dm_trackbtns[tb].ph2 = v2
                    dm_trackbtns[tb].ph2_t = rt+lvar.phtime
                  end
                end
                gfx.a = 1
                f_Get_SSV(c)
                gfx.rect(x, y+h - math.floor(v1*h), ww, math.floor(v1*h), 1)
                gfx.rect(x+ww+2, y+h - math.floor(v2*h), ww, math.floor(v2*h), 1)
              else
                if lvar.trmix_show then


                  local rt = reaper.time_precise()
                  if v1 >= (dm_trackbtns[tb].ph1 or 0) or rt > (dm_trackbtns[tb].ph1_t or 0) then
                    dm_trackbtns[tb].ph1 = v1
                    dm_trackbtns[tb].ph1_t = rt+lvar.phtime
                  end
                  if v2 >= (dm_trackbtns[tb].ph2 or 0) or rt > (dm_trackbtns[tb].ph2_t or 0) then
                    dm_trackbtns[tb].ph2 = v2
                    dm_trackbtns[tb].ph2_t = rt+lvar.phtime
                  end
                end
                gfx.a = 1
                f_Get_SSV(c)
                gfx.rect(x, y+h - math.floor(v1*h), ww, math.floor(v1*h), 1)
                gfx.rect(x+ww+2, y+h - math.floor(v2*h), ww, math.floor(v2*h), 1)
              end
              if lvar.trmix_show then
                gfx.a = 1
                f_Get_SSV(c)
                if (dm_trackbtns[tb].ph1 or 0) > 0 then
                  local y1 = y+h - math.floor(dm_trackbtns[tb].ph1*h)
                  gfx.line(x, y1, x+ww-1, y1)
                end
                if (dm_trackbtns[tb].ph2 or 0) > 0 then
                  local y2 = y+h - math.floor(dm_trackbtns[tb].ph2*h)
                  gfx.line(x+ww+2, y2, x+1+ww*2, y2)
                end
                local pkhold1 = reaper.Track_GetPeakHoldDB(tr, 0, false)
                local pkhold2 = reaper.Track_GetPeakHoldDB(tr, 1, false)
                local c = gui.color.black
                if pkhold1 > 0 then
                  c = '255 0 0'
                  f_Get_SSV(c)
                  gfx.rect(x, y-pkhoff, ww, pkhoff-2, 1)
                end
                if pkhold2 > 0 then
                  c = '255 0 0'
                  f_Get_SSV(c)
                  gfx.rect(x+ww+2, y-pkhoff, ww, pkhoff-2, 1)
                end
                local v = round(math.max(pkhold1*100,pkhold2*100),1)
                if v <= -150 then
                  v = '-inf'
                end
                local xywh = {x = x, y = y-pkhoff_tot, w = (ww*2)+2, h = 10}
                GUI_Str(gui,xywh,v,5,'160 160 160',-4 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb)
              end
            end
          end
          x = x + w
        end
      end

      if show_bitmap == false then
        if lvar.blittbl_cnt > 1 then
          gfx.dest = -1
          gfx.a = alp or 1
          local active
          for b = 1, lvar.blittbl_cnt-1 do
            local bt = blittbl[b]
            gfx.a = alp or bt[0] or 1
            gfx.blit(bt[1],bt[2],bt[3],bt[4],bt[5],bt[6],bt[7],
                     bt[8],bt[9])
            if lvar.active_switcher and bt[12] and lvar.active_switcher.switchid == bt[12] then
              active = b
            end
          end
          if active then
            f_Get_SSV('255 255 255')
            local x,y,w,h = blittbl[active][8],blittbl[active][9],blittbl[active][10],blittbl[active][11]
            if h > 0 then
              --gfx.a = inOutSine(((reaper.time_precise()*10) % 10) /5)*0.2
              --gfx.a=0.04
              gfx.a = 0.6
              --gfx.rect(x,y,w,h,0)
              w=w*lvar.zoom
              h=h*lvar.zoom
              local sz = 40*lvar.zoom
              gfx.line(x,y,x+sz,y)
              gfx.line(x,y,x,math.min(y+sz,y+h))
  
              gfx.line(x+w,y,x+w-sz,y)
              gfx.line(x+w,y,x+w,math.min(y+sz,y+h))
  
              gfx.line(x,y+h,x+sz,y+h)
              gfx.line(x,y+h,x,math.max(y+h-sz,y))
              
              gfx.line(x+w,y+h,x+w-sz,y+h)
              gfx.line(x+w,y+h,x+w,math.max(y+h-sz,y))
            end
          end
          gfx.a = 1
        end
      end

      if insertstrip and lvar.showpop and lvar.popout_autoarrange and CheckOver10() then
        local istrip = insertstrip
        local pop = istrip.pop
        if pop then
          local t_swid = istrip.target
          local swdata = lvar.stripdim.swdata
          if swdata and t_swid and swdata[t_swid] then
            local rect10 = obj.sections[10]
            local o10y = rect10.y
            local o10b = rect10.y + rect10.h - 1
            local o10x = rect10.x + 1
            local o10r = rect10.x + rect10.w
            if lvar.mmov_show then
              if lvar.mixmodedir == 0 then
                o10x = o10x + (lvar.mmov_vsize + lvar.mmov_pad*2)
              else
                o10y = o10y + (lvar.mmov_vsize + lvar.mmov_pad*2)
              end
            end
            
            local xoff, yoff = lvar.pop_xoff or 0,lvar.pop_yoff
            local sh = swdata[t_swid].sb - swdata[t_swid].st
            local gap = 0 --lvar.mmgap
            if lvar.popout_autoarrange_hideswitchers == true then
              sh = 0
              gap = -lvar.mmgap
            end
            local x = rect10.x + pop.x + xoff
            local y = rect10.y + pop.y +(sh+gap)*lvar.zoom + yoff 
            local w = (swdata[t_swid].r - swdata[t_swid].l)*lvar.zoom
            local h = (swdata[t_swid].stripb - swdata[t_swid].stript)*lvar.zoom
          
            x, y, w, h = CropToRect(x,y,w,h,o10x,o10y,o10r,o10b)
            
            local ident = 2
            local midy = y+lvar.mmgap*lvar.zoom + h/2
          
            f_Get_SSV(gui.color.blue)
            if not mouse.shift and not mouse.alt then
              local barw = math.min(math.floor(w/2),40)
              local sz = barw/2
              if istrip.before == true then
                gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,1)
                f_Get_SSV('0 0 0')
                gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,0)
                gfx.triangle(x+ident,midy,x+barw-ident*2,midy-sz,x+barw-ident*2,midy+sz)
              else
                gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,1)
                f_Get_SSV('0 0 0')
                gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,0)
                gfx.triangle(x+w-ident,midy,x+w-barw+ident*2,midy-sz,x+w-barw+ident*2,midy+sz)
              end
            end
            gfx.a = 1
            if mouse.shift or mouse.alt then
              if mouse.alt then
                f_Get_SSV(gui.color.green)
                GUI_Str(gui,{x=x+4,y=y+lvar.mmgap*lvar.zoom,w=40,h=20},'LINK',5,gui.color.green,2,1,gui.color.black,nil,nil)
              else
                GUI_Str(gui,{x=x+4,y=y+lvar.mmgap*lvar.zoom,w=60,h=20},'REPLACE',4,gui.color.yellow,2,1,gui.color.black,nil,nil)
              end
              gfx.rect(x,y+lvar.mmgap*lvar.zoom,w,h--[[+lvar.mmgap*lvar.zoom]],0)
            end
          end
        end
      end

      if lvar.dragswitcher and lvar.showpop == true and lvar.popout_autoarrange then
        
        local t_swid = lvar.dragswitcher.target
        local s_swid = lvar.dragswitcher.selected
        local swdata = lvar.stripdim.swdata
        local strip = tracks[track_select].strip
        local pop = lvar.dragswitcher.pop
        
        if swdata and t_swid and t_swid ~= s_swid and swdata[t_swid] then
          --DBG(switchers[s_swid].extendpos..'  '..switchers[t_swid].extendpos)
          local rect10 = obj.sections[10]
          local o10y = rect10.y
          local o10b = rect10.y + rect10.h - 1
          local o10x = rect10.x + 1
          local o10r = rect10.x + rect10.w
          if lvar.mmov_show then
            if lvar.mixmodedir == 0 then
              o10x = o10x + (lvar.mmov_vsize + lvar.mmov_pad*2)
            else
              o10y = o10y + (lvar.mmov_vsize + lvar.mmov_pad*2)
            end
          end
          
          local xoff, yoff = lvar.pop_xoff or 0,lvar.pop_yoff
          local sh = swdata[t_swid].sb - swdata[t_swid].st
          local gap = 0 --lvar.mmgap
          if lvar.popout_autoarrange_hideswitchers == true then
            sh = 0
            gap = -lvar.mmgap
          end
          local x = rect10.x + pop.x + xoff
          local y = rect10.y + pop.y +(sh+gap)*lvar.zoom + yoff 
          local w = (swdata[t_swid].r - swdata[t_swid].l)*lvar.zoom
          local h = (swdata[t_swid].stripb - swdata[t_swid].stript)*lvar.zoom
        
          x, y, w, h = CropToRect(x,y,w,h,o10x,o10y,o10r,o10b)
          
          local ident = 2
          local midy = y+lvar.mmgap*lvar.zoom + h/2
        
          f_Get_SSV(gui.color.blue)
          --if not mouse.shift and not mouse.alt then
            local barw = math.min(math.floor(w/2),40)
            local sz = barw/2
            if lvar.dragswitcher.before == true then
              gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,1)
              f_Get_SSV('0 0 0')
              gfx.rect(x,y+lvar.mmgap*lvar.zoom,barw,h,0)
              gfx.triangle(x+ident,midy,x+barw-ident*2,midy-sz,x+barw-ident*2,midy+sz)
            else
              gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,1)
              f_Get_SSV('0 0 0')
              gfx.rect(x+w-barw,y+lvar.mmgap*lvar.zoom,barw,h,0)
              gfx.triangle(x+w-ident,midy,x+w-barw+ident*2,midy-sz,x+w-barw+ident*2,midy+sz)
            end
          --end
        end
        
        local a = 0.9
        if t_swid and t_swid ~= s_swid then
          a = 0.5
        --else
        --  gfx.a = 0.9
        end
        local swdata = lvar.stripdim.swdata[s_swid]
        local gpage = swdata.gfxpage or 0
        --local swdata = lvar.stripdim.swdata[s_swid]
        local sh = swdata.sb-swdata.st
        local sw = swdata.sr-swdata.sl
        local xw = math.floor(-sw/2)
        if swdata.stripl then
          local gap = 0
          if lvar.livemode >= 1 then
            --[[if lvar.mixmodealign == 0 or lvar.mixmodedir == 1 then
              xw = math.floor((swdata.stripr-swdata.stripl)/2 - sw/2)*lvar.zoom
            else
              xw = 0
            end]]
            gap = lvar.mmgap
          else
            xw = 0
          end
          gfx.a = 1--a

          --crop to obj10
          local mmx = mouse.mx-lvar.dragswitcher.offx
          local mmy = mouse.my-lvar.dragswitcher.offy
          local yoff = 0
          if not lvar.popout_autoarrange_hideswitchers then
            yoff = yoff +(sh+gap)*lvar.zoom
          end

          gfx.dest = -1
          mmx = mouse.mx-lvar.dragswitcher.offx
          mmy = mouse.my-lvar.dragswitcher.offy+yoff
          gfx.blit(strip_image+gpage,lvar.zoom,0,
                   swdata.stripl--[[-cutw/lvar.zoom]],
                   swdata.stript--[[-cuth2/lvar.zoom]],
                   math.max(swdata.stripr-swdata.stripl--[[+cutw/lvar.zoom]],0),
                   math.max(swdata.stripb-swdata.stript--[[+cuth/lvar.zoom+cuth2/lvar.zoom]],0),
                   mmx, mmy)
        end
      end

      if lvar.sk2overlay_active == 1 and lvar.sk2overlay_hud > 0 and lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp] then
        local ctlfxidx
        if lvar.stripdim then
          ctlfxidx = lvar.stripdim.ctlfxidx
        end
        if ctlfxidx then
          local strip = tracks[track_select].strip
          local o10 = obj.sections[10]
          local sz = 4
          gfx.a = (alp or 1)--*0.5
          for a, b in pairs(lvar.sk2overlay.assign[lvar.sk2overlay_globalassgrp]) do
            if b then
              local c = ctlfxidx[b.fxguid..'|'..b.fxparam]
              if c then
                local x,y,w,h = GetControlLoc_Screen(strip,page,c)
                if x and y and w and h then
                  f_Get_SSV(tab_xtouch_colors[b.sscolor or 7].c)
                  local mmov, mmovh = 0, 0
                  if lvar.livemode == 2 then
                    if lvar.mmov_show then
                      if lvar.mixmodedir == 1 then
                        mmov = lvar.mmov_vsize + 2*lvar.mmov_pad
                      else
                        mmovh = lvar.mmov_vsize + 2*lvar.mmov_pad
                      end
                    end
                  end
                  x, y, w, h = CropToRect(x-sz,y-sz,w+sz*2,h+sz*2,o10.x+mmovh,o10.y+mmov,o10.x+o10.w,o10.y+o10.h)
                  if lvar.sk2overlay_hudt >= 1 then
                    gfx.roundrect(x,y-2,w,h+2,4,1)
                  end
                  if lvar.sk2overlay_hudt <= 1 then
                    local f = 1
                    local cc = tab_xtouch_colors[b.sscolor or 7].tc
                    local xywh = {x = x, y = y-14, w = w+1, h = 16}
                    xywh.y = F_limit(xywh.y,o10.y+mmov-2,o10.y+o10.h-16)
                    if lvar.sk2overlay_hudt == 0 then
                      f = 0
                      cc = tab_xtouch_colors[b.sscolor or 7].c
                      gfx.a = (alp or 1)*0.4
                      f_Get_SSV('0 0 0')
                      gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1)
                      f_Get_SSV(tab_xtouch_colors[b.sscolor or 7].c)
                      gfx.a = (alp or 1)
                    end
                    gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,f)
                    GUI_Str(gui,xywh,lvar.sk2overlay.slot[a].name,5,cc or gui.color.black,-4,1)
                  end
                end
              end
            end
          end
        end
      end

      if settings_ssdock ~= true and show_snapshots and macro_lrn_mode ~= true then

        gfx.dest = -1
        gfx.blit(1003,1,0,0,0,obj.sections[160].w,obj.sections[160].h,obj.sections[160].x,obj.sections[160].y)

        if dragparam ~= nil then
          local x, y = dragparam.x, dragparam.y
          gfx.a = dragparam.alpha or 0.7
          local iidx = ctl_files[knob_select].imageidx
          if iidx == nil and ksel_loaded == false then
            ksel_loaded = true
            gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
            iidx = 1023
          elseif iidx == nil then
            iidx = 1023
          end
          local w, _ = gfx.getimgdim(iidx)
          local h = ctl_files[knob_select].cellh
          dragparam.iw, dragparam.ih = w, h
          gfx.blit(iidx,scale_select*lvar.zoom,0,0,p*h,w,ctl_files[knob_select].cellh,x,y)
          if dragparam.alpha and dragparam.alpha < 1 then
            f_Get_SSV(gui.color.red)
          else
            f_Get_SSV(gui.color.yellow)
          end
          gfx.a = 1
          gfx.roundrect(x, y ,w*lvar.zoom, h*lvar.zoom, 8, 1, 0)
        end
      end

      if settings_moddock ~= true and show_lfoedit then
        if lupd.update_gfx or lupd.update_lfoedit or resize_display then
          GUI_DrawLFOEdit(obj, gui)
        elseif lupd.update_lfoeditbar then
          GUI_DrawLFOBar(obj, gui)
        end
        if lupd.update_lfopos then
          GUI_DrawLFOPos(obj, gui)
        end
        gfx.dest = -1
        gfx.blit(992,1,0,0,0,obj.sections[1100].w,obj.sections[1100].h,obj.sections[1100].x-2,obj.sections[1100].y)
      end

      if settings_showmorphpop then
        if #morph_data > 0 then
          gfx.dest = -1
          GUI_DrawMorph(obj, gui)
        end
      end

      if show_fsnapshots or show_xysnapshots then
        gfx.dest = -1
        gfx.blit(1005,1,0,0,0,obj.sections[180].w,obj.sections[180].h,obj.sections[180].x,obj.sections[180].y)
      end

      if show_mutate then
        if lupd.update_gfx or lupd.update_mutate then
          GUI_DrawMutate(obj, gui)
        end
        gfx.dest = -1
        gfx.blit(989,1,0,0,0,obj.sections[1120].w,obj.sections[1120].h,obj.sections[1120].x,obj.sections[1120].y)
      end

      if show_randomopts then
        if lupd.update_gfx or lupd.update_randomopts then
          GUI_DrawRandomOpts(obj, gui)
        end
        gfx.dest = -1
        gfx.blit(988,1,0,0,0,obj.sections[1130].w,obj.sections[1130].h,obj.sections[1130].x,obj.sections[1130].y)
      end

      if show_samplemanager and not fullscreen_open then
        if lupd.update_gfx or lupd.update_samplemanager or resize_display then
          GUI_DrawSampleManager(obj, gui)
        end
        gfx.dest = -1
        gfx.blit(986,1,0,0,0,obj.sections[1300].w,obj.sections[1300].h,obj.sections[1300].x,obj.sections[1300].y)
      end

      if not settings_sbdock and show_stripbrowser then
        if lupd.update_gfx or lupd.update_stripbrowser or resize_display then
          GUI_DrawStripBrowser(obj, gui)
        end
        --if lupd.update_gfx or lupd.update_surface or lupd.update_stripbrowser or (sb_drag and mouse.context ~= contexts.sb_dragstrip2) then
          gfx.dest = -1
          gfx.blit(907,1,0,0,0,obj.sections[1350].w,obj.sections[1350].h,obj.sections[1350].x,obj.sections[1350].y)
        --end
        if sb_drag and mouse.context ~= contexts.sb_dragstrip2 then
          gfx.a = sb_drag.alpha
          local w,h = gfx.getimgdim(sb_drag.img)
          gfx.dest = -1
          gfx.blit(sb_drag.img,sb_drag.scale,0,0,0,sb_drag.w,sb_drag.h,sb_drag.x-sb_drag.xoff,sb_drag.y-sb_drag.yoff)
          gfx.a = 1
        end
      end

      if show_midiout then
        GUI_DrawMIDIOut(gui, obj)
      end
      
      if insertstrip and CheckOver10() then
        gfx.dest = -1
        local istrip = insertstrip
        local x, y = istrip.x, istrip.y+math.floor(istrip.dy/settings_gridsize)*settings_gridsize
        local w, h = gfx.getimgdim(1022)
        if lvar.livemode >= 1 then
          gfx.a = (istrip.alpha or 0.8) * 0.7
          gfx.blit(1022,lvar.zoom,0,0,0,w,h,x-istrip.xoff,y)
          gfx.a = 1
          f_Get_SSV(gui.color.yellow)
          gfx.rect(x-istrip.xoff,y,w*lvar.zoom,h*lvar.zoom,0)
        else
          gfx.a = (istrip.alpha or 0.8)
          gfx.blit(1022,lvar.zoom,0,0,0,w,h,x,y)
        end
      elseif dragfader then
        local sz = 30
        local xywh = {x = dragfader.x-sz, y = dragfader.y-butt_h/2, w = sz*2, h = butt_h}
        if dragfader.ctl == nil then
          f_Get_SSV(faderselcol)
          gfx.a = 1
        elseif dragfader.ctl == -1 then
          f_Get_SSV('255 0 0')
          gfx.a = 0.3
        else
          f_Get_SSV('0 255 0')
          gfx.a = 0.3
        end
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
        f_Get_SSV(gui.color.black)
        gfx.a = 1
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
        GUI_textC(gui,xywh,'FADER ' ..string.format('%i',fader_select),gui.color.black,-2,1,0)
      elseif dragmod then
        local sz = 30
        local xywh = {x = dragmod.x-sz, y = dragmod.y-butt_h/2, w = sz*2, h = butt_h}
        if dragmod.ctl == nil then
          f_Get_SSV(modselcol)
          gfx.a = 1
        elseif dragmod.ctl == -1 then
          f_Get_SSV('255 0 0')
          gfx.a = 0.3
        else
          f_Get_SSV('0 255 0')
          gfx.a = 0.3
        end
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
        f_Get_SSV(gui.color.black)
        gfx.a = 1
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,0,1)
        GUI_textC(gui,xywh,'MOD ' ..string.format('%i',mod_select),gui.color.black,-2,1,0)
      elseif lvar.infoclick and lvar.infoclick.active == true then
        gfx.dest = -1
        local i = lvar.infoclick.src
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local sz = math.floor(ctls[i].wsc/2)
        local val = ctls[i].info_val
        local xywh = {x = mouse.mx-sz, y = mouse.my-math.floor(butt_h/2), w = sz*2, h = butt_h}

        gfx.a = 0.5
        f_Get_SSV(gui.color.black)
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

        GUI_Str(gui,xywh,val,5,ctls[i].textcolv,-4+ctls[i].textsizev,1)
        gfx.a = 1
      elseif lvar.switchdrag then

        local i = lvar.switchdrag.c
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local sz = math.floor(ctls[i].wsc/2)
        local val = ctls[i].param_info.paramname
        local xywh = {x = mouse.mx-sz, y = mouse.my-math.floor(butt_h/2), w = sz*2, h = butt_h}

        gfx.a = 0.5
        f_Get_SSV(gui.color.black)
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)

        GUI_Str(gui,xywh,val,5,ctls[i].textcolv,-4+ctls[i].textsizev,1)
        gfx.a = 1

        if lvar.switchdrag.targetc and lvar.switchdrag.targetc ~= lvar.switchdrag.c then
          local ctl = ctls[lvar.switchdrag.targetc]
          if ctl then
            if lvar.switchdrag.before == true then
              local x = ctl.xsc - surface_offset.x + obj.sections[10].x
              local y = ctl.ysc - surface_offset.y + obj.sections[10].y
              f_Get_SSV(gui.color.green)
              gfx.a = 0.5
              gfx.rect(x,y,ctl.wsc,4,1,1)
            else
              local x = ctl.xsc - surface_offset.x + obj.sections[10].x
              local y = ctl.ysc+ctl.hsc -4 - surface_offset.y + obj.sections[10].y
              f_Get_SSV(gui.color.green)
              gfx.a = 0.5
              gfx.rect(x,y,ctl.wsc,4,1,1)
            end
          end
        end

      elseif lvar.trmix_snddrag then
        gfx.dest = -1
        local sz = 50
        local xywh = {x = mouse.mx-sz, y = mouse.my-math.floor(butt_h/2), w = sz*2, h = butt_h}

        gfx.a = 0.5
        f_Get_SSV(gui.color.black)
        gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
        local c = gui.color.white
        local t = 'ASSIGN SEND'
        if lvar.trmix_sndpnl_show == 2 then
          t = 'ASSIGN RECEIVE'
        end
        if lvar.trmix_snddrag.target then
          c = '0 255 0'
          t = lvar.trmix_snddrag.tgtname
        end

        GUI_Str(gui,xywh,t,5,c,-4,1)
        gfx.a = 1

      elseif lvar.sk2drag then
        gfx.dest = -1
        local sz = lvar.sk2drag.sz
        local xywh = {x = mouse.mx-sz, y = mouse.my-sz*2+20, w = sz*2, h = sz*2}
        local wwdata = lvar.sk2drag.wwdata
        local th = lvar.sk2drag.th
        
        gfx.a = 0.5
        f_Get_SSV(gui.color.black)
        --gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1,1)
        local c = gui.color.white
        local t = lvar.sk2drag.name
        --[[if lvar.trmix_snddrag.target then
          c = '0 255 0'
          t = lvar.trmix_snddrag.tgtname
        end]]
        if wwdata then
          
          local bc = -1
          --local rgbadjust = actdata.rgb or (205 + (205 << 8) + (205 << 16))
          GUI_StrFontOnly(gui, 0, _, _)
          
          --local _, th = gfx.measurestr('|')
          GUI_DrawButtonWW(gui, wwdata, th-3, 4, xywh, bc, gui.color.white, true, nil, nil, 0)
        else
          GUI_Str(gui,xywh,t,5,c,-4,1)
        end
        gfx.a = 1

      end

      if lvar.show_addstripdialog == true then
        GUI_DrawAddStripDialog(obj, gui, -1)
      end

      if show_trackfxorder then

        if lupd.update_gfx or lupd.update_trackfxorder or resize_display then
          GUI_DrawTrackFXOrder(gui, obj)
        end
        if lvar.trackfxorder_repos then
          lvar.trackfxorder_repos = false
          obj.sections[900].y = math.floor(gfx1.main_h/2 - obj.sections[901].h/2)
          obj.sections[901].y = obj.sections[900].y
        end
        gfx.dest = -1
        gfx.blit(978,1,0,0,0,obj.sections[901].w,obj.sections[901].h,obj.sections[901].x,obj.sections[901].y)

      end

      if lvar.show_templatechooser then

        if lupd.update_gfx or lupd.update_tchooser or resize_display then
          GUI_DrawTemplateChooser(obj, gui)
        end
        gfx.a = 1
        gfx.dest = -1
        gfx.blit(952,1,0,0,0,obj.sections[5050].w,obj.sections[5050].h,obj.sections[5050].x,obj.sections[5050].y)

      end

      if lvar.show_stripassoc then
        if lupd.update_gfx or lupd.update_stripass or resize_display then
          GUI_DrawStripAssocDialog(obj, gui)
        end
        gfx.a = 1
        gfx.dest = -1
        gfx.blit(977,1,0,0,0,obj.sections[4500].w,obj.sections[4500].h,obj.sections[4500].x,obj.sections[4500].y)
      end

      if show_settings then
        gfx.dest = -1
        GUI_DrawSettings(gui, obj, -1)
      end

    elseif mode == 0 and snaplrn_mode then
      if settings_ssdock ~= true and show_snapshots and macro_lrn_mode ~= true then

        gfx.dest = -1
        gfx.blit(1003,1,0,0,0,obj.sections[160].w,obj.sections[160].h,obj.sections[160].x,obj.sections[160].y)

        if dragparam ~= nil then
          local x, y = dragparam.x, dragparam.y
          gfx.a = dragparam.alpha or 0.7
          local iidx = ctl_files[knob_select].imageidx
          if iidx == nil and ksel_loaded == false then
            ksel_loaded = true
            gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
            iidx = 1023
          elseif iidx == nil then
            iidx = 1023
          end
          local w, _ = gfx.getimgdim(iidx)
          local h = ctl_files[knob_select].cellh
          dragparam.iw, dragparam.ih = w, h
          gfx.blit(iidx,scale_select*lvar.zoom,0,0,p*h,w,ctl_files[knob_select].cellh,x,y)
          if dragparam.alpha and dragparam.alpha < 1 then
            f_Get_SSV(gui.color.red)
          else
            f_Get_SSV(gui.color.yellow)
          end
          gfx.a = 1
          gfx.roundrect(x, y ,w*lvar.zoom, h*lvar.zoom, 8, 1, 0)
        end
      end
    end

    local hb = #lvar.highbox
    if hb > 0 then
      gfx.dest = -1
      local clear = true
      for x = 1, hb do
        local box = lvar.highbox[x]
        if reaper.time_precise() < box.time then
          local col = box.col
          if tonumber(col) then
            gfx.r = (col & 255)/255
            gfx.g = ((col >> 8) & 255)/255
            gfx.b = ((col >> 16) & 255)/255            
          else
            f_Get_SSV(col)
          end
          gfx.rect(box.x,box.y,box.w,box.h,0)
          clear = false
        end
      end
      if clear then
        lvar.highbox = {}
      end
    end

    if show_arrowupdn then
      local sk, o = skin.updn, 2000
      if stripgallery_view == 1 or settings_pagescrolldir == 1 then
        sk = skin.lr
        o = 2001
      end
      gfx.blit(sk,1,0,0,moupdn_img*obj.sections[o].h,obj.sections[o].w,obj.sections[o].h,obj.sections[o].x,obj.sections[o].y)
    end
    
    --[[if lvar.analyzer.active == true and lvar.analyzer.type == 2 then

      --local lvar.analyzer.window = reaper.JS_Window_Find('- LBX Stripper -', true)

      local a_hwnd = reaper.JS_Window_Find(lvar.analyzer.title, true)
      if a_hwnd then
        local gdi_dc = reaper.JS_LICE_GetDC(lvar.analyzer.bitmap)
        local an_dc = reaper.JS_GDI_GetClientDC(a_hwnd)
        local xywh = obj.sections[5046]
        reaper.JS_GDI_Blit(gdi_dc, xywh.x, xywh.y, an_dc, 0, 0, xywh.w, xywh.h, "COPY")
        reaper.JS_Window_InvalidateRect(lvar.analyzer.window,0,0,xywh.x+xywh.w,xywh.y+xywh.h, true)
        --reaper.JS_LICE_ReleaseDC(, gdi_dc)
        reaper.JS_GDI_ReleaseDC(a_hwnd, an_dc)

        --reaper.JS_Window_Update(win_hwnd)
      end

    end]]

    if not fullscreen_open then
      gfx.a = 1
      DrawXPnls()
    end
    
    if show_dd == true then
      if lupd.update_gfx == true or lupd.update_dd == true or resize_display == true then
        GUI_DrawDropdown(gui, obj)
      end
      --gfx.blit(1,1,0,ddlist.x,ddlist.y,ddlist.w+6,ddlist.h+6,ddlist.x,ddlist.y)
      --if lupd.update_surface or lupd.update_gfx or lupd.update_dd then
        gfx.dest = -1
        gfx.blit(996,1,0,0,0,ddlist.w+2,ddlist.h+2,ddlist.x,ddlist.y)
      --end
    end

    gfx.dest = -1
    if MS_Open > 0 then
      GUI_DrawMsg(gui, obj)

    elseif EB_Open > 0 then
      editbox_draw(gui, editbox)

    end

    gfx.dest = -1
    if show_midioutind and midimsg == true then
      f_Get_SSV(gui.color.red)
      gfx.rect(5,0,5,5,1,1)
      --f_Get_SSV(gui.color.black)
      --gfx.rect(6,6,8,8,0,1)
    end
    if touch_trigger == true then
      f_Get_SSV('0 0 255')
      gfx.rect(0,0,5,5,1)
    end
    if lvar.delayfunction.touch_timer then
      f_Get_SSV('255 255 255')
      gfx.rect(0,0,5,5,1)
    end


    if show_bitmap then
      --[[if lvar.showguibitmap then
        gfx.blit(guibitmap,1,0,0,
                          0,
                          gfx1.main_w,
                          gfx1.main_h,
                          0,
                          0)      
      end]]
      --[[f_Get_SSV(gui.color.white)
      gfx.rect(obj.sections[10000].x,
               obj.sections[10000].y,
               obj.sections[10000].w,
               obj.sections[10000].h)
      
      if stripgallery_view == 0 and lvar.livemode == 0 then
        gfx.blit(ctl_bitmap,1,0,surface_offset.x,
                          surface_offset.y,
                          obj.sections[10].w,
                          obj.sections[10].h,
                          obj.sections[10].x,
                          obj.sections[10].y)
      else
        gfx.blit(ctl_bitmap2,1,0,0,
                          0,
                          obj.sections[10000].w,
                          obj.sections[10000].h,
                          obj.sections[10000].x,
                          obj.sections[10000].y)
      end    ]]  
    end
    
    
    gfx.update()

    resize_display = false
    resize_snaps = false
    resize_fsnaps = false

    if --[[lupd.update_gfx or]] (lvar.redrawguibitmap == true and lvar.redrawguibitmap_nocontext ~= true) or (lvar.redrawguibitmap_nocontext == true and mouse.context == nil) then
      RedrawGUIBitmap2()
      lvar.redrawguibitmap_nocontext = nil
      --lvar.redrawguibitmap = nil
    elseif lvar.redrawguibitmap_timer and reaper.time_precise() > lvar.redrawguibitmap_timer then
      RedrawGUIBitmap2()
      lvar.redrawguibitmap_timer = nil
    end
    
    --[[if redraw_ctlbitmapmix then
      redraw_ctlbitmapmix = nil
      GUI_DrawCtlBitmap_Mix()
    end]]
    
    lupd = {}
    return lupd

    --[[lupd.update_gfx = false
    lupd.update_surface = false
    lupd.update_surfaceedge = false
    lupd.update_sidebar = false
    lupd.update_topbar = false
    lupd.update_ctlopts = false
    resize_display = false
    lupd.update_ctls = false
    lupd.update_bg = false
    lupd.update_settings = false
    lupd.update_snaps = false
    lupd.update_msnaps = false
    lupd.update_fsnaps = false
    lupd.update_fmsnaps = false
    lupd.update_actcho = false
    resize_snaps = false
    resize_fsnaps = false
    lupd.update_xxy = false
    lupd.update_xxypos = false
    lupd.update_eqcontrol = false
    lupd.update_macroedit = false
    lupd.update_macrobutt = false
    lupd.update_trackfxorder = false
    lupd.update_dd = false
    lupd.update_snapmorph = false
    lupd.update_lfoedit = false
    lupd.update_lfoeditbar = false
    lupd.update_lfopos = false
    lupd.update_mutate = false
    lupd.update_randomopts = false
    lupd.update_samplemanager = false
    lupd.update_stripbrowser = false]]

  end

  function SetSurfaceFade()
    if lvar.surfacefade_active then
      lvar.surface_fade = {}
      local rt = reaper.time_precise()
      lvar.surface_fade.start = 0
      lvar.surface_fade.st = rt
      lvar.surface_fade.et = rt+lvar.surfacefadetime
      lupd.update_surface = true
    end
  end

  function GetControlLoc_Screen(strip, page, c)
    local ctl = strips[strip][page].controls[c]
    if ctl then
      if lvar.livemode >= 1 then
        if ctl.switcher then
          local swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
          local sx, sy = TranslateMixCtlPos(c, swid)
          return sx, sy, ctl.wsc*lvar.zoom, ctl.hsc*lvar.zoom
        end
      else
        local sx = ctl.xsc - surface_offset.x + obj.sections[10].x 
        local sy = ctl.ysc - surface_offset.y + obj.sections[10].y
        return sx, sy, ctl.wsc*lvar.zoom, ctl.hsc*lvar.zoom
      end
    end
  end

  function GUI_DrawMixerScroll(obj, gui, show)

    --825 = mixer over - temp

    lvar.mixerscrollsetup = true
    GUI_DrawMixerPanel(obj, gui)
    local offx = obj.sections[5024].x
    local offy = obj.sections[5024].y
    lvar.mixerscrollsetup = nil
    gfx.dest = 825
    --gfx.setimgdim(825,-1,-1)
    Img_SetDim(825,obj.sections[5024].w,obj.sections[5024].h)

    gfx.a=1
    --gfx.mode = -2
    if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
      gfx.blit(lvar.bgloaded,1,0,obj.sections[5024].x - obj.sections[10].x -(lvar.bgoffx or 0),obj.sections[5024].y-obj.sections[10].y-(lvar.bgoffy or 0),
               obj.sections[5024].w,obj.sections[5024].h,0,0)
    else
      f_Get_SSV(backcol2 or backcol)
      gfx.rect(0, 0, obj.sections[5024].w, obj.sections[5024].h, 1)
    end
    gfx.a = lvar.mmov_tint
    f_Get_SSV(gui.color.black)
    gfx.rect(0, 0, obj.sections[5024].w, obj.sections[5024].h, 1)
    gfx.a = lvar.trmix_pnl_tbar_alpha
    gfx.rect(0, 0, obj.sections[5024].w, obj.sections[5024].h, 1)
    gfx.a = 1
    --gfx.mode = gmode

    GUI_BlitMixerPanel(obj, gui, offx, offy)
    lvar.mst = 0.08
    lvar.mixerscroll_time = reaper.time_precise() + lvar.mst
    lvar.mixerscroll_open = show
  end

  function GUI_DrawAnalyzerTracks(obj, gui)
    gfx.a = 1
    gfx.dest = 963
    --gfx.setimgdim(963, -1,-1)
    Img_SetDim(963, obj.sections[5048].w, 15)

    local atr = Analyzer_GetTrack()

    local scnt = reaper.GetTrackNumSends(atr,-1)
    local fnd
    for i = 0, lvar.freqcnt do
      lvar.freq[i].name = ''
    end
    for i = 0, scnt-1 do
      local ttr = reaper.GetTrackSendInfo_Value(atr,-1,i,'P_SRCTRACK')
      local mut = reaper.GetTrackSendInfo_Value(atr,-1,i,'B_MUTE')
      if mut == 0 then
        local tch = reaper.GetTrackSendInfo_Value(atr,-1,i,'I_DSTCHAN')
        local _,nm = reaper.GetTrackName(ttr)
        lvar.freq[tch/2].name = nm
      end
    end

    f_Get_SSV(gui.color.black)
    gfx.rect(0, 0, obj.sections[5048].w, 15, 1)

    local gap = 2
    local w = math.floor(obj.sections[5048].w/(lvar.freqcnt+1))-gap
    local xywh = {x = 0, y = 0, w = w, h = 13}
    for i = 0, lvar.freqcnt do
      local f = 0
      local c = lvar.freq[i].col
      f_Get_SSV(c)
      if atr and reaper.TrackFX_GetParamNormalized(atr,0,12+i) == 1 then
        f = 1
        c = '0 0 0'
      end
      xywh.x = (i)*(w+gap)
      gfx.rect(xywh.x,xywh.y+1,xywh.w,xywh.h,f)

      local t = lvar.freq[i].name or ''
      GUI_Str(gui,xywh,t,5,c,-4 + gui.fontsz.sb,1,nil,gui.fontnm.sb)
    end

    gfx.dest = 1

  end

  function GUI_DrawAnalyzerControls(obj, gui)
    gfx.a = 1
    gfx.dest = 962

    --gfx.setimgdim(962, -1,-1)
    Img_SetDim(962, obj.sections[5047].w, obj.sections[5047].h)

    f_Get_SSV(gui.color.black)
    gfx.rect(0, 0, obj.sections[5047].w, obj.sections[5047].h, 1)

    local bh = 20

    local tr = Analyzer_GetTrack()

    local xywh = {x = 5,
                  y = 5,
                  w = lvar.trbtns_size,
                  h = bh/2}

    if tr then
      local idx = lvar.analyzer.pos+1
      if lvar.analyzer.controls[idx] then
        for c = 1, #lvar.analyzer.controls[idx] do

          local param = lvar.analyzer.controls[idx][c].param
          local _, pname = reaper.TrackFX_GetParamName(tr,idx-1,param,'')
          local _, dval = reaper.TrackFX_GetFormattedParamValue(tr,idx-1,param,'')

          GUI_Str(gui,xywh,pname,5,'160 160 160',-4 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb)--,98)
          xywh.y = xywh.y + bh/2
          GUI_Str(gui,xywh,dval,5,'160 160 160',-4 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb)--,98)
          xywh.y = xywh.y + bh/2 + 10
        end
      end
    end

    gfx.dest = 1

  end

  function GUI_DrawMixerPanel(obj, gui, flag)

    GUI_DrawTrackBtnPanel(obj, gui, 956, obj.sections[5040],
                          lvar.trmix_btnpnl_cols,
                          lvar.trmix_btnpnl_rows,
                          lvar.dm_btnpnlidx, 1)
    GUI_DrawTrackMixer(obj, gui)
    if lvar.analyzer.active and lvar.analyzer.showcontrols then
      GUI_DrawAnalyzerControls(obj, gui)
      if lvar.analyzer.pos == 0 then
        GUI_DrawAnalyzerTracks(obj, gui)
      end
    end
    if lvar.trmix_sndpnl_show > 0 then
      GUI_DrawTrackSendPanel(obj, gui)
    else
      GUI_DrawTrackBtnPanel(obj, gui, 957, obj.sections[5042],
                            lvar.trmix_btnpnl2_cols,
                            lvar.trmix_btnpnl_rows,
                            lvar.dm_btnpnl2idx, 0)
    end

    lvar.trmix_sndpnl_dirty = {}
    lvar.trmix_dirty = {}

  end

  function GUI_BlitMixerPanel(obj, gui, offx, offy)

    gfx.a = 1
    gfx.blit(956, 1, 0, 0, 0, obj.sections[5040].w, obj.sections[5040].h, obj.sections[5040].x-offx, obj.sections[5040].y-offy)
    gfx.mode = 2
    if not lvar.analyzer.active then
      gfx.blit(954, 1, 0, 0, 0, obj.sections[5005].w, obj.sections[5025].h, obj.sections[5025].x-offx, obj.sections[5025].y-offy)
    else
      f_Get_SSV(gui.color.black)
      gfx.rect(obj.sections[5025].x-offx, obj.sections[5025].y-offy, obj.sections[5005].w-lvar.trbtns_size, obj.sections[5025].h,1)
      gfx.blit(962, 1, 0, 0, 0, obj.sections[5047].w, obj.sections[5047].h,
                          obj.sections[5047].x, obj.sections[5047].y)
      if lvar.analyzer.pos == 0 then
        gfx.blit(963, 1, 0, 0, 0, obj.sections[5048].w, obj.sections[5048].h,
                            obj.sections[5048].x, obj.sections[5048].y)
      end
      gfx.blit(954, 1, 0, obj.sections[5005].w-lvar.trbtns_size, 0, lvar.trbtns_size, obj.sections[5025].h,
                          obj.sections[5025].x-offx +obj.sections[5005].w-(lvar.trbtns_size), obj.sections[5025].y-offy)
    end
    if lvar.trmix_sndpnl_show > 0 then
      gfx.blit(955, 1, 0, 0, 0, obj.sections[5030].w, obj.sections[5030].h, obj.sections[5030].x-offx, obj.sections[5030].y-offy)
    else
      gfx.mode = gmode
      gfx.blit(957, 1, 0, 0, 0, obj.sections[5042].w, obj.sections[5042].h, obj.sections[5042].x-offx, obj.sections[5042].y-offy)
    end
    gfx.mode = gmode

    local t = 'Action Panel '..string.format('%i',math.floor(lvar.dm_btnpnl_page+1))
    GUI_Str(gui,obj.sections[5045],t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)

    f_Get_SSV(gui.color.black)
    --gfx.a = 0.3
    --gfx.rect(obj.sections[5080].x-offx, obj.sections[5080].y-offy, obj.sections[5080].w, obj.sections[5080].h,1)
    gfx.a = 0.3
    gfx.rect(obj.sections[5081].x-offx, obj.sections[5081].y-offy, obj.sections[5081].w, obj.sections[5081].h,1)
    --gfx.rect(obj.sections[5080].x-offx, obj.sections[5080].y-offy, obj.sections[5080].w, obj.sections[5080].h,1)
    gfx.a = 1 --lvar.trmix_pnl_tbar_alpha
    --f_Get_SSV('0 0 0')
    gfx.rect(obj.sections[5080].x-offx, obj.sections[5080].y-offy, 4, obj.sections[5080].h,1)
    gfx.rect(obj.sections[5080].x-offx+4, obj.sections[5080].y-offy, 6, 4,1)
    --gfx.rect(obj.sections[5081].x-offx-6,obj.sections[5080].y-offy,6,obj.sections[5025].h,1)
    gfx.a = 1
    local hh = obj.sections[5081].y+obj.sections[5081].h-1
    gfx.line(obj.sections[5081].x-1,obj.sections[5081].y,obj.sections[5081].x-1,hh)
    gfx.line(obj.sections[5081].x-lvar.trbtns_size-5,hh,obj.sections[5081].x-1,hh)
  end

  function GUI_DrawTrackBtnPanel_BtnUpdate(obj, gui, iidx, box, cols, rows, idx, dir, c, r)

    gfx.dest = iidx

    local xywh = {w = lvar.trmixbtns_size, h = lvar.trmixbtns_size}

    local offs = lvar.dm_btnpnl_page*cols

    local cc = c
    if dir == 1 then
      cc = cols-1-c
    end
    xywh.x = (cc)*(xywh.w+10)
    xywh.y = (r)*(xywh.h+10)

    local col = c+1
    local row = r+1
    if lvar.dm_btnpnl and lvar.dm_btnpnl[idx] and lvar.dm_btnpnl[idx][row] and lvar.dm_btnpnl[idx][row][col+offs] then
      local actdata = lvar.dm_btnpnl[idx][row][col+offs]
      GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
      local tab, th = GetWWData(actdata.ndesc or actdata.desc, xywh.w-8)
      if not tab[#tab].t then
        tab[#tab] = nil
      end
      local bc = -1
      local rgbadjust = actdata.rgb or (205 + (205 << 8) + (205 << 16))
      if actdata.val and actdata.val == 1 then
        bc = -11
      end
      GUI_DrawButtonWW(gui, tab, th-3, 4, xywh, bc, gui.color.white, true, nil, nil, 0, nil, nil, nil, nil, nil, rgbadjust)
    else
      GUI_DrawButton(gui,'+',xywh,-7,'48 48 48',true,nil,nil,10)
    end

    gfx.dest = 1

  end

  function GUI_DrawTrackBtnPanel(obj, gui, iidx, box, cols, rows, idx, dir)

    gfx.dest = iidx
    --gfx.setimgdim(iidx, -1,-1)
    Img_SetDim(iidx, box.w, box.h)

    local xywh = {w = lvar.trmixbtns_size, h = lvar.trmixbtns_size}

    local offs = lvar.dm_btnpnl_page*cols

    local uptab = {}
    local uptabcnt = 1

    for r = 0, rows-1 do
      for c = 0, cols-1 do
        local cc = c
        if dir == 1 then
          cc = cols-1-c
        end
        xywh.x = (cc)*(xywh.w+10)
        xywh.y = (r)*(xywh.h+10)

        local col = c+1
        local row = r+1
        if lvar.dm_btnpnl and lvar.dm_btnpnl[idx] and lvar.dm_btnpnl[idx][row] and lvar.dm_btnpnl[idx][row][col+offs] then
          local actdata = lvar.dm_btnpnl[idx][row][col+offs]
          GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
          local tab, th = GetWWData(actdata.ndesc or actdata.desc, xywh.w-8)
          if not tab[#tab].t then
            tab[#tab] = nil
          end
          local commid = actdata.commid
          local v
          if tonumber(commid) then
            v = reaper.GetToggleCommandStateEx(0, commid)
          else
            v = reaper.GetToggleCommandStateEx(0, reaper.NamedCommandLookup(commid))
          end
          local bc = -1
          local rgbadjust = actdata.rgb or (205 + (205 << 8) + (205 << 16))
          if v == 1 then
            bc = -11            
          end
          GUI_DrawButtonWW(gui, tab, th-3, 4, xywh, bc, gui.color.white, true, nil, nil, 0, nil, nil, nil, nil, nil, rgbadjust)
          if v ~= -1 then
            uptab[uptabcnt] = {tab = lvar.dm_btnpnl[idx][row][col+offs],
                               iidx = iidx, box = box, cols = cols, rows = rows, idx = idx, dir = dir, row = r, col = c}
            uptabcnt = uptabcnt + 1
          end
        else
          GUI_DrawButton(gui,'+',xywh,-7,'48 48 48',true,nil,nil,10)
        end

      end
    end
    lvar.btnpnl_update[idx] = uptab

    gfx.dest = 1

  end

  function GUI_DrawTrackSendPanel(obj, gui)

    xywh = {x = 0, y = 0, w = obj.sections[5030].w, h = obj.sections[5030].h}
    local cnt = lvar.sndpnl_maxrows

    gfx.dest = 955
    --gfx.setimgdim(955, -1,-1)
    Img_SetDim(955, xywh.w,xywh.h)

    lvar.trmix_sndpnl_data = {}

    for tb2 = 0, cnt-1 do
      local tb = tb2 + lvar.trmix_sndpnl_offs
      GUI_DrawSendChannel(obj, gui, tb)
    end

    gfx.dest = 1
  end

  function GUI_DrawSendChannel(obj, gui, tb)

    gfx.dest = 955
    lvar.trmix_sndpnl_data[tb] = {}

    local tb2 = tb-lvar.trmix_sndpnl_offs
    local trmix_sndpnl_data = lvar.trmix_sndpnl_data
    local tr = GetTrack(lvar.dynamicmode_trn)
    if tr then

      local func = reaper.GetTrackSendUIVolPan
      local func2 = reaper.GetTrackSendName
      local func3 = reaper.GetTrackSendUIMute
      if lvar.trmix_sndpnl_show == 2 then
        func = reaper.GetTrackReceiveUIVolPan
        func2 = reaper.GetTrackReceiveName
        func3 = reaper.GetTrackReceiveUIMute
      end

      local r, vol, pan = func(tr, tb)
      local v = normalize(trsends_mmtable[1].min,trsends_mmtable[1].max,vol or 0)
      local v = ctlScaleInv(lvar.trmix_vscale, v)
      trmix_sndpnl_data[tb].vol = vol
      trmix_sndpnl_data[tb].vol_normscale = v

      local p = normalize(trsends_mmtable[2].min,trsends_mmtable[2].max,pan or 0)
      trmix_sndpnl_data[tb].pan = pan
      trmix_sndpnl_data[tb].pan_norm = p

      local sk_w, sk_h = skin.sliderknb_w, skin.sliderknb_h
      local rk_w = skin.rotknb_w

      local o5030 = obj.sections[5030]
      local o5031 = obj.sections[5031]
      local o5032 = obj.sections[5032]
      local xx = math.floor(((tb2)*(lvar.sndpnl_cwidth+10)))
      local x = math.floor(xx + lvar.sndpnl_cwidth/2)+5
      local y = math.floor(o5031.y+o5031.h - (v*o5031.h))

      local py = o5032.y

      local xywh = {x = xx+5, y = o5031.y-40, w = lvar.sndpnl_cwidth, h = 14}
      local xywh2 = {x = xx+5, y = o5032.y-40, w = lvar.sndpnl_cwidth, h = 35}

      gfx.a = 1
      if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
        gfx.blit(lvar.bgloaded,1,0,obj.sections[5030].x + xx - obj.sections[10].x -(lvar.bgoffx or 0),obj.sections[5024].y-obj.sections[10].y-(lvar.bgoffy or 0),
                 lvar.sndpnl_cwidth+10,obj.sections[5030].h,xx,0)
      else
        f_Get_SSV(backcol2 or backcol)
        gfx.rect(xx, 0, lvar.sndpnl_cwidth+10, obj.sections[5030].h, 1)
      end
      gfx.a = lvar.mmov_tint
      f_Get_SSV(gui.color.black)
      gfx.rect(xx, 0, lvar.sndpnl_cwidth+10, obj.sections[5030].h, 1)
      gfx.a = lvar.trmix_pnl_tbar_alpha
      gfx.rect(xx, 0, lvar.sndpnl_cwidth+10, lvar.trmix_pnl_tbar, 1)
      gfx.a = 1

      local xywh3 = {x = xx+lvar.sndpnl_cwidth/2-5+2, y = o5031.y+o5031.h+6, w = 20, h = 14}
      GUI_Str(gui,xywh3,string.format('%i',tb+1),5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb)

      if r then
        local t = reaper.mkvolstr('', vol)
        GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)
        xywh.y = xywh.y - 15
        t = reaper.mkpanstr('', pan)
        GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)

        local r, t = func2(tr, tb, '')
        trmix_sndpnl_data[tb].name = t or ''
        local tab, th = GetWWData(t, lvar.sndpnl_cwidth-10)
        if not tab[#tab].t then
          tab[#tab] = nil
        end
        local rcnt = math.min(#tab,2)
        local bc = -8
        local _, mute = func3(tr, tb)
        trmix_sndpnl_data[tb].mute = mute
        if mute == true then
          bc = -1
        end
        GUI_DrawButtonWW(gui, tab, th-3, 2, xywh2, bc, gui.color.white, true, nil, nil, 0)
      end

      if r then
        gfx.a = 1
      else
        gfx.a = 0.5
      end

      f_Get_SSV('128 128 128')
      gfx.rect(x, o5031.y,2,o5031.h,0)
      if r then
        gfx.blit(skin.sliderknb,1,0,0,0,sk_w,sk_h,x-math.floor(sk_w/2),y-math.floor(sk_h/2))
      end
      local frames = (skin.rotknb_h/skin.rotknb_w)-1
      gfx.blit(skin.rotknb,1,0,0,rk_w*math.floor(p*frames),rk_w,rk_w,x-math.floor(rk_w/2),py)
      gfx.a = 1

      f_Get_SSV('0 0 0')
      gfx.line(xx+lvar.sndpnl_cwidth+9, 0, xx+lvar.sndpnl_cwidth+9, lvar.trmix_h)
      if tb2 == 0 then
        gfx.line(xx, 0, xx, lvar.trmix_h)
      end
      gfx.line(xx, lvar.trmix_h-1, xx+lvar.sndpnl_cwidth+10, lvar.trmix_h-1)
      gfx.dest = 1

      return x-math.floor(lvar.sndpnl_cwidth/2), tb2

    end

    gfx.dest = 1
  end

  function GUI_DrawTrackMixer(obj, gui)

    --5025 = track strip
    --5005 = track buttons

    xywh = {x = 0, y = 0, w = obj.sections[5004].w, h = obj.sections[5025].h}
    local cnt = math.min(--[[#lvar.dm_trackbtns[lvar.dm_tbidx],]] lvar.trov_maxrows-1, lvar.dm_maxvistracks)

    local w = (xywh.w + 10)*(cnt+1)

    gfx.dest = 954
    --gfx.setimgdim(954, -1,-1)
    --gfx.setimgdim(954, w,xywh.h)
    Img_SetDim(954, w,xywh.h)

    --DBG('A')
    if lvar.mixerchan_redraw then
      GUI_DrawMixerChanOverlay(obj, gui)
      GUI_DrawMixerChanOverlay2(obj, gui)
      lvar.mixerchan_redraw = nil
    end

    gfx.dest = 954

    local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
    for tb2 = 1, cnt do
      local tb = tb2 + lvar.trbtns_offs
      --if dm_trackbtns[tb] then
        GUI_DrawMixerChannel(obj, gui, tb)
      --end
      gfx.dest = 954
    end
    
    --[[if #dm_trackbtns < cnt then
      
    end]]

    local xywh = obj.sections[5008]
    gfx.a = 1
    gfx.mode = 2
    gfx.blit(959,1,0,obj.sections[5005].w-xywh.w,0,xywh.w,obj.sections[5025].h,(xywh.w+10)*(cnt),0)
    gfx.mode = gmode
    gfx.a = 1 --lvar.trmix_pnl_tbar_alpha
    f_Get_SSV('0 0 0')
    gfx.rect((xywh.w+10)*(cnt),0,4,obj.sections[5025].h,1)
    gfx.a = 1
    GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
    local xywh = obj.sections[5009]
    local seltr = GetTrack(lvar.dynamicmode_trn) --reaper.GetSelectedTrack2(0,0,true)
    --local seltr = reaper.GetSelectedTrack2(0,0,true)
    local trnm = ''
    if seltr then
      _, trnm = reaper.GetTrackName(seltr)
    end
    local tab, th
    if lvar.trmix_sndpnl_show < 2 then
      tab, th = GetWWData(trnm..' SENDS', xywh.w-2)
    else
      tab, th = GetWWData(trnm..' RECEIVES', xywh.w-2)
    end
    if not tab[#tab].t then
      tab[#tab] = nil
    end
    local bc = -1
    if lvar.trmix_sndpnl_show > 0 then
      bc = -8
    end
    GUI_DrawButtonWW(gui, tab, th-6, 4, xywh, bc, gui.color.white, true, nil, nil, 0)

    GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
    local xywh = obj.sections[5010]
    local tab, th = GetWWData(trnm..' STRIP ORDER', xywh.w-2)
    if not tab[#tab].t then
      tab[#tab] = nil
    end
    local bc = -1
    if show_trackfxorder then
      bc = -8
    end
    GUI_DrawButtonWW(gui, tab, th-6, 4, xywh, bc, gui.color.white, true, nil, nil, 0)

    GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
    local xywh = obj.sections[5011]
    local tab, th = GetWWData('ANALYZER', xywh.w-2)
    if not tab[#tab].t then
      tab[#tab] = nil
    end
    local bc = -1
    if lvar.analyzer.active then
      bc = -8
    end
    GUI_DrawButtonWW(gui, tab, th-6, 4, xywh, bc, gui.color.white, true, nil, nil, 0)

    if lvar.trmix_sizebtn then
      GUI_StrFontOnly(gui,gui.fontsz.butt,gui.fontnm.butt,gui.fontflag.butt)
      local xywh = obj.sections[5012]
      local tab, th = GetWWData('< >', xywh.w-2)
      if not tab[#tab].t then
        tab[#tab] = nil
      end
      local bc = -1
      if lvar.mdrag then
       bc = -8
      end
      GUI_DrawButtonWW(gui, tab, th-6, 4, xywh, bc, gui.color.white, true, nil, nil, 0)
    end
    
    f_Get_SSV('0 0 0')
    gfx.line(obj.sections[5008].x, 0, obj.sections[5008].x, lvar.trmix_h)

    gfx.dest = 1
  end

  function GUI_DrawMixerChanOverlay2(obj, gui)

    xywh = {x = 0, y = 0, w = obj.sections[5004].w, h = obj.sections[5025].h}
    local cnt = math.min(--[[#lvar.dm_trackbtns[lvar.dm_tbidx],]] lvar.trov_maxrows-1, lvar.dm_maxvistracks)

    local w = (xywh.w + 10)*(cnt+1)

    gfx.dest = 959
    --gfx.setimgdim(959, -1,-1)
    --gfx.setimgdim(959, w,xywh.h)
    Img_SetDim(959, w,xywh.h)

    if lvar.bgloaded > 0 and lvar.mmov_bgimgon then
      gfx.blit(lvar.bgloaded,1,0,obj.sections[5005].x - obj.sections[10].x -(lvar.bgoffx or 0),
                                 obj.sections[5025].y - obj.sections[10].y -(lvar.bgoffy or 0),
                                 w, obj.sections[5025].h,0,0)
    else
      f_Get_SSV(backcol2 or backcol)
      gfx.rect(0, 0, w, obj.sections[5025].h, 1)
    end
    gfx.a = lvar.mmov_tint
    f_Get_SSV(gui.color.black)
    gfx.rect(0, 0, w, obj.sections[5025].h, 1)
    gfx.a = lvar.trmix_pnl_tbar_alpha
    gfx.rect(0, 0, w, lvar.trmix_pnl_tbar-2, 1)
    gfx.a = 1 --lvar.trmix_pnl_tbar_alpha
    gfx.rect(0, 0, (xywh.w + 10)*cnt, 4, 1)
    gfx.a = 1

    local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
    for tb2 = 1, cnt do
      local tb = tb2 + lvar.trbtns_offs
      if dm_trackbtns and dm_trackbtns[tb] then
        gfx.a = 1
      else
        gfx.a = 0.3
      end
        gfx.blit(958,1,0,0,0,(xywh.w)+10,xywh.h,(xywh.w+10)*(tb2-1),0)
        --GUI_DrawMixerChannel(obj, gui, tb)
      --end
      --gfx.dest = 954
    end

  end

  function GUI_DrawMixerChanOverlay(obj, gui)

    xywh = {x = 0, y = 0, w = obj.sections[5004].w+10, h = obj.sections[5025].h}
    --local w = (xywh.w + 10)*(cnt+1)

    gfx.dest = 958
    --gfx.setimgdim(958, -1,-1)
    --gfx.setimgdim(958, xywh.w+10,xywh.h)
    Img_SetDim(958,xywh.w+10,xywh.h)

    f_Get_SSV('0 0 0')
    gfx.line(0, 0, 0, lvar.trmix_h)
    gfx.line(0, lvar.trmix_h-1, lvar.trbtns_size+10, lvar.trmix_h-1)

    local xywh = {x = obj.sections[5070].x,
                  y = obj.sections[5070].y,
                  w = obj.sections[5070].w,
                  h = obj.sections[5070].h}
    local bc = -1
    GUI_DrawButton(gui, 'REC', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)

    local xywh = {x = obj.sections[5071].x,
                  y = obj.sections[5071].y,
                  w = obj.sections[5071].w,
                  h = obj.sections[5071].h}
    GUI_DrawButton(gui, 'FX', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)

    xywh.y = obj.sections[5072].y
    GUI_DrawButton(gui, 'Ø', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)

    xywh.y = obj.sections[5075].y
    local t = 'MASTER'
    if xywh.w < 40 then
      t = 'MAST'
    end
    GUI_DrawButton(gui, t, xywh, bc, gui.skol.sb_txt_on, true, '', nil, -4)

    xywh.y = obj.sections[5073].y
    xywh.h = obj.sections[5073].h
    GUI_DrawButton(gui, 'M', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)

    xywh.y = obj.sections[5074].y
    GUI_DrawButton(gui, 'S', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)

    local x,y,w,h,ww,tint,pkhoff,pkhoff2
    x = obj.sections[5029].x
    y = obj.sections[5029].y
    h = obj.sections[5029].h
    ww = lvar.trmix_peak_w
    tint = 0.5
    pkhoff = 8
    pkhoff2 = 13
    pkhoff_tot = pkhoff+pkhoff2

    f_Get_SSV(gui.color.black)
    gfx.a = tint
    gfx.rect(x, y-pkhoff_tot, ww*2+2, h+pkhoff_tot, 1)
    gfx.a = 1
    gfx.rect(x-1, y-1-pkhoff_tot, ww*2+4, h+2+pkhoff_tot, 0)
    gfx.line(x,y-2,x+ww*2+2,y-2)

    gfx.dest = 1

  end

  function GUI_DrawMixerChannel(obj, gui, tb)
    gfx.dest = 954
    local tb2 = tb-lvar.trbtns_offs

    local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
    local master
    --[[if dm_trackbtns[tb].trn == -1 then
      master = true
    end]]
    local tr 
    if dm_trackbtns and dm_trackbtns[tb] then
      tr = GetTrack(dm_trackbtns[tb].trn)
      if tr then
        if GetTrackGUID(tr) ~= dm_trackbtns[tb].guid and dm_trackbtns[tb].trn ~= -1 then
          tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtns[tb].guid)
          if tr then
            dm_trackbtns[tb].trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
          end
        end
      end
    end
    
    local r, vol, pan, v, p = nil, 0, 0.5, 0, 0.5
    if tr then

      r, vol, pan = trctls_table[1].funcget(tr)
      v = normalize(trctls_table[1].min,trctls_table[1].max,vol or 0)
      v = ctlScaleInv(lvar.trmix_vscale, v)
      p = normalize(trctls_table[2].min,trctls_table[2].max,pan or 0)

    end
    
    local sk_w, sk_h = skin.sliderknb_w, skin.sliderknb_h
    local rk_w = skin.rotknb_w

    local o5028 = obj.sections[5028]
    local o5026 = obj.sections[5026]
    local o5025 = obj.sections[5025]
    local xx = math.floor(((tb2-1)*(o5025.w+10)))
    local x = math.floor(xx + o5026.x + o5026.w/2)
    local y = math.floor(o5026.y+o5026.h - (v*o5026.h))

    local py = o5028.y

    local xywh = {x = xx+o5026.x, y = o5026.y-35, w = o5026.w, h = 10}

    gfx.a = 1
    gfx.mode = 2
    gfx.blit(959,1,0,xx,0, o5025.w+10, o5025.h, xx, 0)
    gfx.mode = gmode

    local h = o5026.h
    if tr then

      local t = reaper.mkvolstr('', vol)
      GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)
      xywh.y = xywh.y - 15
      t = reaper.mkpanstr('', pan)
      GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)
    else
      gfx.a = 0.3
      h = o5026.h - math.floor(sk_h/2)
    end
    

    f_Get_SSV('128 128 128')
    gfx.rect(x, o5026.y,2,h,0)

    gfx.blit(skin.sliderknb,1,0,0,0,sk_w,sk_h,x-math.floor(sk_w/2),y-math.floor(sk_h/2))

    local frames = (skin.rotknb_h/skin.rotknb_w)-1
    gfx.blit(skin.rotknb,1,0,0,rk_w*math.floor(p*frames),rk_w,rk_w,x-math.floor(rk_w/2),py)
    
    gfx.a = 1
    
    if tr then

      dm_trackbtns[tb].vol = vol
      dm_trackbtns[tb].vol_normscale = v
      dm_trackbtns[tb].pan = pan
      dm_trackbtns[tb].pan_norm = p
    
      --[[f_Get_SSV('0 0 0')
      gfx.line(xx, 0, xx, lvar.trmix_h)
      gfx.line(xx, lvar.trmix_h-1, xx+lvar.trbtns_size+10, lvar.trmix_h-1)]]

      local xywh = {x = xx+obj.sections[5070].x,
                    y = obj.sections[5070].y,
                    w = obj.sections[5070].w,
                    h = obj.sections[5070].h}
      if not master then
        if reaper.GetMediaTrackInfo_Value(tr,'I_RECARM') == 1 then
          local bc = -2
          GUI_DrawButton(gui, 'REC', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)
        end
      end
      local xywh = {x = xx+obj.sections[5071].x,
                    y = obj.sections[5071].y,
                    w = obj.sections[5071].w,
                    h = obj.sections[5071].h}
      if reaper.GetMediaTrackInfo_Value(tr,'I_FXEN') ~= 0 then
        local bc = -8
        GUI_DrawButton(gui, 'FX', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)
      end

      if not master then
        if reaper.GetMediaTrackInfo_Value(tr,'B_PHASE') == 1 then
          xywh.y = obj.sections[5072].y
          local bc = -8
          GUI_DrawButton(gui, 'Ø', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)
        end
      end

      if reaper.GetMediaTrackInfo_Value(tr,'B_MAINSEND') == 1 then
        xywh.y = obj.sections[5075].y
        local t = 'MASTER'
        if xywh.w < 40 then
          t = 'MAST'
        end
        local bc = -8
        GUI_DrawButton(gui, t, xywh, bc, gui.skol.sb_txt_on, true, '', nil, -4)
      end

      if not master then
        xywh.h = obj.sections[5073].h
        if reaper.GetMediaTrackInfo_Value(tr,'B_MUTE') == 1 then
          xywh.y = obj.sections[5073].y
          local bc = -2
          GUI_DrawButton(gui, 'M', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)
        end

        if reaper.GetMediaTrackInfo_Value(tr,'I_SOLO') > 0 then
          xywh.y = obj.sections[5074].y
          local bc = -9
          GUI_DrawButton(gui, 'S', xywh, bc, gui.skol.sb_txt_on, true, '', nil, -2)
        end
      end
      
    end

    gfx.dest = 1

    return x-math.floor(o5025.w/2), tb2

    --gfx.dest = 1
  end

  function GUI_DrawMixerChannel2(obj, gui, tb)
    gfx.dest = 954
    local tb2 = tb-lvar.trbtns_offs
    local o5028 = obj.sections[5028]
    local o5026 = obj.sections[5026]
    local o5025 = obj.sections[5025]
    local xx = math.floor(((tb2-1)*(o5025.w+10)))
    local x = math.floor(xx + o5026.x + o5026.w/2)

    local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
    local master
    local tr = GetTrack(dm_trackbtns[tb].trn)
    if tr then
      if GetTrackGUID(tr) ~= dm_trackbtns[tb].guid and dm_trackbtns[tb].trn ~= -1 then
        tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtns[tb].guid)
        if tr then
          dm_trackbtns[tb].trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
        end
      end
    end
    if tr then

      local r, vol, pan = trctls_table[1].funcget(tr)
      local v = normalize(trctls_table[1].min,trctls_table[1].max,vol or 0)
      v = ctlScaleInv(lvar.trmix_vscale, v)
      local p = normalize(trctls_table[2].min,trctls_table[2].max,pan or 0)

      local sk_w, sk_h = skin.sliderknb_w, skin.sliderknb_h
      local rk_w = skin.rotknb_w

      local y = math.floor(o5026.y+o5026.h - (v*o5026.h))

      local py = o5028.y

      local xywh = {x = xx+o5026.x, y = o5026.y-35, w = o5026.w, h = 10}
      local bx = xx + o5026.x
      local by = o5028.y
      local bw = o5026.w
      local bh = o5025.h - o5028.y

      gfx.a = 1
      gfx.mode = 2
      gfx.blit(959,1,0,bx,by,bw,bh, bx, by)
      gfx.mode = gmode

      local t = reaper.mkvolstr('', vol)
      GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)
      xywh.y = xywh.y - 15
      t = reaper.mkpanstr('', pan)
      GUI_Str(gui,xywh,t,5,'160 160 160',-2 + gui.fontsz.sb,1,gui.skol.sb_shad,gui.fontnm.sb,98)

      f_Get_SSV('128 128 128')
      gfx.rect(x, o5026.y,2,o5026.h,0)
      gfx.blit(skin.sliderknb,1,0,0,0,sk_w,sk_h,x-math.floor(sk_w/2),y-math.floor(sk_h/2))

      local frames = (skin.rotknb_h/skin.rotknb_w)-1
      gfx.blit(skin.rotknb,1,0,0,rk_w*math.floor(p*frames),rk_w,rk_w,x-math.floor(rk_w/2),py)

      dm_trackbtns[tb].vol = vol
      dm_trackbtns[tb].vol_normscale = v
      dm_trackbtns[tb].pan = pan
      dm_trackbtns[tb].pan_norm = p

      gfx.dest = 1

    end

    gfx.dest = 1

    return x-math.floor(o5025.w/2), tb2

  end

  function DrawMD(gui, obj)
    gfx.dest = -1
    gfx.a = 1
    f_Get_SSV('0 0 255')
    gfx.rect(0,0,5,5,1)
    gfx.update()
    gfx.dest = 1
  end

  function GUI_DrawXXYSnaps(gui, obj)
    gfx.dest = 1006

    gfx.a=1
    f_Get_SSV(gui.skol.ss_bg)
    gfx.rect(0,
             0,
             obj.sections[221].w,
             obj.sections[221].h, 1, 1)
    f_Get_SSV('64 64 64')
    gfx.rect(0,
             0,
             obj.sections[221].w,
             obj.sections[221].h, 0, 1)

    xywh = {x = 0,
            y = 0,
            w = obj.sections[221].w,
            h = butt_h}

    GUI_DrawBar(gui,lvar.xxymode_table[xxymode+1],xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

    --GUI_textC(gui,xywh,lvar.xxymode_table[xxymode+1],gui.color.black,-2)

    if xxymode == 0 then
      local sstypestr = 'PAGE'
      if sstype_select > 1 then
        if tracks[track_select] and tracks[track_select].strip and snapshots[tracks[track_select].strip] and
           snapshots[tracks[track_select].strip][page][sstype_select] then
          sstypestr = snapshots[tracks[track_select].strip][page][sstype_select].subsetname
        else
          sstypestr = ''
        end
      end

      GUI_DrawButton(gui, sstypestr, obj.sections[226], gui.color.white, gui.skol.sb_txt_on, true, '', nil, gui.fontsz.sb)
      GUI_DrawSliderH(gui, 'GRAVITY', obj.sections[225], gui.color.black, gui.color.white, ((xxy_gravity-1)/3))

      local strip = tracks[track_select].strip
      local xywh = {x = obj.sections[232].x,
                    y = obj.sections[232].y - obj.sections[232].h,
                    w = obj.sections[232].w,
                    h = obj.sections[232].h}
      GUI_textC(gui,xywh,'AUTOMATION',gui.color.white,-2)
      if xxy and xxy[strip] and xxy[strip][page][sstype_select] and xxy[strip][page][sstype_select].xfader then
        GUI_DrawButton(gui, 'FADER '..string.format('%i',xxy[strip][page][sstype_select].xfader), obj.sections[232], gui.color.white, gui.color.black, true, 'X', false)
      else
        GUI_DrawButton(gui, 'NONE', obj.sections[232], -3, gui.color.black, false, 'X', false)
      end
      if xxy and xxy[strip] and xxy[strip][page][sstype_select] and xxy[strip][page][sstype_select].yfader then
        GUI_DrawButton(gui, 'FADER '..string.format('%i',xxy[strip][page][sstype_select].yfader), obj.sections[233], gui.color.white, gui.color.black, true, 'Y', false)
      else
        GUI_DrawButton(gui, 'NONE', obj.sections[233], -3, gui.color.black, true, 'Y', false)
      end
      local txt = 'RECORD MODE OFF'
      local bt = gui.color.white

      if xxyrecord then
        txt = 'RECORD MODE ON'
        bt = -2
      end
      GUI_DrawButton(gui, txt, obj.sections[235], bt, gui.skol.sb_txt_on, true, '', false)

      local bc, bc2 = gui.color.white, gui.color.white
      if sstype_select == 1 then
        bc = '64 64 64'
        bc2 = '64 64 64'
      elseif snaplrn_mode then
        bc = '255 0 0'
      end

      xywh = {x = obj.sections[223].x,
              y = obj.sections[223].y,
              w = obj.sections[223].w,
              h = obj.sections[223].h}
      f_Get_SSV('64 64 64')
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 0 )


      xywh.h = butt_h
      GUI_DrawBar(gui,'',xywh,skin.barUD,true,gui.color.black,nil,-2)
      gfx.line(xywh.x+xywh.w/2,xywh.y,xywh.x+xywh.w/2,xywh.y+xywh.h)
      local w, h = gfx.getimgdim(skin.arrowup)
      gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/4-w/2,xywh.y+xywh.h/2-h/2)
      gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.75-w/2,xywh.y+xywh.h/2-h/2)

      gfx.a = 1

      SSXXY_butt_cnt = math.floor(obj.sections[223].h / butt_h) - 1
      --if snaplrn_mode == false then

        local strip = tracks[track_select].strip
        if strip and snapshots and snapshots[strip] and snapshots[strip][page][sstype_select] then

          if sstype_select == 1 then
            if #snapshots[strip][page][sstype_select] > 0 then
              for i = 1,SSXXY_butt_cnt do

                xywh.y = obj.sections[223].y + i*butt_h
                local c = gui.skol.ss_txt
                if ss_select == xxylist_offset+i then
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   xywh.h, 1 )
                  c = gui.color.black
                end
                if snapshots[strip][page][sstype_select][i+xxylist_offset] then
                  GUI_textsm_LJ(gui,xywh,roundX(i+xxylist_offset,0)..': '..snapshots[strip][page][sstype_select][i+xxylist_offset].name,c,-2,xywh.w)
                end

              end

            end
          elseif sstype_select > 1 then
            if #snapshots[strip][page][sstype_select].snapshot > 0 then
              for i = 1,SSXXY_butt_cnt do

                xywh.y = obj.sections[223].y + i*butt_h
                local c = gui.skol.ss_txt
                if ss_select == xxylist_offset+i then
                  f_Get_SSV(gui.color.white)
                  gfx.rect(xywh.x,
                   xywh.y,
                   xywh.w,
                   xywh.h, 1 )
                  c = gui.color.black
                end
                if snapshots[strip][page][sstype_select].snapshot[i+xxylist_offset] then
                  GUI_textsm_LJ(gui,xywh,roundX(i+xxylist_offset,0)..': '..snapshots[strip][page][sstype_select].snapshot[i+xxylist_offset].name,c,-2,xywh.w)
                end

              end

            end

          end

        end

    elseif xxymode == 1 then

      local bar = gui.color.white
      if xxypath_edit == true then
        bar = -4
      end
      GUI_DrawButton(gui, 'EDIT', obj.sections[227], bar, gui.skol.sb_txt_on, true, '', false)
      GUI_DrawButton(gui, 'SAVE META PATH', obj.sections[228], gui.color.white, gui.skol.sb_txt_on, true, '', false, gui.fontsz.sb)
      GUI_DrawButton(gui, 'LOAD META PATH', obj.sections[229], gui.color.white, gui.skol.sb_txt_on, true, '', false, gui.fontsz.sb)

      local strip = tracks[track_select].strip
      local xywh = {x = obj.sections[231].x,
                    y = obj.sections[231].y - obj.sections[231].h,
                    w = obj.sections[231].w,
                    h = obj.sections[231].h}
      GUI_textC(gui,xywh,'AUTOMATION',gui.color.white,-2)
      if xxy and xxy[strip] and xxy[strip][page][sstype_select] and xxy[strip][page][sstype_select].pathfader then
        GUI_DrawButton(gui, 'FADER '..string.format('%i',xxy[strip][page][sstype_select].pathfader), obj.sections[231], gui.color.white, gui.color.black, true, '', false)
      else
        GUI_DrawButton(gui, 'NONE', obj.sections[231], -3, gui.color.black, false, '', false)
      end
      local txt = 'RECORD MODE OFF'
      local bar = gui.color.white
      if xxyrecord then
        txt = 'RECORD MODE ON'
        bar = -2
      end
      GUI_DrawButton(gui, txt, obj.sections[235], bar, gui.skol.sb_txt_on, true, '', false)

    end

    gfx.dest = 1

  end

  function GUI_DrawXXYSSLabels(gui, obj)

    gfx.dest = 1
    gfx.a=1

    local strip = tracks[track_select].strip
    if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
      if #xxy[strip][page][sstype_select].points > 0 then
        for p = 1, #xxy[strip][page][sstype_select].points do
          local x,y = xxy[strip][page][sstype_select].points[p].x, xxy[strip][page][sstype_select].points[p].y
          x = obj.sections[220].x + x*obj.sections[220].w
          y = obj.sections[220].y + y*obj.sections[220].h
          local xywh = {x = x, y = y-butt_h, w = 1, h = 1}
          local sstxt = snapshots[strip][page][sstype_select].snapshot[xxy[strip][page][sstype_select].points[p].ss].name
          local c = gui.color.white
          local dist = xxy[strip][page][sstype_select].points[p].distance
          local dfnd = false
          if dist then
            local gx = 0
            if tostring(dist) == tostring(xxy_mindist) then
              gx = F_limit((192-dist*1000),0,255)
              dfnd = true
            end
            dist = (dist^(1/(xxy_gravity)))^(5-xxy_gravity)
            local rx = F_limit(255-(dist*800),0,255)
            local bx = F_limit((dist*1000),0,255)
            c = rx..' '..gx..' '..bx
          end
          local alpha = 1
          if xxy[strip][page][sstype_select].points[p].inactive == true then
            alpha = 0.2
            c = '128 128 128'
          end
          --f_Get_SSV(gui.color.black)
          --gfx.rect(xywh.x,xywh.y,xywh.w,xywh.h,1)
          GUI_textC(gui,xywh,sstxt,c,-2,alpha)
        end
      end
    end
    gfx.a = 1
  end

  function GUI_DrawXXY(gui, obj)

    gfx.dest = 1007
    gfx.a=1

    --gfx.a=0.5
    f_Get_SSV(gui.color.black)
    gfx.rect(0,
             0,
             obj.sections[220].w,
             obj.sections[220].h, 1, 1)

    --gfx.a=1
    f_Get_SSV(gui.color.white)
    gfx.rect(0,
             0,
             obj.sections[220].w,
             obj.sections[220].h, 0, 1)

    local ppw, pph = gfx.getimgdim(def_xytarget)

    local strip = tracks[track_select].strip
    if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
      if #xxy[strip][page][sstype_select].points > 0 then
        for p = 1, #xxy[strip][page][sstype_select].points do
          local x,y = xxy[strip][page][sstype_select].points[p].x, xxy[strip][page][sstype_select].points[p].y
          x = x*obj.sections[220].w
          y = y*obj.sections[220].h
          if xxy[strip][page][sstype_select].points[p].inactive == true then
            gfx.a = 0.2
          else
            gfx.a = 1
          end
          gfx.blit(def_xytarget,1,0, 0, 0, ppw, pph, x-ppw/2, y-pph/2)
        end
      end
    end
    gfx.a = 1
    --if xxymode == 1 then

      if xxypath[xxypath_select] then
        local pcnt = #xxypath[xxypath_select].points
        if pcnt > 1 then

          --yyy
          for p = 1, pcnt-1 do
            draw_curve(xxypath[xxypath_select].points[p].x, xxypath[xxypath_select].points[p].y, p, pcnt-1)
          end

        elseif pcnt == 1 then

          draw_curve(xxypath[xxypath_select].points[pcnt].x, xxypath[xxypath_select].points[pcnt].y, p, 1)

        end

      end
    --end

    gfx.dest = 1

  end

  function GUI_DrawCBox(gui, obj)
    gfx.dest = 981

    if lupd.update_gfx or resize_display then
      --gfx.setimgdim(981,-1,-1)
      --gfx.setimgdim(981,obj.sections[3000].w,obj.sections[3000].h)
      Img_SetDim(981,obj.sections[3000].w,obj.sections[3000].h)
    end

    gfx.a = 1
    local tscale = 0
    if noscale ~= true then
      tscale = tb_fontscale
    end

    local pcol = '128 128 128'

    local xywh = {x = 0, y = 0, w = obj.sections[3000].w, h = obj.sections[3000].h}
    GUI_DrawBar(gui, '', xywh, skin.barG,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb, nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
    f_Get_SSV(gui.color.black)
    gfx.line(0,0,xywh.w,1)
    local gscol = gui.skol.pnl_txt
    if settings_gridsize == 1 then
      gscol = '96 96 96'
    end
    GUI_DrawButton(gui, string.format('%i', ogrid), obj.sections[3001], -6, gscol, true, 'GRID', nil, nil, nil, nil, pcol)

    if (lvar.locky or false) == true then
      gfx.a = 0.3
    end
    gfx.blit(skin.cp_lockx,1,0,0,0,24,24,obj.sections[3106].x,obj.sections[3106].y,obj.sections[3106].w,obj.sections[3106].h)
    gfx.a = 1
    if (lvar.lockx or false) == true then
      gfx.a = 0.3
    end
    gfx.blit(skin.cp_locky,1,0,0,0,24,24,obj.sections[3107].x,obj.sections[3107].y,obj.sections[3107].w,obj.sections[3107].h)

    if undo.max > 0 then
      gfx.a = 0.3
      if undo_pos > 0 then
        gfx.a = 1
      end
      gfx.blit(skin.cp_undo,1,0,0,0,24,24,obj.sections[3108].x,obj.sections[3108].y,obj.sections[3108].w,obj.sections[3108].h)

      gfx.a = 0.3
      if undo_pos < #undo then
        gfx.a = 1
      end
      gfx.blit(skin.cp_redo,1,0,0,0,24,24,obj.sections[3109].x,obj.sections[3109].y,obj.sections[3109].w,obj.sections[3109].h)
    end
    gfx.a = 1

    if submode == 0 then
      if (ctl_select and #ctl_select > 0) then

        gfx.blit(skin.cp_aligntop,1,0,0,0,24,24,obj.sections[3100].x,obj.sections[3100].y,obj.sections[3100].w,obj.sections[3100].h)
        gfx.blit(skin.cp_alignbottom,1,0,0,0,24,24,obj.sections[3110].x,obj.sections[3110].y,obj.sections[3110].w,obj.sections[3110].h)
        gfx.blit(skin.cp_alignleft,1,0,0,0,24,24,obj.sections[3101].x,obj.sections[3101].y,obj.sections[3101].w,obj.sections[3101].h)
        gfx.blit(skin.cp_alignright,1,0,0,0,24,24,obj.sections[3111].x,obj.sections[3111].y,obj.sections[3111].w,obj.sections[3111].h)
        gfx.blit(skin.cp_aligncentreh,1,0,0,0,24,24,obj.sections[3112].x,obj.sections[3112].y,obj.sections[3112].w,obj.sections[3112].h)
        gfx.blit(skin.cp_aligncentrev,1,0,0,0,24,24,obj.sections[3113].x,obj.sections[3113].y,obj.sections[3113].w,obj.sections[3113].h)
        gfx.blit(skin.cp_distv,1,0,0,0,24,24,obj.sections[3102].x,obj.sections[3102].y,obj.sections[3102].w,obj.sections[3102].h)
        gfx.blit(skin.cp_disth,1,0,0,0,24,24,obj.sections[3103].x,obj.sections[3103].y,obj.sections[3103].w,obj.sections[3103].h)
        gfx.blit(skin.cp_copy,1,0,0,0,24,24,obj.sections[3104].x,obj.sections[3104].y,obj.sections[3104].w,obj.sections[3104].h)
        if copy_ctls == nil then
          gfx.a = 0.3
        end
        gfx.blit(skin.cp_paste,1,0,0,0,24,24,obj.sections[3105].x,obj.sections[3105].y,obj.sections[3105].w,obj.sections[3105].h)
        gfx.a = 1
        local c = lvar.ctlpreview_sel
        if not c then
          c = ctl_select[1].ctl
        end
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        if ctl then
          GUI_DrawButton(gui, round(ctl.scale,4), obj.sections[3002], -6, gui.skol.pnl_txt, true, 'SCALE', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.xsc)), obj.sections[3003], -6, gui.skol.pnl_txt, true, 'X', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.ysc)), obj.sections[3004], -6, gui.skol.pnl_txt, true, 'Y', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.wsc)), obj.sections[3005], -6, gui.skol.pnl_txt, true, 'W', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.ctl_info.cellh * ctl.scale)), obj.sections[3006], -6, gui.skol.pnl_txt, true, 'H', nil, nil, nil, nil, pcol)
        end
      else
        gfx.a = 0.3
        gfx.blit(skin.cp_aligntop,1,0,0,0,24,24,obj.sections[3100].x,obj.sections[3100].y,obj.sections[3100].w,obj.sections[3100].h)
        gfx.blit(skin.cp_alignbottom,1,0,0,0,24,24,obj.sections[3110].x,obj.sections[3110].y,obj.sections[3110].w,obj.sections[3110].h)
        gfx.blit(skin.cp_alignleft,1,0,0,0,24,24,obj.sections[3101].x,obj.sections[3101].y,obj.sections[3101].w,obj.sections[3101].h)
        gfx.blit(skin.cp_alignright,1,0,0,0,24,24,obj.sections[3111].x,obj.sections[3111].y,obj.sections[3111].w,obj.sections[3111].h)
        gfx.blit(skin.cp_aligncentreh,1,0,0,0,24,24,obj.sections[3112].x,obj.sections[3112].y,obj.sections[3112].w,obj.sections[3112].h)
        gfx.blit(skin.cp_aligncentrev,1,0,0,0,24,24,obj.sections[3113].x,obj.sections[3113].y,obj.sections[3113].w,obj.sections[3113].h)
        gfx.blit(skin.cp_distv,1,0,0,0,24,24,obj.sections[3102].x,obj.sections[3102].y,obj.sections[3102].w,obj.sections[3102].h)
        gfx.blit(skin.cp_disth,1,0,0,0,24,24,obj.sections[3103].x,obj.sections[3103].y,obj.sections[3103].w,obj.sections[3103].h)
        gfx.blit(skin.cp_copy,1,0,0,0,24,24,obj.sections[3104].x,obj.sections[3104].y,obj.sections[3104].w,obj.sections[3104].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3106].x,obj.sections[3106].y,obj.sections[3106].w,obj.sections[3106].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3107].x,obj.sections[3107].y,obj.sections[3107].w,obj.sections[3107].h)
        --gfx.blit(skin.cp_undo,1,0,0,0,24,24,obj.sections[3108].x,obj.sections[3108].y,obj.sections[3108].w,obj.sections[3108].h)
        --gfx.blit(skin.cp_redo,1,0,0,0,24,24,obj.sections[3109].x,obj.sections[3109].y,obj.sections[3109].w,obj.sections[3109].h)

        GUI_DrawButton(gui, '-', obj.sections[3002], -6, gui.skol.pnl_txt, true, 'SCALE', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3003], -6, gui.skol.pnl_txt, true, 'X', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3004], -6, gui.skol.pnl_txt, true, 'Y', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3005], -6, gui.skol.pnl_txt, true, 'W', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3006], -6, gui.skol.pnl_txt, true, 'H', nil, nil, nil, nil, pcol)

        gfx.a = 0.3
        if copy_ctls ~= nil then
          gfx.a = 1
        end
        gfx.blit(skin.cp_paste,1,0,0,0,24,24,obj.sections[3105].x,obj.sections[3105].y,obj.sections[3105].w,obj.sections[3105].h)

      end
    elseif submode == 1 then

      if (gfx4_select and #gfx4_select > 0) then

        gfx.blit(skin.cp_aligntop,1,0,0,0,24,24,obj.sections[3100].x,obj.sections[3100].y,obj.sections[3100].w,obj.sections[3100].h)
        gfx.blit(skin.cp_alignbottom,1,0,0,0,24,24,obj.sections[3110].x,obj.sections[3110].y,obj.sections[3110].w,obj.sections[3110].h)
        gfx.blit(skin.cp_alignleft,1,0,0,0,24,24,obj.sections[3101].x,obj.sections[3101].y,obj.sections[3101].w,obj.sections[3101].h)
        gfx.blit(skin.cp_alignright,1,0,0,0,24,24,obj.sections[3111].x,obj.sections[3111].y,obj.sections[3111].w,obj.sections[3111].h)
        gfx.blit(skin.cp_aligncentreh,1,0,0,0,24,24,obj.sections[3112].x,obj.sections[3112].y,obj.sections[3112].w,obj.sections[3112].h)
        gfx.blit(skin.cp_aligncentrev,1,0,0,0,24,24,obj.sections[3113].x,obj.sections[3113].y,obj.sections[3113].w,obj.sections[3113].h)
        gfx.blit(skin.cp_distv,1,0,0,0,24,24,obj.sections[3102].x,obj.sections[3102].y,obj.sections[3102].w,obj.sections[3102].h)
        gfx.blit(skin.cp_disth,1,0,0,0,24,24,obj.sections[3103].x,obj.sections[3103].y,obj.sections[3103].w,obj.sections[3103].h)
        gfx.blit(skin.cp_copy,1,0,0,0,24,24,obj.sections[3104].x,obj.sections[3104].y,obj.sections[3104].w,obj.sections[3104].h)
        if copy_ctls == nil then
          gfx.a = 0.3
        end
        gfx.blit(skin.cp_paste,1,0,0,0,24,24,obj.sections[3105].x,obj.sections[3105].y,obj.sections[3105].w,obj.sections[3105].h)
        --gfx.a = 0.3
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3108].x,obj.sections[3108].y,obj.sections[3108].w,obj.sections[3108].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3109].x,obj.sections[3109].y,obj.sections[3109].w,obj.sections[3109].h)
        gfx.a = 1
        local c = lvar.gfxpreview_sel
        if not c then
          c = gfx4_select[1]
        end
        local ctl = strips[tracks[track_select].strip][page].graphics[c]
        if ctl then
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.x)), obj.sections[3003], -6, gui.skol.pnl_txt, true, 'X', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.y)), obj.sections[3004], -6, gui.skol.pnl_txt, true, 'Y', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.stretchw)), obj.sections[3005], -6, gui.skol.pnl_txt, true, 'W', nil, nil, nil, nil, pcol)
          GUI_DrawButton(gui, string.format('%i',math.floor(ctl.stretchh)), obj.sections[3006], -6, gui.skol.pnl_txt, true, 'H', nil, nil, nil, nil, pcol)
        end
      else
        gfx.a = 0.3
        gfx.blit(skin.cp_aligntop,1,0,0,0,24,24,obj.sections[3100].x,obj.sections[3100].y,obj.sections[3100].w,obj.sections[3100].h)
        gfx.blit(skin.cp_alignbottom,1,0,0,0,24,24,obj.sections[3110].x,obj.sections[3110].y,obj.sections[3110].w,obj.sections[3110].h)
        gfx.blit(skin.cp_alignleft,1,0,0,0,24,24,obj.sections[3101].x,obj.sections[3101].y,obj.sections[3101].w,obj.sections[3101].h)
        gfx.blit(skin.cp_alignright,1,0,0,0,24,24,obj.sections[3111].x,obj.sections[3111].y,obj.sections[3111].w,obj.sections[3111].h)
        gfx.blit(skin.cp_aligncentreh,1,0,0,0,24,24,obj.sections[3112].x,obj.sections[3112].y,obj.sections[3112].w,obj.sections[3112].h)
        gfx.blit(skin.cp_aligncentrev,1,0,0,0,24,24,obj.sections[3113].x,obj.sections[3113].y,obj.sections[3113].w,obj.sections[3113].h)
        gfx.blit(skin.cp_distv,1,0,0,0,24,24,obj.sections[3102].x,obj.sections[3102].y,obj.sections[3102].w,obj.sections[3102].h)
        gfx.blit(skin.cp_disth,1,0,0,0,24,24,obj.sections[3103].x,obj.sections[3103].y,obj.sections[3103].w,obj.sections[3103].h)
        gfx.blit(skin.cp_copy,1,0,0,0,24,24,obj.sections[3104].x,obj.sections[3104].y,obj.sections[3104].w,obj.sections[3104].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3106].x,obj.sections[3106].y,obj.sections[3106].w,obj.sections[3106].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3107].x,obj.sections[3107].y,obj.sections[3107].w,obj.sections[3107].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3108].x,obj.sections[3108].y,obj.sections[3108].w,obj.sections[3108].h)
        --gfx.blit(skin.cp_blank,1,0,0,0,24,24,obj.sections[3109].x,obj.sections[3109].y,obj.sections[3109].w,obj.sections[3109].h)

        GUI_DrawButton(gui, '-', obj.sections[3003], -6, gui.skol.pnl_txt, true, 'X', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3004], -6, gui.skol.pnl_txt, true, 'Y', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3005], -6, gui.skol.pnl_txt, true, 'W', nil, nil, nil, nil, pcol)
        GUI_DrawButton(gui, '-', obj.sections[3006], -6, gui.skol.pnl_txt, true, 'H', nil, nil, nil, nil, pcol)

        gfx.a = 0.3
        if copy_ctls ~= nil then
          gfx.a = 1
        end
        gfx.blit(skin.cp_paste,1,0,0,0,24,24,obj.sections[3105].x,obj.sections[3105].y,obj.sections[3105].w,obj.sections[3105].h)

      end


    end

    gfx.a = 1
    gfx.dest = 1

  end

  function GUI_DrawTopBarMin(gui, obj)

    if not settings_showminimaltopbar then return end

    local xywh = {x = obj.sections[18].x,
                  y = obj.sections[18].y,
                  w = obj.sections[18].w,
                  h = obj.sections[18].h}
    gfx.a = 0.6
    if mode == 0 then
      if show_editbar then
        GUI_DrawBar(gui,'<',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontflag.sb)
      else
        GUI_DrawBar(gui,'>',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontflag.sb)
      end
    else
      GUI_DrawBar(gui,'<>',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontflag.sb)
    end
    gfx.line(obj.sections[18].x+obj.sections[18].w,obj.sections[18].y,obj.sections[18].x+obj.sections[18].w,obj.sections[18].y+obj.sections[18].h-1)
    gfx.line(obj.sections[18].x,obj.sections[18].y+obj.sections[18].h-1,obj.sections[18].x+obj.sections[18].w,obj.sections[18].y+obj.sections[18].h-1)

    if show_eqcontrol ~= true and macro_edit_mode ~= true then
      gfx.a = 0.6
      GUI_DrawBar(gui,'...',obj.sections[21],skin.bar,true,gui.skol.sb_txt_on,nil,-2,nil,gui.skol.sb_shad,gui.fontflag.sb)
      gfx.line(obj.sections[21].x-1,obj.sections[21].y,obj.sections[21].x-1,obj.sections[21].y+obj.sections[21].h-1)
      gfx.line(obj.sections[21].x,obj.sections[21].y+obj.sections[21].h-1,obj.sections[21].x+obj.sections[21].w,obj.sections[21].y+obj.sections[21].h-1)
    end
    gfx.dest = 1
  end

  function GUI_DrawTopBar(gui, obj)

    gfx.dest = 999
    if topbarheight == 0 then GUI_DrawTopBarMin(gui, obj) return end

    gfx.a=1
    f_Get_SSV(gui.color.black)
    local w, h = gfx.getimgdim(999)
    gfx.rect(0,0,w,h,1)

    local tscale = 0
    if noscale ~= true then
      tscale = tb_fontscale
    end

    local xywh = {x = obj.sections[18].x,
                  y = obj.sections[18].y,
                  w = obj.sections[18].w,
                  h = obj.sections[18].h}
    GUI_DrawBar(gui,'',obj.sections[12],skin.bar,true,gui.skol.sb_txt_on,nil,-2)

    if xywh.w > 0 then
      GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb)
    end
    if mode == 0 then
      if show_editbar then
        GUI_DrawBar(gui,'<',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad)
      else
        GUI_DrawBar(gui,'>',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad)
      end
    else
      GUI_DrawBar(gui,'<>',obj.sections[18],skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb,nil,gui.skol.sb_shad)
    end
    --[[if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,obj.sections[18].x,obj.sections[18].y)
    end ]]

    local t
    if c == gui.color.black then
      f_Get_SSV(gui.color.black)
      gfx.rect(obj.sections[20].x,obj.sections[20].y,obj.sections[20].w,obj.sections[20].h,1)
    end
    for i = 0, 3 do
      local xywh = {x = obj.sections[20].x + i*(obj.sections[20].w/4),
                    y = obj.sections[20].y,
                    w = obj.sections[20].w/4-1,
                    h = obj.sections[20].h}
      if i == 0 and lockx == false then
        GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.color.black,nil,-2)
        f_Get_SSV(gui.color.white)
        c = gui.skol.sb_txt_on
        t = 'X'
      elseif i == 0 then
        f_Get_SSV(gui.color.black)
        c = gui.skol.sb_txt_off
        t = 'X'
      elseif i == 1 and locky == false then
        GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.color.black,nil,-2)
        f_Get_SSV(gui.color.white)
        c = gui.skol.sb_txt_on
        t = 'Y'
      elseif i == 1 then
        f_Get_SSV(gui.color.black)
        c = gui.skol.sb_txt_off
        t = 'Y'
      elseif i == 2 then
        GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.color.black,nil,-2)
        f_Get_SSV(gui.color.white)
        c = gui.skol.sb_txt_on
        t = ''
      elseif i == 3 then
        GUI_DrawBar(gui,'',xywh,skin.bar,true,gui.color.black,nil,-2)
        f_Get_SSV(gui.color.white)
        c = gui.skol.sb_txt_on
        t = ''
      end

      --GUI_textC_shadow(gui,xywh,t,c,-2 + gui.fontsz.sb,1,0,gui.skol.sb_shad,98)
      GUI_Str(gui,xywh,t,5,c,-2 + gui.fontsz.sb + tscale,1,gui.skol.sb_shad,gui.fontnm.sb,98)
      if i == 2 then
        local w, h = gfx.getimgdim(skin.arrowup)
        gfx.blit(skin.arrowup,1,0,0,0,w,h,xywh.x+xywh.w/2-w/2,xywh.y+xywh.h/2-h/2)
        --gfx.triangle(xywh.x+xywh.w/2,xywh.y+6,xywh.x+xywh.w/2-4,xywh.y+xywh.h-6,xywh.x+xywh.w/2+4,xywh.y+xywh.h-6,1)
      elseif i == 3 then
        --gfx.triangle(xywh.x+xywh.w/2,xywh.y+xywh.h-6,xywh.x+xywh.w/2-4,xywh.y+6,xywh.x+xywh.w/2+4,xywh.y+6,1)
        local w, h = gfx.getimgdim(skin.arrowup)
        gfx.blit(skin.arrowdn,1,0,0,0,w,h,xywh.x+xywh.w*0.5-w/2,xywh.y+xywh.h*0.5-h/2)
      end
    end

    if obj.sections[12].w > 0 then
      if infomsg ~= nil then
        --GUI_textC_LIM(gui,obj.sections[12],infomsg,gui.skol.sb_txt_on,-2 + gui.fontsz.sb,gui.skol.sb_shad,98,gui.fontnm.sb,5)
        GUI_Str(gui,obj.sections[12],infomsg,5,gui.skol.sb_txt_on,-2 + gui.fontsz.sb + tscale,1,gui.skol.sb_shad,gui.fontnm.sb,98)

        infomsg = nil
      elseif tracks and tracks[track_select] then
        local trn = tracks[track_select].name
        if trn == LBX_GTRACK_NAME then
          trn = '[LBX GLOBAL]'
        elseif trn == LBX_CTL_TRNAME then
          trn = '[LBX CTL]'
        elseif trn == '' then
          trn = '[unnamed track]'
        end
        --GUI_textC_LIM(gui,obj.sections[12],GetProjectName()..' - '..STRIPSET..' - TRACK: ' .. tracks[track_select].tracknum+1 .. ' - '.. trn,gui.skol.sb_txt_on,-2 + gui.fontsz.sb,gui.skol.sb_shad,98,gui.fontnm.sb,5)
        GUI_Str(gui,obj.sections[12],GetProjectName()..' - '..lvar.STRIPSET..' - TRACK: ' .. tracks[track_select].tracknum+1 .. ' - '.. trn,5,gui.skol.sb_txt_on,-2 + gui.fontsz.sb + tscale,1,gui.skol.sb_shad,gui.fontnm.sb,98)
      end
    end

    local xywh = {x = obj.sections[21].x-1,
                  y = obj.sections[1000].y,
                  w = obj.sections[21].w+obj.sections[1000].w+obj.sections[14].w,
                  h = obj.sections[1000].h}
    f_Get_SSV(gui.color.black)
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1, 1)

    GUI_DrawBar(gui,'...',obj.sections[21],skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb)
    if obj.sections[17].x > obj.sections[20].x+obj.sections[20].w then
      local sb = skin.bar
      if g_savedirty then
        sb = skin.barR
      else
      end
      GUI_DrawBar(gui,'SAVE',obj.sections[17],sb,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb, nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)
      f_Get_SSV(gui.color.black)
      gfx.line(obj.sections[17].x,obj.sections[17].y,obj.sections[17].x,obj.sections[17].y+obj.sections[17].h)
    else
    end

    local gflag = false
    local c
    local xywh = {x = obj.sections[1000].x+2,
                  y = obj.sections[1000].y,
                  w = obj.sections[1000].w-1,
                  h = obj.sections[1000].h}
    if gpage == true or track_select == LBX_GTRACK then
      f_Get_SSV(gui.color.white)
      GUI_DrawBar(gui,'GLOBAL',xywh,skin.barR,true,gui.skol.sb_txt_on,nil,-5 + gui.fontsz.sb, nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb, true)
      gflag = true
    else
      c = gui.skol.sb_txt_off
      --GUI_textC(gui,xywh,'GLOBAL',c,-5 + gui.fontsz.sb)
      GUI_Str(gui,xywh,'GLOBAL',5,c,-5 + gui.fontsz.sb,1,nil,gui.fontnm.sb,98)
    end
    for i = 0, lvar.maxpage-1 do
      local xywh = {x = obj.sections[14].x+2 + i*(obj.sections[14].w/lvar.maxpage),
                    y = obj.sections[14].y,
                    w = math.floor(obj.sections[14].w/lvar.maxpage-2),
                    h = obj.sections[14].h}
      if gpage == false and page == i+1 and gflag == false then
        f_Get_SSV(gui.color.white)
        GUI_DrawBar(gui,i+1,xywh,skin.bar,true,gui.skol.sb_txt_on,nil,-2 + gui.fontsz.sb, nil,gui.skol.sb_shad,gui.fontnm.sb,gui.fontflag.sb)

      else
        f_Get_SSV(gui.color.black)
        c = gui.skol.sb_txt_off
        --[[gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1, 1)]]
        GUI_textC(gui,xywh,i+1,c,-2 + gui.fontsz.sb + tscale)
      end
    end


  end

  function GUI_DrawBars(gui, obj)

    local ww = gfx1.main_w - (plist_w)
    local bw = F_limit((obj.sections[10].w / surface_size.w),0,1)*(ww-4)
    local bx = F_limit(F_limit(((surface_offset.x) / surface_size.w),0,1)*(ww-4),0,ww-4-bw)

    local hh = gfx1.main_h - (topbarheight+2)
    local bh = F_limit((obj.sections[10].h / surface_size.h),0,1)*(hh-4)
    local by = F_limit(F_limit(((surface_offset.y) / surface_size.h),0,1)*(hh-4),0,hh-4-bh)

    local xywh = {x = obj.sections[10].x,
                  y = obj.sections[10].y,
                  w = ww,
                  h = sb_size+2}
    f_Get_SSV(gui.color.black)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )

    local xywh = {x = (obj.sections[10].x),
                  y = (obj.sections[10].y),
                  w = sb_size+4,
                  h = hh}
    f_Get_SSV(gui.color.black)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )

    local xywh = {x = obj.sections[10].x+obj.sections[10].w,
                      y = obj.sections[10].y,
                      w = 5,
                      h = hh}
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )

    local xywh = {x = obj.sections[10].x,
                      y = obj.sections[10].y+obj.sections[10].h,
                      w = ww,
                      h = 5}
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )



    local xywh = {x = (obj.sections[10].x+2)+2 +bx,
                  y = obj.sections[10].y,
                  w = bw,
                  h = sb_size}
    f_Get_SSV(gui.color.white)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )

    local xywh = {x = (obj.sections[10].x+2),
                  y = (obj.sections[10].y+2) + by,
                  w = sb_size,
                  h = bh}
    f_Get_SSV(gui.color.white)
    gfx.a = 1
    gfx.rect(xywh.x,
             xywh.y,
             xywh.w,
             xywh.h, 1 )
    gfx.dest = 1

  end

  function GUI_DrawSettings(gui, obj, dest)

    gfx.dest = dest or 1

    GUI_DrawPanel(obj.sections[70],true,'SETTINGS',false)

    local xywh = {x = obj.sections[70].x + 10,
                  y = obj.sections[70].y + 2,
                  w = math.floor(120*pnl_scale),
                  h = math.floor((butt_h-4)*pnl_scale)}
    local tscale = (pnl_scale-1)*fontscale
    GUI_Str(gui,xywh,'v: '..lvar.scriptver,4,gui.skol.pnl_tittxt,gui.fontsz.pnltit+tscale,1,gui.skol.pnltit_shad,gui.fontnm.pnltit,gui.fontflag.pnltit)

    f_Get_SSV(gui.skol.lst_bg)
    local ind = 6
    local x = obj.sections[70].x+ind
    local y = obj.sections[70].y+math.floor((23)*pnl_scale)+ind
    local w = obj.sections[70].w-(ind*2)
    local h = obj.sections[70].h-math.floor((23)*pnl_scale)-ind*2
    gfx.rect(x,y,w,h)
    if skin.panela_cnrbl ~= -1 then
      local pnlcnr_w, pnlcnr_h = gfx.getimgdim(skin.panela_cnrbl)
      gfx.blit(skin.panela_cnrbl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y+h-pnlcnr_h)
      gfx.blit(skin.panela_cnrbr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y+h-pnlcnr_h)
      gfx.blit(skin.panela_cnrtl,1,0,0,0,pnlcnr_w,pnlcnr_h,x,y)
      gfx.blit(skin.panela_cnrtr,1,0,0,0,pnlcnr_w,pnlcnr_h,x+w-pnlcnr_w,y)
    end

    local ww = math.floor(obj.sections[732].w / #lvar.settingspages)
    local xywh = {x = obj.sections[732].x,
                  y = obj.sections[732].y,
                  w = ww-1,
                  h = obj.sections[732].h}
    for i = 1, #lvar.settingspages do
      xywh.x = obj.sections[732].x + (i-1)*ww
      local c = -1
      if i == lvar.settingspage then
        c = -4
      end
      GUI_DrawButton(gui, lvar.settingspages[i], xywh, c, gui.color.white, true, '', true, gui.fontsz.settings-1)

    end

    gfx.dest = 990
    --gfx.setimgdim(990,-1,-1)
    --gfx.setimgdim(990,obj.sections[70].w,obj.sections[70].h)
    Img_SetDim(990,obj.sections[70].w,obj.sections[70].h)
    
    
    f_Get_SSV('0 0 0')
    gfx.a = 1
    --[[gfx.rect(0,
             0,
             obj.sections[70].w,
             obj.sections[70].h, 1)]]

    if lvar.settingspage == 1 then

      GUI_DrawTick(gui, 'Follow selected track', obj.sections[71], gui.color.white, settings_followselectedtrack, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Lock control window width', obj.sections[75], gui.color.white, lockx, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Lock control window height', obj.sections[76], gui.color.white, locky, gui.fontsz.settings)
      GUI_DrawButton(gui, lockw, obj.sections[77], -3, gui.color.black, lockx, '', true, gui.fontsz.settings)
      GUI_DrawButton(gui, lockh, obj.sections[78], -3, gui.color.black, locky, '', true, gui.fontsz.settings)

      GUI_DrawTick(gui, 'Show grid / grid size', obj.sections[80], gui.color.white, settings_showgrid, gui.fontsz.settings)
      GUI_DrawColorBox(gui, 'Grid colour', obj.sections[733], gui.color.white, lvar.gridcolor, gui.fontsz.settings)
      GUI_DrawButton(gui, ogrid, obj.sections[79], -3, gui.color.black, true, '', false, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Combine X and Y drag on control', obj.sections[735], gui.color.white, lvar.sliderxy, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Can mousewheel on knob', obj.sections[81], gui.color.white, settings_mousewheelknob, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Swap ctrl click and dbl click actions', obj.sections[82], gui.color.white, settings_swapctrlclick, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Insert default strip on every track', obj.sections[83], gui.color.white, settings_insertdefaultoneverytrack, gui.fontsz.settings)
      GUI_DrawTick(gui, '...and on every page', obj.sections[84], gui.color.white, settings_insertdefaultoneverypage, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Lock surface on new projects', obj.sections[97], gui.color.white, settings_locksurfaceonnewproject, gui.fontsz.settings)
      local t = false
      if settings_pagescrolldir == 1 then
        t = true
      end
      GUI_DrawTick(gui, 'Mousewheel scrolls page horizontally', obj.sections[719], gui.color.white, t, gui.fontsz.settings)

      --column2

      local abs, rel = GetMOFaders()
      if abs then
        GUI_DrawButton(gui, 'FADER '..abs, obj.sections[700], -1, gui.color.black, true, 'Global mouseover fader (absolute)',true, gui.fontsz.settings)
      else
        GUI_DrawButton(gui, 'NO FADER', obj.sections[700], gui.color.white, gui.color.black, false, 'Global mouseover fader (absolute)',true, gui.fontsz.settings)
      end
      GUI_DrawTick(gui, 'Show takeover bar', obj.sections[701], gui.color.white, lvar.showtakeover, gui.fontsz.settings)
      local mo = false
      if lvar.mousefadermode == 1 then
        mo = true
      end
      GUI_DrawTick(gui, 'Use encoder mode', obj.sections[734], gui.color.white, mo, gui.fontsz.settings)

      --[[if rel then
        GUI_DrawButton(gui, 'FADER '..rel, obj.sections[701], gui.color.white, gui.color.black, true, 'Global mouseover fader (relative)')
      else
        GUI_DrawButton(gui, 'NO FADER', obj.sections[701], gui.color.white, gui.color.black, false, 'Global mouseover fader (relative)')
      end]]

      GUI_DrawTick(gui, 'Send MIDI feedback on track change', obj.sections[705], gui.color.white, settings_trackchangemidi, gui.fontsz.settings)

      GUI_DrawTick(gui, 'Mouse sensitivity changes with zoom', obj.sections[707], gui.color.white, lvar.sliderzoom, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Limit mouse wheel multiplier to 1', obj.sections[708], gui.color.white, lvar.limitmw, gui.fontsz.settings)
      
      --[[GUI_DrawTick(gui, 'Autosnap strips when adding', obj.sections[707], gui.color.white, settings_stripautosnap, gui.fontsz.settings,true)
      GUI_DrawButton(gui, autosnap_rowheight, obj.sections[708], gui.color.white, gui.color.black, false, 'Autosnap row height', true, gui.fontsz.settings,true)
      GUI_DrawButton(gui, autosnap_itemgap, obj.sections[709], gui.color.white, gui.color.black, false, 'Autosnap strip item gap min', true, gui.fontsz.settings,true)
      GUI_DrawButton(gui, autosnap_itemgapmax, obj.sections[710], gui.color.white, gui.color.black, false, 'Autosnap strip item gap max', true, gui.fontsz.settings,true)
      GUI_DrawButton(gui, gallery_itemgap, obj.sections[711], gui.color.white, gui.color.black, false, 'Strip gallery item gap', true, gui.fontsz.settings,true)]]
      
      GUI_DrawTick(gui, 'Delete FX with strip', obj.sections[713], gui.color.white, settings_deletefxwithstrip, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Prevent plugin GUI opening on strip load', obj.sections[752], gui.color.white, lvar.forcestrippluginguisclosed, gui.fontsz.settings)
      GUI_DrawButton(gui, modulator_cnt, obj.sections[716], gui.color.white, gui.color.black, false, 'Modulators', true, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Simple select grouped controls', obj.sections[718], gui.color.white, settings_groupsel, gui.fontsz.settings)

      if lvar.updateravailable then
        GUI_DrawButton(gui, 'UPDATE LBX', obj.sections[727], -1, gui.color.black, true, '', true, gui.fontsz.settings)
      end


    elseif lvar.settingspage == 2 then

      GUI_DrawSliderH(gui, 'Control refresh rate', obj.sections[74], gui.color.black, gui.color.white, (1-(settings_updatefreq*10)), gui.fontsz.settings)
      GUI_DrawButton(gui, lvar.ctlupdate_rr or 'off', obj.sections[731], -3, gui.color.black, true, 'No. of controls in update round-robin', true, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Use bitmap mask control detection', obj.sections[88], gui.color.white, settings_usectlbitmap, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Run modulators when stopped', obj.sections[715], gui.color.white, settings_alwaysrunmods, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Alternative edit mode drag', obj.sections[726], gui.color.white, settings_dragmode, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Disable send checks', obj.sections[72], gui.color.white, settings_disablesendchecks, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Allow control value monitoring to be disabled', obj.sections[738], gui.color.white, settings_enablednu, gui.fontsz.settings)
      GUI_DrawButton(gui, undo.max, obj.sections[740], -3, gui.color.black, true, 'Max edit mode undo states', true, gui.fontsz.settings)

    elseif lvar.settingspage == 3 then

      GUI_DrawTick(gui, 'Save all track fx with strip', obj.sections[73], gui.color.white, settings_saveallfxinststrip, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Save script data in project folder', obj.sections[87], gui.color.white, settings_savedatainprojectfolder, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Create backup when manually saving', obj.sections[98], gui.color.white, settings_createbackuponmanualsave, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Enable temp bkp of data when saving', obj.sections[728], gui.color.white, settings_backupduringsave, gui.fontsz.settings)
      GUI_DrawButton(gui, nz(save_subfolder,''), obj.sections[95], gui.color.white, gui.color.white, false, 'Save subfolder', true, gui.fontsz.settings)

    elseif lvar.settingspage == 4 then

      GUI_DrawTick(gui, 'Display scroll bars', obj.sections[85], gui.color.white, settings_showbars, gui.fontsz.settings)
      GUI_DrawColorBox(gui, 'Snapshot list background colour', obj.sections[86], gui.color.white, settings_snaplistbgcol, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Show minimal top bar when hidden', obj.sections[89], gui.color.white, settings_showminimaltopbar, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Hide edit bar on new projects', obj.sections[96], gui.color.white, settings_hideeditbaronnewproject, gui.fontsz.settings)
      GUI_DrawButton(gui, string.sub(skin_select,0,string.len(skin_select)-1), obj.sections[720], -3, gui.color.black, true, 'Skin', true, gui.fontsz.settings)
      GUI_DrawButton(gui, tb_butt_h, obj.sections[721], -3, gui.color.black, true, 'Top/sidebar size', true, gui.fontsz.settings)
      GUI_DrawButton(gui, tb_fontscale, obj.sections[724], -3, gui.color.black, true, 'Top/sidebar font size', true, gui.fontsz.settings)
      GUI_DrawButton(gui, lst_fontscale, obj.sections[725], -3, gui.color.black, true, 'Sidebar list font size', true, gui.fontsz.settings)
      GUI_DrawButton(gui, pnl_scale, obj.sections[722], -3, gui.color.black, true, 'Panel size', true, gui.fontsz.settings)
      GUI_DrawButton(gui, fontscale, obj.sections[723], -3, gui.color.black, true, 'Panel font size', true, gui.fontsz.settings)
      GUI_DrawColorBox(gui, 'Main background colour', obj.sections[702], gui.color.white, backcol, gui.fontsz.settings)
      local tk = false
      if lvar.bgmatchestrackcolour > 0 then
        tk = true
      end
      GUI_DrawTick(gui, '', obj.sections[741], gui.color.white, tk, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Enable Shadows', obj.sections[742], gui.color.white, lvar.enablegfxshadows, gui.fontsz.settings)
      --DBG(lvar.shadow_offsx..'  '..lvar.shadowmax)
      GUI_DrawSliderH(gui, 'Shadow Size', obj.sections[743], gui.color.black, gui.color.white, (lvar.shadow_offsx/lvar.shadowmax), gui.fontsz.settings)
      GUI_DrawSliderH(gui, 'Shadow Opacity', obj.sections[744], gui.color.black, gui.color.white, lvar.shadow_alpha, gui.fontsz.settings)
      GUI_DrawSliderH(gui, 'Shadow Feather', obj.sections[745], gui.color.black, gui.color.white, lvar.shadow_feather/50, gui.fontsz.settings)


      GUI_DrawTick(gui, 'Show fader assignments on grid', obj.sections[706], gui.color.white, settings_showfaderassignments, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Activate snapshot morphing pop-ups', obj.sections[717], gui.color.white, settings_showmorphpop, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Hide "plugin not found" text when plugin missing', obj.sections[737], gui.color.white, settings_hideplugnotfound, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Enable surface size > 2048 pixels', obj.sections[751], gui.color.white, lvar.enablelargegui, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Show labels in strip browser', obj.sections[739], gui.color.white, lvar.stripbrowser.showlabel, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Mac: Fix colour picker colours', obj.sections[753], gui.color.white, lvar.Mac_revcol, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Mac: Force sort on files', obj.sections[754], gui.color.white, lvar.sortcontrols, gui.fontsz.settings)

    elseif lvar.settingspage == 5 then

      local sb = false
      local sbt = 'NOT SET'
      if neb_scanboot_tab then
        sb = true
        sbt = 'SET'
      end
      GUI_DrawButton(gui, sbt, obj.sections[703], gui.color.white, gui.skol.butt1_txt, sb, 'Nebula scanboot location', true, gui.fontsz.settings)

      GUI_DrawTick(gui, 'Hide mouse pointer when dragging control', obj.sections[748], gui.color.white, lvar.hidecursordrag or false, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Touch screen mode', obj.sections[749], gui.color.white, settings_touchmode, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Touch feedback indicator', obj.sections[704], gui.color.white, settings_touchFB, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Morph fader/mod assigned controls', obj.sections[714], gui.color.white, settings_morphfaderassignedctls, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Disable key input when surface locked', obj.sections[712], gui.color.white, settings_disablekeysonlockedsurface, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Run lbxstart batch file when script starts', obj.sections[729], gui.color.white, settings_runstartbat, gui.fontsz.settings)
      GUI_DrawTick(gui, 'Create log file when adding strips (not saved)', obj.sections[730], gui.color.white, logflag, gui.fontsz.settings)
      sb = false
      if lvar.striploadoverride then
        sb = true
      end
      GUI_DrawButton(gui, lvar.striploadoverride or 'NOT SET', obj.sections[736], gui.color.white, gui.skol.butt1_txt, sb, 'Data file override', true, gui.fontsz.settings -2)
      GUI_DrawButton(gui, lvar.altrespath or paths.resource_path or 'NOT SET', obj.sections[750], gui.color.white, gui.skol.butt1_txt, sb, 'LBX Resource path', true, gui.fontsz.settings -2, 5)

    end
    gfx.dest = dest or 1
    gfx.a = 1

    --set font
    GUI_Str(gui, {x=0,y=0,w=0,h=0}, '', 5, gui.color.black, -4 + gui.fontsz.settings +tscale, 1, nil, gui.fontnm.butt, gui.fontflag.butt)
    local _, h = gfx.measurestr('|')
    --setting info
    if lvar.settingsinf_txt[lvar.settings_last] then
      local c = gui.color.blue

      local lines = #lvar.settingsinf_txt[lvar.settings_last]
      local ypm = 1
      if lines == 2 then
        ypm = 0.5
      elseif lines == 3 then
        ypm = 0
      end
      local xywh = {x = obj.sections[70].x,
                    y = obj.sections[70].y + obj.sections[70].h - math.floor(((3*h)+9*pnl_scale) - ypm*h),
                    w = obj.sections[70].w,
                    h = h}
      GUI_Str(gui, xywh, lvar.settingsinf_txt[lvar.settings_last][1], 5, c, -4 + gui.fontsz.settings+tscale, 1, nil, gui.fontnm.butt, gui.fontflag.butt)
      xywh.y = xywh.y + h
      GUI_Str(gui, xywh, lvar.settingsinf_txt[lvar.settings_last][2] or '', 5, c, -4 + gui.fontsz.settings+tscale, 1, nil, gui.fontnm.butt, gui.fontflag.butt)
      xywh.y = xywh.y + h
      GUI_Str(gui, xywh, lvar.settingsinf_txt[lvar.settings_last][3] or '', 5, c, -4 + gui.fontsz.settings+tscale, 1, nil, gui.fontnm.butt, gui.fontflag.butt)
    end

    local xywh = {x = obj.sections[70].x, y = obj.sections[70].y+lvar.settingsy, w = obj.sections[70].w, h = obj.sections[70].h-lvar.settingsy-math.floor(h*3+12*pnl_scale)}
    gfx.blit(990,1,0,0,lvar.settingsy,xywh.w,xywh.h,xywh.x,xywh.y)
    f_Get_SSV('32 32 32')
    gfx.a = 1
    gfx.line(xywh.x,
             xywh.y,
             xywh.x+xywh.w,
             xywh.y)
    gfx.line(xywh.x,
             xywh.y+xywh.h,
             xywh.x+xywh.w,
             xywh.y+xywh.h)

  end

  function GetMOFaders()
    local abs, rel
    if LBX_CTL_TRACK then

      for i = 1, lvar.LBX_FB_CNT*LBX_CTL_TRACK_INF.count do
        if faders[i].targettype == 3 then
          if faders[i].mode == 0 then
            abs = i
          else
            rel = i
          end
        end
      end

    end
    return abs, rel
  end

  function UpdateLEdges()

    f_Get_SSV('0 0 0')
    if lockw > 0 or surface_size.exceed == true then

      local xx = plist_w

      if obj.sections[10].x > xx then
        local xywh = {x = xx,
                      y = topbarheight,
                      w = obj.sections[10].x - xx,
                      h = gfx1.main_h - topbarheight}
        gfx.a = 1
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )
      end

      if obj.sections[10].x + obj.sections[10].w < gfx1.main_w then
        xx = obj.sections[10].x + obj.sections[10].w
        local xywh = {x = xx,
                      y = topbarheight,
                      w = gfx1.main_w - xx+1,
                      h = gfx1.main_h - topbarheight}
        gfx.a = 1
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )

      end

    end
    if lockh > 0 or surface_size.exceed == true then

      local yy = obj.sections[10].y

      if yy > topbarheight then
        local xywh = {x = obj.sections[10].x,
                      y = topbarheight,
                      w = obj.sections[10].w,
                      h = obj.sections[10].y - topbarheight}
        gfx.a = 1
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )
      end

      yy = obj.sections[10].y + obj.sections[10].h
      if yy < gfx1.main_h then
        local xywh = {x = obj.sections[10].x,
                      y = yy,
                      w = obj.sections[10].w,
                      h = gfx1.main_h - yy}
        gfx.a = 1
        gfx.rect(xywh.x,
                 xywh.y,
                 xywh.w,
                 xywh.h, 1 )

      end

    end

    if mode == 1 and surface_size.exceed == true then
      if lupd.update_gfx or lupd.update_surface or lasso ~= nil then
        f_Get_SSV(gui.color.red)
        gfx.rect(obj.sections[10].x,obj.sections[10].y,obj.sections[10].w+1,obj.sections[10].h+1,0)
      end
    end

  end

  function UpdateEdges()

    local winw, winh = obj.sections[10].w , obj.sections[10].h
    if surface_offset.x == 0 and lvar.maxdim*lvar.zoom < obj.sections[10].w then
      local xywh = {x = obj.sections[10].x+lvar.maxdim*lvar.zoom-1,
                    y = obj.sections[10].y,
                    w = obj.sections[10].w-lvar.maxdim*lvar.zoom+1,
                    h = winh}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end
    if surface_offset.y == 0 and lvar.maxdim*lvar.zoom < obj.sections[10].h then
      local xywh = {x = obj.sections[10].x,
                    y = obj.sections[10].y+lvar.maxdim*lvar.zoom-1,
                    w = winh,
                    h = obj.sections[10].w-lvar.maxdim*lvar.zoom+1}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end


  end

  --[[function UpdateEdges()

    local winw, winh = obj.sections[10].w , obj.sections[10].h

    f_Get_SSV('0 0 0')
    if surface_offset.x < 0 then
      local xywh = {x = obj.sections[10].x,
                    y = obj.sections[10].y,
                    w = -surface_offset.x*lvar.zoom+1,
                    h = winh}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end
    if surface_offset.y < 0 then
      local xywh = {x = obj.sections[10].x,
                    y = obj.sections[10].y,
                    w = winw,
                    h = -surface_offset.y-1}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end
    if surface_offset.x > surface_size.w-winw then
      local xywh = {x = obj.sections[10].x+winw-(surface_offset.x - (surface_size.w-winw))-1,
                    y = obj.sections[10].y,
                    w = surface_offset.x - (surface_size.w-winw),
                    h = winh}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end
    if surface_offset.y > surface_size.h-winh then
      local xywh = {x = obj.sections[10].x,
                    y = obj.sections[10].y+winh-(surface_offset.y - (surface_size.h-winh))-1,
                    w = winw,
                    h = surface_offset.y - (surface_size.h-winh)}
      gfx.a = 1
      gfx.rect(xywh.x,
               xywh.y,
               xywh.w,
               xywh.h, 1 )
    end

  end]]

  function GUI_DrawMsg(gui, obj)

    f_Get_SSV('0 0 0')
    gfx.a = 1
    gfx.rect(obj.sections[61].x,
             obj.sections[61].y,
             obj.sections[61].w,
             obj.sections[61].h, 1)
    f_Get_SSV(gui.color.white)
    gfx.rect(obj.sections[61].x,
             obj.sections[61].y,
             obj.sections[61].w,
             obj.sections[61].h, 0)
    gfx.rect(obj.sections[62].x,
             obj.sections[62].y,
             obj.sections[62].w,
             obj.sections[62].h, 1)
    if msgbox then
      local tscale = (pnl_scale-1)*fontscale

      if msgbox.b == 2 then
        f_Get_SSV(gui.color.white)
        gfx.rect(obj.sections[64].x,
                 obj.sections[64].y,
                 obj.sections[64].w,
                 obj.sections[64].h, 1)
        GUI_textC(gui,obj.sections[62],'Yes',gui.color.black,-2*tscale)
        GUI_textC(gui,obj.sections[64],'No',gui.color.black,-2*tscale)
      else
        GUI_textC(gui,obj.sections[62],'OK',gui.color.black,-2*tscale)
      end
      GUI_textC(gui,obj.sections[63],nz(msgbox.text1,''),gui.color.white,-2*tscale)
      if msgbox.text2 then
        local xywh = {x = obj.sections[63].x,
                      y = obj.sections[63].y + butt_h,
                      w = obj.sections[63].w,
                      h = obj.sections[63].h}
        GUI_textC(gui,xywh,nz(msgbox.text2,''),gui.color.white,-2*tscale)
      end
    else
      GUI_textC(gui,obj.sections[62],'OK',gui.color.black,-2*tscale)
    end

  end

  ------------------------------------------------------------

  function Lokasenna_Window_At_Center (w, h, x, y)
    -- thanks to Lokasenna
    -- http://forum.cockos.com/showpost.php?p=1689028&postcount=15
    local l, t, r, b = 0, 0, w, h
    local __, __, screen_w, screen_h = reaper.my_getViewport(l, t, r, b, l, t, r, b, 1)
    if x == nil or y == nil then
      x, y = (screen_w - w) / 2, (screen_h - h) / 2
    end
    gfx.init("- LBX Stripper -", w, h, 0, x, y)

    gfx.ext_retina = 1
  end

  function GetParamDisp_Val(c, val, sleep)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    local oval = ctl.val

    if ctl.ctlcat == ctlcats.pkmeter then
      return DenormalizeValue(-60,0,val)
    elseif ctl.ctlcat == ctlcats.gr_meter then
      local min, max = ctl.grmin or -20, ctl.grmax or 0
      return DenormalizeValue(min,max,val or 0)    
    else
      local tracknum = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        tracknum = ctl.tracknum
      end
      local cc = ctl.ctlcat
      local fxnum = ctl.fxnum
      local param = ctl.param
      local dvoff = ctl.dvaloffset
      local sldiv = 400

      SetParam3(strip,page,c,ctl,val)
      if sleep then
        os.sleep((auto_delay/sldiv)*10)
      end
      local dval = GetParamDisp(cc, tracknum, fxnum, param, dvoff, c)
      --SetParam3(strip,page,c,ctl,oval)

      return dval
    end

  end

  function GetParamDisp_Ctl(c)
    local t = strips[tracks[track_select].strip].track.tracknum
    if strips[tracks[track_select].strip][page].controls[c].tracknum ~= nil then
      t = strips[tracks[track_select].strip][page].controls[c].tracknum
    end

    local cc = strips[tracks[track_select].strip][page].controls[c].ctlcat
    if cc == ctlcats.fxparam then
      local f = strips[tracks[track_select].strip][page].controls[c].fxnum
      local p = strips[tracks[track_select].strip][page].controls[c].param
      local dvoff = strips[tracks[track_select].strip][page].controls[c].dvaloffset
      local dval = GetParamDisp(cc, t, f, p, dvoff,c)
      return dval

    elseif cc == ctlcats.trackparam then
      local p = strips[tracks[track_select].strip][page].controls[c].param
      local dvoff = strips[tracks[track_select].strip][page].controls[c].dvaloffset
      local dval = GetParamDisp(cc, t, nil, p, dvoff,c)
      return dval

    elseif cc == ctlcats.tracksend then
      local p = strips[tracks[track_select].strip][page].controls[c].param
      local dvoff = strips[tracks[track_select].strip][page].controls[c].dvaloffset
      local dval = GetParamDisp(cc, t, nil, p, dvoff,c)
      return dval

    elseif cc == ctlcats.action then
      return ''
    end

  end

  function GetParamDisp(ctlcat,tracknum,fxnum,paramnum, dvoff, c)
    track = GetTrack(tracknum)
    if track == nil then return '' end

    if ctlcat == ctlcats.fxparam then
      local _, d = reaper.TrackFX_GetFormattedParamValue(track, fxnum, paramnum, "")
      if dvoff then
        d = dvaloffset(d, dvoff)
      end
      return d

    elseif ctlcat == ctlcats.trackparam then
      local d
      if paramnum == 1 then
        --volume
        local _, vv = reaper.GetTrackUIVolPan(track)
        d = reaper.mkvolstr('', vv)
      elseif paramnum == 2 or paramnum == 4 or paramnum == 5 then
        --pan
        local _, _, vv = reaper.GetTrackUIVolPan(track)
        d = reaper.mkpanstr('', vv)
      else
        d = round(reaper.GetMediaTrackInfo_Value(track, trctls_table[paramnum].parmname),2)
      end

      if dvoff then
        d = dvaloffset(d, dvoff)
      end
      return d

    elseif ctlcat == ctlcats.tracksend then
      local d
      local paramidx = strips[tracks[track_select].strip][page].controls[c].param_info.paramidx
      local paramstr = strips[tracks[track_select].strip][page].controls[c].param_info.paramstr
      local tidx = ((paramnum-1) % 3) +1
      if paramnum % 3 == 1 then
        --volumes
        --d = reaper.mkvolstr('', reaper.GetTrackSendInfo_Value(track, 0, paramidx, paramstr))
        retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, paramidx)
        d = reaper.mkvolstr('', vOut)
      elseif paramnum % 3 == 2 then
        --pan
        --d = reaper.mkpanstr('', reaper.GetTrackSendInfo_Value(track, 0, paramidx, paramstr))
        retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, paramidx)
        d = reaper.mkpanstr('', pOut)
      else
        d = round(reaper.GetTrackSendInfo_Value(track, 0, paramidx, paramstr),2)
      end

      if dvoff then
        d = dvaloffset(d, dvoff)
      end
      return d

    elseif ctlcat == ctlcats.action then
      return ''

    elseif ctlcat == ctlcats.pkmeter then

      if tracknum == -3 then
        local ttr = GetTrack(tracknum)
        if ttr then
          tracknum = reaper.GetMediaTrackInfo_Value(ttr, 'IP_TRACKNUMBER')-1
        end
      end
      if paramnum <=64 and peak_info[tracknum] and peak_info[tracknum][paramnum] then
        return round(peak_info[tracknum][paramnum].ch_d,1)
      elseif paramnum > 64 then
        return ''
      else
        return '-inf'
      end

    elseif ctlcat == ctlcats.midictl then

      local ctl = strips[tracks[track_select].strip][page].controls[c]
      return math.floor(ctl.val * 127)

    elseif ctlcat == ctlcats.statectl then
      local ctl = strips[tracks[track_select].strip][page].controls[c]
      return ctl.stateinfo.min + round(ctl.val*(ctl.stateinfo.max-ctl.stateinfo.min)/ctl.stateinfo.step)*ctl.stateinfo.step
    end
  end

  function GetParamValue_Ctl(c)
    if c then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[c]

      if not ctl then return end
      
      local t = ctl.tracknum or strips[strip].track.tracknum
      local cc = ctl.ctlcat

      if cc == ctlcats.fxparam then
        local f = ctl.fxnum
        local p = ctl.param
        track = GetTrack(t)

        local v, min, max = reaper.TrackFX_GetParam(track, f, p)
        if ctl.minov then
          min = ctl.minov
        end
        if ctl.maxov then
          max = ctl.maxov
        end
        return normalize(min, max, v)

      elseif cc == ctlcats.trackparam then
        local p = ctl.param
        local min, max = GetParamMinMax(cc,nil,nil,p,true,c)
        return GMTI_norm(track, p, min, max)

      elseif cc == ctlcats.tracksend then
        local p = ctl.param
        local min, max = GetParamMinMax(cc,nil,nil,p,true,c)
        return GTSI_norm(track, p, min, max,c)

      elseif cc == ctlcats.action then
        return 0

      elseif cc == ctlcats.pkmeter then
        local tracknum = t
        if tracknum == -3 then
          local ttr = GetTrack(tracknum)
          if ttr then
            tracknum = reaper.GetMediaTrackInfo_Value(ttr, 'IP_TRACKNUMBER')-1
          end
        end
        local p = ctl.param
        if p <= 64 and peak_info[tracknum] and peak_info[tracknum][p] then
          return peak_info[tracknum][p].ch
        else
          return 0
        end

      elseif cc == ctlcats.gr_meter then
        local min, max, v
        min, max = ctl.grmin, ctl.grmax
        _, val = reaper.TrackFX_GetNamedConfigParm(track, ctl.fxnum, 'GainReduction_dB')
        if tonumber(val) then
          v = tonumber(val)
        end        
        return normalize(min or -20, max or 0, v or 0)

      elseif cc == ctlcats.macro then
        return ctl.val
      end
    else
      return 0
    end
  end

  function GMTI_norm(track,trctl_idx,min,max)

    if not track then return end
    if trctls_table[trctl_idx].parmname == 'B_MUTE' then
      local retval, muteOut = reaper.GetTrackUIMute(track)
      local mo
      if muteOut then mo = 1 else mo = 0 end
      return mo
    elseif trctls_table[trctl_idx].parmname == 'I_SOLO' then
      local trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')
      if trn == -1 then
        local flags = reaper.GetMasterMuteSoloFlags()
        local soloOut = flags&2==2
        if soloOut then so = 1 else so = 0 end
        return so
      else
        return normalize(min,max,reaper.GetMediaTrackInfo_Value(track, trctls_table[trctl_idx].parmname))
      end

    else
      if trctls_table[trctl_idx].funcget then
        local r, v1, v2 = trctls_table[trctl_idx].funcget(track)
        local v
        if trctls_table[trctl_idx].getret == 1 then
          v = v1
        else
          v = v2
        end
        return normalize(min,max,v or 0)
      else
        return normalize(min,max,reaper.GetMediaTrackInfo_Value(track, trctls_table[trctl_idx].parmname))
      end
    end

  end

  function GTSI_norm(track,trctl_idx,min,max,c)

    local strip = tracks[track_select].strip
    if strips[strip] and strips[strip][page].controls[c] then

      local idx = strips[strip][page].controls[c].param_info.paramidx
      local paramstr = strips[strip][page].controls[c].param_info.paramstr

      --if paramstr == nil then return 0 end

      if track == nil then
        track = GetTrack(nz(strips[strip][page].controls[c].tracknum,strips[strip].track.tracknum))
        if not track then return end
      end

      if paramstr == 'D_VOL' then
        local retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, idx)
        return normalize(min, max, vOut)
      elseif paramstr == 'D_PAN' then
        local retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, idx)
        return normalize(min, max, pOut)
      elseif paramstr == 'B_MUTE' then
        local retval, muteOut = reaper.GetTrackSendUIMute(track, idx)
        local mo
        if muteOut then mo = 1 else mo = 0 end
        return mo
      --else
      --  return normalize(min,max,reaper.GetTrackSendInfo_Value(track, 0, idx, paramstr))
      end
    end

  end

  function GTSI_norm_XX(track,trctl_idx,min,max,c,strip,page)

    local idx = strips[strip][page].controls[c].param_info.paramidx
    local paramstr = strips[strip][page].controls[c].param_info.paramstr

    --if paramstr == nil then return 0 end

    if track == nil then
      track = GetTrack(nz(strips[strip][page].controls[c].tracknum,strips[strip].track.tracknum))
      if not track then return end
    end

    if paramstr == 'D_VOL' then
      local retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, idx)
      return normalize(min, max, vOut)
    elseif paramstr == 'D_PAN' then
      local retval, vOut, pOut = reaper.GetTrackSendUIVolPan(track, idx)
      return normalize(min, max, pOut)
    elseif paramstr == 'B_MUTE' then
      local retval, muteOut = reaper.GetTrackSendUIMute(track, idx)
      local mo
      if muteOut then mo = 1 else mo = 0 end
      return mo
    --else
    --  return normalize(min,max,reaper.GetTrackSendInfo_Value(track, 0, idx, paramstr))
    end

  end

  function SMTI_norm(track,trctl_idx,v,min,max)

    if not track then return end

    local val = DenormalizeValue(min,max,v)
    if trctls_table[trctl_idx].func then
      trctls_table[trctl_idx].func(track, val, false)
    else
      reaper.SetMediaTrackInfo_Value(track, trctls_table[trctl_idx].parmname, val)
    end
    --DBG(v..'  '..val)
    return v

  end

  function SMTI_denorm(track,trctl_idx,v)

    if not track then return end

    if trctls_table[trctl_idx].func then
      trctls_table[trctl_idx].func(track, v, false)
    else
      reaper.SetMediaTrackInfo_Value(track, trctls_table[trctl_idx].parmname, v)
    end
  end

  function STSI_norm(track,trctl_idx,v,min,max,c, strip, page)

    if not track then return end

    local idx = strips[strip][page].controls[c].param_info.paramidx
    local paramstr = strips[strip][page].controls[c].param_info.paramstr

    local val = DenormalizeValue(min,max,v)
    if paramstr == 'D_VOL' then
      reaper.SetTrackSendUIVol(track, idx, val, 0)
    elseif paramstr == 'D_PAN' then
      reaper.SetTrackSendUIPan(track, idx, val, 0)
    elseif paramstr == 'B_MUTE' then
      reaper.ToggleTrackSendUIMute(track, idx)
    else
      reaper.SetTrackSendInfo_Value(track, 0, idx, paramstr, val)
    end
    return val

  end

  function STSI_denorm(track,trctl_idx,val,c, strip, page)

    if not track then return end

    local idx = strips[strip][page].controls[c].param_info.paramidx
    local paramstr = strips[strip][page].controls[c].param_info.paramstr
    if paramstr == 'D_VOL' then
      reaper.SetTrackSendUIVol(track, idx, val, 0)
    elseif paramstr == 'D_PAN' then
      reaper.SetTrackSendUIPan(track, idx, val, 0)
    elseif paramstr == 'B_MUTE' then
      local v = strips[strip][page].controls[c].val
      if v ~= val then
        reaper.ToggleTrackSendUIMute(track, idx)
      end
    else
      reaper.SetTrackSendInfo_Value(track, 0, idx, paramstr, val)
    end
  end

  function GetParamValue(ctlcat,tracknum,fxnum,paramnum,c)
    track = GetTrack(tracknum)
    if not track then return end

    if ctlcat == ctlcats.fxparam then
      local v, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
      if c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        if ctl.minov then
          min = ctl.minov
        end
        if ctl.maxov then
          max = ctl.maxov
        end
      end
      return normalize(min, max, v)

    elseif ctlcat == ctlcats.trackparam then
      local min, max = GetParamMinMax(ctlcat,nil,nil,paramnum,true,c)
      return GMTI_norm(track, paramnum, min, max)

    elseif ctlcat == ctlcats.tracksend then
      local min, max = GetParamMinMax(ctlcat,nil,nil,paramnum,true,c)
      return GTSI_norm(track, paramnum, min, max,c)

    elseif ctlcat == ctlcats.action then
      return 0

    elseif ctlcat == ctlcats.pkmeter then

      if tracknum == -3 then
        local ttr = GetTrack(tracknum)
        if ttr then
          tracknum = reaper.GetMediaTrackInfo_Value(ttr, 'IP_TRACKNUMBER')-1
        end
      end
      if peak_info[tracknum] and peak_info[tracknum][paramnum % 64] then
        if paramnum < 64 then
          return peak_info[tracknum][paramnum].ch
        else
          return peak_info[tracknum][paramnum-64].pk
        end
      else
        return 0
      end

    elseif ctlcat == ctlcats.gr_meter then

      local min, max, v
      if c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]        
        min, max = ctl.grmin, ctl.grmax
        _, val = reaper.TrackFX_GetNamedConfigParm(track, fxnum, 'GainReduction_dB')
        if tonumber(val) then
          v = tonumber(val)
        end
      end
      return normalize(min or -20, max or 0, v or 0)

    elseif ctlcat == ctlcats.midictl then
      local ctl = strips[tracks[track_select].strip][page].controls[c]
      local v = ctl.val
      local min, max = 0, 1
      if c then
        if ctl.minov then
          min = ctl.minov
        end
        if ctl.maxov then
          max = ctl.maxov
        end
      end
      return normalize(min, max, v)

    elseif ctlcat == ctlcats.macro or ctlcat == ctlcats.rs5k or ctlcat == ctlcats.statectl then
      return strips[tracks[track_select].strip][page].controls[c].val
    --elseif ctlcat == ctlcats.statectl then
    --  return ctl.val
    else
      return 0
    end
  end

  function GetParamValue_XX(ctlcat,tracknum,fxnum,paramnum,c,strip,page, ctl)
    track = GetTrack(tracknum)
    if track then
      if ctlcat == ctlcats.fxparam then
        local v, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
        if ctl then
          if ctl.minov then
            min = ctl.minov
          end
          if ctl.maxov then
            max = ctl.maxov
          end
        elseif c then
          local ctl = strips[strip][page].controls[c]
          if ctl.minov then
            min = ctl.minov
          end
          if ctl.maxov then
            max = ctl.maxov
          end
        end
        return normalize(min, max, v)

      elseif ctlcat == ctlcats.trackparam then
        local min, max = GetParamMinMax_XX(ctlcat,nil,nil,paramnum,true,c,strip,page,ctl)
        return GMTI_norm(track, paramnum, min, max)

      elseif ctlcat == ctlcats.tracksend then
        local min, max = GetParamMinMax_XX(ctlcat,nil,nil,paramnum,true,c,strip,page,ctl)
        return GTSI_norm_XX(track, paramnum, min, max,c, strip, page)

      elseif ctlcat == ctlcats.macro then
        if ctl then
          return ctl.val
        else
          return strips[strip][page].controls[c].val
        end

      elseif ctlcat == ctlcats.action then
        return 0

      elseif ctlcat == ctlcats.pkmeter then
        if tracknum == -3 then
          local ttr = GetTrack(tracknum)
          if ttr then
            tracknum = reaper.GetMediaTrackInfo_Value(ttr, 'IP_TRACKNUMBER')-1
          end
        end
        if peak_info[tracknum] and peak_info[tracknum][paramnum % 64] then
          if paramnum < 64 then
            return peak_info[tracknum][paramnum].ch
          else
            return peak_info[tracknum][paramnum-64].pk
          end
        else
          return 0
        end
      
      elseif ctlcat == ctlcats.gr_meter then
  
        local min, max, v
        if ctl then
          min, max = ctl.grmin, ctl.grmax
          _, val = reaper.TrackFX_GetNamedConfigParm(track, fxnum, 'GainReduction_dB')
          if tonumber(val) then
            v = tonumber(val)
          end        
        elseif c then
          local ctl = strips[strip][page].controls[c]        
          min, max = ctl.grmin, ctl.grmax
          _, val = reaper.TrackFX_GetNamedConfigParm(track, fxnum, 'GainReduction_dB')
          if tonumber(val) then
            v = tonumber(val)
          end
        end
        return normalize(min or -20, max or 0, v or 0)
      
      end
    end
  end

  function GetParamValue2(ctlcat,track,fxnum,paramnum,c)

    if not track then return end

    if ctlcat == ctlcats.fxparam then
      local v, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
      if c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        min = ctl.minov or min
        max = ctl.maxov or max
      end
      return normalize(min, max, v)

    elseif ctlcat == ctlcats.trackparam then

      local min, max = GetParamMinMax(ctlcat,nil,nil,paramnum,true,c)
      return GMTI_norm(track, paramnum, min, max)

    elseif ctlcat == ctlcats.tracksend then
      local min, max = GetParamMinMax(ctlcat,nil,nil,paramnum,true,c)
      return GTSI_norm(track, paramnum, min, max,c)

    elseif ctlcat == ctlcats.gr_meter then

      local min, max, v
      if c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]        
        min, max = ctl.grmin, ctl.grmax
        _, val = reaper.TrackFX_GetNamedConfigParm(track, fxnum, 'GainReduction_dB')
        if tonumber(val) then
          v = tonumber(val)
        end
      end
      return normalize(min or -20, max or 0, v or 0)

    elseif ctlcat == ctlcats.action then
      return 0

    elseif ctlcat == ctlcats.pkmeter then
      local tracknum = strips[tracks[track_select].strip].track.tracknum
      local ctl = strips[tracks[track_select].strip][page].controls[c]
      if ctl and ctl.tracknum ~= nil then
        tracknum = ctl.tracknum
        if tracknum == -3 then
          local ttr = GetTrack(tracknum)
          if ttr then
            tracknum = reaper.GetMediaTrackInfo_Value(ttr, 'IP_TRACKNUMBER')-1
          end
        end
      end
      if peak_info[tracknum] and peak_info[tracknum][paramnum % 64] then
        if paramnum < 64 then
          return peak_info[tracknum][paramnum].ch
        else
          return peak_info[tracknum][paramnum-64].pk
        end
      else
        return 0
      end
    end
  end

  function A_GetParamMinMax(ctlcat,track,ctl,fxnum,paramnum,checkov,c)
    if ctlcat == ctlcats.fxparam then
      if track == nil then return end
      local _, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
      if checkov and checkov == true and ctl then
        min = ctl.minov or min
        max = ctl.maxov or max
      end
      return min, max

    elseif ctlcat == ctlcats.trackparam then
      local min, max = trctls_table[paramnum].min, trctls_table[paramnum].max
      if checkov and checkov == true and ctl then
        min = ctl.minov or min
        max = ctl.maxov or max
      end
      return tonumber(min), tonumber(max)

    elseif ctlcat == ctlcats.tracksend then
      local idx = math.floor((paramnum-1) % 3)+1
      local min, max = trsends_mmtable[idx].min, trsends_mmtable[idx].max
      if checkov and checkov == true and ctl then
        min = ctl.minov or min
        max = ctl.maxov or max
      end
      return tonumber(min), tonumber(max)
    else
      return 0, 1
    end
  end

  function GetParamMinMax(ctlcat,track,fxnum,paramnum,checkov,c)
    if ctlcat == ctlcats.fxparam then
      if track == nil then return end
      local _, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
      if checkov and checkov == true and c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        if ctl then
          min = ctl.minov or min
          max = ctl.maxov or max
        end
      end
      return min, max

    elseif ctlcat == ctlcats.trackparam then
      local min, max = trctls_table[paramnum].min, trctls_table[paramnum].max
      if checkov and checkov == true and c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        if ctl then
          min = ctl.minov or min
          max = ctl.maxov or max
        end
      end
      return tonumber(min), tonumber(max)

    elseif ctlcat == ctlcats.tracksend then
      local idx = math.floor((paramnum-1) % 3)+1
      local min, max = trsends_mmtable[idx].min, trsends_mmtable[idx].max
      if checkov and checkov == true and c then
        local ctl = strips[tracks[track_select].strip][page].controls[c]
        if ctl then
          min = ctl.minov or min
          max = ctl.maxov or max
        end
      end
      return tonumber(min), tonumber(max)
    else
      return 0, 1
    end
  end

  function GetParamMinMax_XX(ctlcat,track,fxnum,paramnum,checkov,c, strip, page, ctl)
    if ctlcat == ctlcats.fxparam then
      if track == nil then return end
      local _, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
      if checkov and checkov == true and c then
        if ctl then
          if ctl.minov then
            min = ctl.minov
          end
          if ctl.maxov then
            max = ctl.maxov
          end
        else
          if strips[strip][page].controls[c].minov then
            min = strips[strip][page].controls[c].minov
          end
          if strips[strip][page].controls[c].maxov then
            max = strips[strip][page].controls[c].maxov
          end
        end
      end
      return min, max

    elseif ctlcat == ctlcats.trackparam then
      local min, max = trctls_table[paramnum].min, trctls_table[paramnum].max
      if checkov and checkov == true and c then
        if ctl then
          if ctl.minov then
            min = ctl.minov
          end
          if ctl.maxov then
            max = ctl.maxov
          end
        else
          if strips[strip][page].controls[c].minov then
            min = strips[strip][page].controls[c].minov
          end
          if strips[strip][page].controls[c].maxov then
            max = strips[strip][page].controls[c].maxov
          end
        end
      end
      return tonumber(min), tonumber(max)

    elseif ctlcat == ctlcats.tracksend then
      local idx = math.floor((paramnum-1) % 3)+1
      local min, max = trsends_mmtable[idx].min, trsends_mmtable[idx].max
      if checkov and checkov == true and c then
        if ctl then
          if ctl.minov then
            min = ctl.minov
          end
          if ctl.maxov then
            max = ctl.maxov
          end
        else
          if strips[strip][page].controls[c].minov then
            min = strips[strip][page].controls[c].minov
          end
          if strips[strip][page].controls[c].maxov then
            max = strips[strip][page].controls[c].maxov
          end
        end
      end
      return tonumber(min), tonumber(max)
    else
      return 0, 1
    end
  end

  function GetParamMinMax_ctlselect()
    if ctl_select and #ctl_select >= 1 then
      trackfxparam_select = ctl_select[1].ctl
      local track
      if strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum == nil then
        track = GetTrack(strips[tracks[track_select].strip].track.tracknum)
      else
        track = GetTrack(strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum)
      end
      local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
      if cc == ctlcats.fxparam then
        local fxnum = strips[tracks[track_select].strip][page].controls[trackfxparam_select].fxnum
        local paramnum = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param

        local _, min, max = reaper.TrackFX_GetParam(track, fxnum, paramnum)
        return min, max
      elseif cc == ctlcats.trackparam then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        return tonumber(trctls_table[param].min), tonumber(trctls_table[param].max)
      elseif cc == ctlcats.tracksend then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        local idx = math.floor((param-1) % 3)+1
        return tonumber(trsends_mmtable[idx].min), tonumber(trsends_mmtable[idx].max)
      else
        return 0, 1
      end
    else
      return nil, nil
    end
  end

  function GetParamMinMax_ctl(c, checkov)

    if checkov == nil then checkov = true end

    local t = strips[tracks[track_select].strip].track.tracknum
    if strips[tracks[track_select].strip][page].controls[c].tracknum ~= nil then
      t = strips[tracks[track_select].strip][page].controls[c].tracknum
    end

    local cc = strips[tracks[track_select].strip][page].controls[c].ctlcat
    if cc == ctlcats.fxparam then
      local f = strips[tracks[track_select].strip][page].controls[c].fxnum
      local p = strips[tracks[track_select].strip][page].controls[c].param
      local cc = strips[tracks[track_select].strip][page].controls[c].ctlcat

      local track = GetTrack(t)
      local min, max = GetParamMinMax(cc,track,nz(f,-1),p,checkov,c)
      return tonumber(min), tonumber(max)

    elseif cc == ctlcats.trackparam then
      local param = strips[tracks[track_select].strip][page].controls[c].param
      local min, max = trctls_table[param].min, trctls_table[param].max
      if checkov then
        if strips[tracks[track_select].strip][page].controls[c].minov then
          min = strips[tracks[track_select].strip][page].controls[c].minov
        end
        if strips[tracks[track_select].strip][page].controls[c].maxov then
          max = strips[tracks[track_select].strip][page].controls[c].maxov
        end
      end
      return tonumber(min), tonumber(max)

    elseif cc == ctlcats.tracksend then
      local param = strips[tracks[track_select].strip][page].controls[c].param
      local idx = math.floor((param-1) % 3)+1
      local min, max = trsends_mmtable[idx].min, trsends_mmtable[idx].max
      if checkov then
        if strips[tracks[track_select].strip][page].controls[c].minov then
          min = strips[tracks[track_select].strip][page].controls[c].minov
        end
        if strips[tracks[track_select].strip][page].controls[c].maxov then
          max = strips[tracks[track_select].strip][page].controls[c].maxov
        end
      end
      return tonumber(min), tonumber(max)

    elseif cc == ctlcats.rs5k then
      min, max = 0, 1
      if checkov then
        if strips[tracks[track_select].strip][page].controls[c].minov then
          min = strips[tracks[track_select].strip][page].controls[c].minov
        end
        if strips[tracks[track_select].strip][page].controls[c].maxov then
          max = strips[tracks[track_select].strip][page].controls[c].maxov
        end
      end
      return tonumber(min), tonumber(max)

    else
      return 0, 1
    end
  end

  function GetParamMinMax_ctl2(strip, page, c, checkov)

    if checkov == nil then checkov = true end

    local t = strips[strip].track.tracknum
    if strips[strip][page].controls[c].tracknum ~= nil then
      t = strips[strip][page].controls[c].tracknum
    end

    local cc = strips[strip][page].controls[c].ctlcat
    if cc == ctlcats.fxparam then
      local f = strips[strip][page].controls[c].fxnum
      local p = strips[strip][page].controls[c].param
      local cc = strips[strip][page].controls[c].ctlcat

      local track = GetTrack(t)
      local min, max = GetParamMinMax(cc,track,nz(f,-1),p,checkov,c)
      return tonumber(min), tonumber(max)

    elseif cc == ctlcats.trackparam then
      local param = strips[strip][page].controls[c].param
      local min, max = trctls_table[param].min, trctls_table[param].max
      if checkov then
        if strips[strip][page].controls[c].minov then
          min = strips[strip][page].controls[c].minov
        end
        if strips[strip][page].controls[c].maxov then
          max = strips[strip][page].controls[c].maxov
        end
      end
      return tonumber(min), tonumber(max)

    elseif cc == ctlcats.tracksend then
      local param = strips[strip][page].controls[c].param
      local idx = math.floor((param-1) % 3)+1
      local min, max = trsends_mmtable[idx].min, trsends_mmtable[idx].max
      if checkov then
        if strips[strip][page].controls[c].minov then
          min = strips[strip][page].controls[c].minov
        end
        if strips[strip][page].controls[c].maxov then
          max = strips[strip][page].controls[c].maxov
        end
      end
      return tonumber(min), tonumber(max)
    else
      return 0, 1
    end
  end

  function FollowSample(v, scnt)
    v=v-1

    if not scnt then scnt = lvar.maxsamples end
    if smshowfavs then
      v = samplefavs.idx[v+1]
      if v then v=v-1 end
      scnt = #samplefavs.samples
    end

    if v and v < smlist_offset then
      smlist_offset = math.min(math.max(v - math.floor(SM_butt_cnt-1),0),scnt-SM_butt_cnt)
    elseif v and v >= smlist_offset + SM_butt_cnt then
      smlist_offset = math.min(math.max(v,0),scnt-SM_butt_cnt)
    else
    end
  end

  ------------------------------------------------------------

  function A_SetParam(strip, page, c, ctl, macrotrigger)

    if strips and strips[strip] and ctl then
      local val = ctl.val
      ctl.mval = val
      local track = GetTrack(ctl.tracknum or strips[strip].track.tracknum)
      --[[if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end]]
      local cc = ctl.ctlcat

      if cc == ctlcats.fxparam then
        local fxnum = ctl.fxnum
        local param = ctl.param
        if fxnum == nil then fxnum = -1 end
        ctl.dirty = true
        --SetCtlDirty(c)
        local min, max = A_GetParamMinMax(cc,track,ctl,fxnum,param,true,c)
        reaper.TrackFX_SetParam(track, fxnum, param, DenormalizeValue(min, max, val))
        _, ctl.dval = reaper.TrackFX_GetFormattedParamValue(track, fxnum, param, "")

      elseif cc == ctlcats.trackparam then
        local param = ctl.param
        ctl.dirty = true
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        SMTI_norm(track,param,val,min,max)

      elseif cc == ctlcats.tracksend then
        local param = ctl.param
        ctl.dirty = true
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        STSI_norm(track,param,val,min,max,c,strip,page)

      elseif cc == ctlcats.action then

        SendAction(ctl.param_info.paramstr, ctl.param_info.paramnum, ctl.param_info.paramidx)

      elseif cc == ctlcats.fxoffline then
        ToggleFXOffline(strip, page, c, strips[strip].track.tracknum)

      elseif cc == ctlcats.macro then

        SetMacro(strip, page, c, nil, lvar.magnetic_active)

      elseif cc == ctlcats.threshold then

        SetThreshold(strip, page, c)

      elseif cc == ctlcats.takeswitcher then
        SetItemTake(strip, page, c)
        if strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end
        lupd.update_ctls = true

      elseif cc == ctlcats.snapshot then

        if ctl.param_info.paramnum == 2 then
          FixedSS(c)
        end

      elseif cc == ctlcats.snapshotrand then
        if mouse.shift and not macrotrigger then
          sstype_select = ctl.param
          ss_select = snapshots[strip][page][sstype_select].selected
          lupd.update_snaps = true
        else
          if mouse.LB and ctl.random and ctl.random.useadv == true then
            Snapshot_RANDOMADV(strip, page, c, ctl.random)
          else
            local sst = ctl.param
            if sst then
              if mouse.LB and not mouse.shift then
                Snapshot_RANDOMIZE(strip, page, sst, true)
              else
                Snapshot_MUTATE(strip, page, sst, true)
              end
            end
          end
        end
        if macrotrigger then
          ctl.val = 0
          ctl.dirty = true
        end
        
      elseif cc == ctlcats.fxgui then

        OpenFXGUI(ctl)

      elseif cc == ctlcats.rs5k then

        ctl.val = math.min(ctl.val, (#ctl.rsdata.samples-1)/lvar.maxsamples)
        local v = math.min(math.floor(ctl.val * (lvar.maxsamples))+1,#ctl.rsdata.samples)
        if rs5k_select == c and sample_select ~= v then
          if show_samplemanager == true then
            lupd.update_samplemanager = true
            if lvar.followsample then
              FollowSample(v,#ctl.rsdata.samples)
            end
          end
          sample_select = v
        end
        if ctl.rsdata.samples[v] and ctl.rsdata.samples[v].fn then
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', ctl.rsdata.samples[v].fol..ctl.rsdata.samples[v].fn)
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        else
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', '')
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        end
        SetCtlDirty(c)

      elseif cc == ctlcats.switcher_pagesel then
        Switcher_ClickPageButton(c)
        ctl.val = 1
        SetCtlDirty(c)

      elseif cc == ctlcats.macro_updateparam then

        MacroUC_Click(ctl)

      elseif cc == ctlcats.statectl then
        SetExtState(ctl)

      elseif cc == ctlcats.navictl then
        NaviCtl_Click(ctl)

      elseif cc == ctlcats.sk2ctl then
        SK2Ctl_Click(ctl, c)
      end

      if ctl.midiout then
        SendMIDIMsg(ctl.midiout,val)
      end
      if ctl.macrofader then
        SetFader(ctl.macrofader, ctl.val)
      end
      
      if ctl.animatetime then
        if lvar.ctltype_buttons[ctl.ctltype] then
          SetAnimate_Ctl(ctl)
        end
      end
      
      if ctl.ctltype == 4 then
        --TSP
        Cycle_SwitcherPage(ctl)
      end
      
      if xPnl.HUD.visible == true and ctl.ctltype ~= 5 then
        SetHUD(ctl)
      end
      
      --[[if ctl.dirty == true then
        SetCtlDirty(c)
      end]]
    end

  end

  function SetAnimate_Ctl(ctl)
  
    if ctl.oval ~= ctl.val then
      local frames = ctl.ctl_info.frames-1
      ctl.animate_st = reaper.time_precise()
      ctl.animate_et = ctl.animate_st + ctl.animatetime
      local val = math.min(ctl.val,1)
      ctl.animate_ef = val
      if ctl.animate_frame then
        ctl.animate_sf = ctl.animate_frame / frames
        if ctl.animate_ef < ctl.animate_sf then
          ctl.animate_et = ctl.animate_st + ctl.animatetime*ctl.animate_sf 
        else
          ctl.animate_et = ctl.animate_et - ctl.animatetime*ctl.animate_sf       
        end
      else
        ctl.animate_sf = 1-val
      end
      ctl.animate_frame = ctl.animate_sf * frames
    end
    
  end

  function SK2Ctl_Click(ctl, c)
    
    --need way to deal with CC's as they do not get triggered in LBX_SKCC module
    --look at SetCCVal in SK2 script
    if tonumber(reaper.GetExtState('SK2DATA_ASSIGN', 'UPDATING')) == 1 then return end
    
    reaper.gmem_attach('LBX_SK2_SharedMem')
    local i = tonumber(ctl.param_info.paramidx)
    if i then
      local t = lvar.sk2data_slots[i]
      local t2 = lvar.sk2data_assign[i]
      if t and t2 then
        if t.lmode == 4 then --button types
          
          if t2.btype ~= 6 then
            reaper.gmem_write(lvar.gm_fb.fader_val +i,16383)
            if t2.btype == 5 then
              mouse.context = contexts.dummy
              lvar.sk2_buttonhold = {ctl = ctl, c = c}
            end
          else
            reaper.gmem_write(lvar.gm_fb.fader_val +i,math.floor(ctl.val * 16383))
          end
        else
          if mouse.context and not lvar.sk2lock then
            lvar.sk2lock = i
            --reaper.gmem_write(lvar.gm_fb.fadertouch+i, 1)
            reaper.SetExtState('SK2DATA_ASSIGN', 'LOCK', i, false)
            reaper.gmem_write(lvar.gm_fb.faderval_lock+i, reaper.time_precise()+0.5)
          elseif mouse.context then
            reaper.gmem_write(lvar.gm_fb.faderval_lock+i, reaper.time_precise()+0.5)
          end
          
          reaper.gmem_write(lvar.gm_fb.fader_val +i,math.floor(ctl.val * 16383))
          reaper.gmem_write(lvar.gm_fb.fader_val2 +i,math.floor(ctl.val * 16383))
          --reaper.gmem_write(lvar.gm_fb.fader_change +i,math.floor(ctl.val * 16383))
        end
      
        local data = reaper.gmem_read(lvar.gm_cc.fdata_fader+i)
        if data ~= -1 then
          --CC
          local fchan = (data & 1920) >> 7;
          local ccnum = data & 127;
          local cc14bit = reaper.gmem_read(lvar.gm_cc.fdata_14bit+i)
          local polarity = reaper.gmem_read(lvar.gm_cc.fdata_polarity+i)
          
          if t.lmode == 4 then --button types
            local bs = reaper.gmem_read(lvar.gm_cc.fbutstate+i) + 1
            local bsc = reaper.gmem_read(lvar.gm_fb.fbutstates+i)
            if bs >= bsc then
              bs = 0
            end
            reaper.gmem_write(lvar.gm_cc.fbutstate+i, bs)
            if bs > 0 then
              reaper.gmem_write(lvar.gm_fb.bstate+i, 1)
            else
              reaper.gmem_write(lvar.gm_fb.bstate+i, 0)
            end
            local v = reaper.gmem_read(lvar.gm_fb.fbutstates_array+((i+1)*32)+bs)
            reaper.gmem_write(lvar.gm_fb.fader_change+i,v)
            if cc14bit ~= 1 then
              reaper.gmem_write(lvar.man_val,(math.floor(v)&127)/127)
              reaper.gmem_write(lvar.man_msg,ccnum)
              reaper.gmem_write(lvar.man_send,1)
            
            else
              reaper.gmem_write(lvar.man_val,(math.floor(v)&16256)/16256)
              reaper.gmem_write(lvar.man_msg,ccnum)
              reaper.gmem_write(lvar.man_send,1)
              --if cc14bit == 1 then
                reaper.gmem_write(lvar.man_val2,(math.floor(v)&127)/127)
                reaper.gmem_write(lvar.man_send2,1)
              --end
            end
            --DBG(bs..'  '..v)
          else
            local v = math.floor(ctl.val * 16383)
            if polarity == 1 then
              if cc14bit == 1 then
                v = 16383 - v
              else
                v = 16383 - v
              end
            end
            
            reaper.gmem_write(lvar.man_val,(v&16256)/16256)
            reaper.gmem_write(lvar.man_msg,ccnum)
            reaper.gmem_write(lvar.man_send,1)
            if cc14bit == 1 then
              reaper.gmem_write(lvar.man_val2,(v&127)/127)
              reaper.gmem_write(lvar.man_send2,1)
            end
          end
          --SetCtlDirty(ctl, c)
        end
      end
    end
  
  end
  
  function NaviCtl_Click(ctl)

    local type_v = ctl.param
    local strip_v = ctl.param_info.paramnum
    local tguid = ctl.param_info.paramstr
    local page_v = tonumber(ctl.param_info.paramidx)
    --DBG(type_v..'  '..strip_v..'  '..tostring(page_v))

    if type_v == 1 then
      --strip/page
      if page_v ~= -1 then
        --not global
        local t, p
        if strip_v == -4 then
          --no change
        elseif strip_v == -3 then
          --prev
          t = track_select - 1
          if gpage == true then
            if gpage_otrackselect then
              t = (gpage_otrackselect) - 1
            end
          end
          if t < -1 then t = #tracks end
          if t == LBX_GTRACK then
            t = t - 1
            if t < -1 then t = #tracks end
          end

          if hideunusedtracks == true and tracksused_idx2.count > 0 then
            while tracksused_idx2[t] == nil do
              t = t - 1
              if t < -1 then t = #tracks end
            end
          end

        elseif strip_v == -2 then
          --next
          t = track_select + 1
          if gpage == true then
            if gpage_otrackselect then
              t = (gpage_otrackselect) + 1
            end
          end
          if t > #tracks then t = -1 end
          if t == LBX_GTRACK then
            t = t + 1
            if t > #tracks then t = -1 end
          end

          if hideunusedtracks == true and tracksused_idx2.count > 0 then
            while tracksused_idx2[t] == nil do
              t = t + 1
              if t > #tracks then t = -1 end
            end
          end

        else
          --specific
          t = ctl.paramnum
        end

        if page_v == -4 then
          --no change
        elseif page_v == -3 then
          --prev
          p = page - 1
          if p < 1 then
            p = 4
          end
        elseif page_v == -2 then
          --next
          p = page + 1
          if p > 4 then
            p = 1
          end
        else
          --specific
          p = page_v
        end

        --DBG(tostring(t)..'  '..tostring(p))
        if t or p then
          if t then
            if t == LBX_GTRACK then
              SetGlobalPage()
            else
              ChangeTrack2(t, p)
              --if p then
                --DBG(p)
                --SetPage(p)
              --end
            end
          else
            SetPage(p)
          end
        end
      else
        --global
        SetGlobalPage()
      end

    elseif type_v == 3 then

      if lvar.livemode == 2 then
        DM_OpenEditMode(ctl)
      end

    end
  end

  local function GetTrackByName(n)

    local track
    for i = 0, reaper.CountTracks(0)-1 do
      track = GetTrack(i)
      if reaper.GetTrackState(track) == n then
        return track
      end
    end

  end

  function DM_EM_AddDummyFX(stripfn, edit_trn)
    if edit_trn then
      local track = GetTrack(edit_trn)
      if track then

        if reaper.TrackFX_GetCount(track) == 0 then

          if reaper.MB('Dynamic Mode strips require at least one FX plugin.\n\nInsert dummy offline FX?','Save Strip',4) == 6 then

            local chunk = GetTrackChunk(track,true)
            local insfxchunk = string.gsub(lvar.lbxdummyfx_chunk,'INSERT',stripfn)
            local nchunk, nguid = Chunk_InsertFXChunkAtEndOfFXChain(trn,chunk,insfxchunk)

            if nchunk then
              SetTrackChunk(track, nchunk, false)
            end
          end
        end
      end
    end
  end

  function DM_SaveSnapsToStrip(swid)

    local t = reaper.time_precise()

    local dmemd = GetOEMData(ctl, swid, edit_trn, p_sfn)

    if dmemd then

      local stripfn = dmemd.stripfn
      local sfn = dmemd.sfn
      if stripfn == 'dynamic_placeholder' or (stripfn or '') == '' then
      elseif stripfn then

        lvar.edmode_ss = true
        if lvar.edmode_ss == true then
          lvar.edmode_ssdata = DM_EdModeSS(swid)
        end

        if lvar.edmode_ssdata then
          --load strip
          local loadstrip, content = LoadStripFN(nil, sfn)
          if loadstrip and loadstrip.version >= 4 then

            --load snapshot data
            if loadstrip.snapcontent then
              local snapcontent = loadstrip.snapcontent
              local data = {}
              local cnt = 0
              local lines = splitln(snapcontent)
              if lines and #lines > 0 then
                for ln = 1, #lines do
                  local idx, val = string.match(lines[ln],'%[(.-)%](.*)')
                  if idx then
                    data[idx] = val
                  end
                end
              end
              loadstrip.snapshots = LoadSnapDataX(nil,data)
            end

            if lvar.edmode_ssdata then
              DM_EdModeSSReplace(lvar.edmode_ssdata, loadstrip)
            end
            lvar.edmode_ssdata = nil

            local content_nosnaps = string.match(content,'(.+%[\\STRIPDATA%]\r?\n)')
            if content_nosnaps then

              file = io.open(sfn,'w')
              if file then

                file:write(content_nosnaps)
                file:write('[SNAPSHOTDATA]\n')
                SaveSnapshotDataX(loadstrip.snapshots,nil,file)
                file:write('[\\SNAPSHOTDATA]\n')

                file:close()

                UpdateStripFileHeader(sfn)
              end
            end

          else
            OpenMsgBox(1,'Strip file version too old.  Please update first.',1)
          end

        else
          OpenMsgBox(1,'No snapshot data to save.',1)
        end

      end
    
      lvar.dm_refreshtrack_active = true
      lvar.dm_refreshtrack = {}
      lvar.dm_refreshtrack[lvar.dynamicmode_guid] = true
    end

    --DBG(reaper.time_precise()-t)
  end

  function DM_OpenEditMode(ctl, swid, p_sfn)

    if lvar.livemode ~= 2 then
      if lvar.analyzer.active then
        DM_ShowAnalyzer(false)
        lupd.update_trbtns = true
        lvar.saveanalactive = true
      end
    end

    --find edit track
    local track = GetTrackByName('__LBXEDIT')

    --if not found - create edit track
    if not track then
      reaper.InsertTrackAtIndex(reaper.GetNumTracks(), false)
      track = GetTrack(reaper.GetNumTracks()-1)
      reaper.GetSetMediaTrackInfo_String(track, "P_NAME", '__LBXEDIT', true)
      reaper.SetMediaTrackInfo_Value(track,'B_MAINSEND',0)
      reaper.SetMediaTrackInfo_Value(track,'D_VOL',0)
      reaper.SetMediaTrackInfo_Value(track,'B_SHOWINTCP',0)
      --reaper.SetMediaTrackInfo_Value(track,'B_SHOWINMIXER',0)
      PopulateTracks()
    end

    local edit_trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1
    local dmemd = GetOEMData(ctl, swid, edit_trn, p_sfn)

    if dmemd then

      local stripfn = dmemd.stripfn
      local sfn = dmemd.sfn
      local edit_trn = dmemd.edit_trn
      local pos = dmemd.pos

      if track then
        if stripfn == 'dynamic_placeholder' or (stripfn or '') == '' then
          --load template
          --local srctrack = GetTrack(lvar.dynamicmode_trn)
          --reaper.TrackFX_CopyToTrack(srctrack,pos,track,0,false)

          lvar.template_strips = PopulateStrips2(paths.templates_folder, lvar.sortcontrols)
          if not lvar.template_strips[0] then

            if plist_w == 0 then
              plist_w = oplist_w
              show_editbar = true
              resize_display = true
            end

            setmode(2)
            ChangeTrack2(edit_trn, 1)

            local strip = tracks[track_select].strip
            for fx = 0, reaper.TrackFX_GetCount(track)-1 do
              reaper.TrackFX_Delete(track, 0)
            end
            ClearPage(page, true)

            local srctrack = GetTrack(lvar.dynamicmode_trn)
            reaper.TrackFX_CopyToTrack(srctrack,pos,track,0,false)
            lvar.dm_editmode_data = dmemd

          else
            obj = PosTemplates(obj)

            lvar.dm_editmode_data_tmp = dmemd
            lvar.show_templatechooser = true
            RedrawGUIBitmap()
            lupd.update_tchooser = true
            lupd.update_surface = true
            
          end
          
        elseif stripfn then

          lvar.edmode_ss = true
          if lvar.edmode_ss == true then
            lvar.edmode_ssdata = DM_EdModeSS(swid)
          end

          if plist_w == 0 then
            plist_w = oplist_w
            show_editbar = true
            resize_display = true
          end

          setmode(2)
          ChangeTrack2(edit_trn, 1)
          lvar.livemode = 0
          
          local strip = tracks[track_select].strip
          for fx = 0, reaper.TrackFX_GetCount(track)-1 do
            reaper.TrackFX_Delete(track, 0)
          end
          ClearPage(page, true)

          --load strip
          local loadstrip = LoadStripFN(nil, sfn)
          if loadstrip then

            reaper.PreventUIRefresh(1)
            local w, h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
            local gs = settings_gridsize
            local x = math.floor(obj.sections[10].w/2) - math.floor(w/2)
            local y = math.floor(obj.sections[10].h/2) - math.floor(h/2)
            x = round(x/gs)*gs
            y = round(y/gs)*gs
            Strip_AddStrip(loadstrip,x,y,true, nil, nil, 0) --, nil, nil, true)

            if lvar.edmode_ssdata then
              DM_EdModeSSReplace(lvar.edmode_ssdata, loadstrip)
            end
            lvar.edmode_ssdata = nil

            reaper.PreventUIRefresh(-1)

          end
          --DBG(sfn)
          --DBG(stripfn)
          lvar.dm_editmode_data = dmemd
          
          CentreAllControls(track_select)
        end
      end

    end

  end

  function DM_EdModeSSReplace(ssdata, stripdata)

    local strip = tracks[track_select].strip
    local ocids = DM_GetStripDataCtls_ocid(stripdata.strip)
    for sst = 1, #ssdata do
      for c = 1, #ssdata[sst].ctls do
        local oc = ssdata[sst].ctls[c].ctl
        local ocid = ssdata.ctltab[oc]
        if ocid then
          ssdata[sst].ctls[c].ctl = ocids[ocid].ctl
          ssdata[sst].ctls[c].c_id = ocids[ocid].cid
        end
      end
      for ss = 1, #ssdata[sst].snapshot do
        for d = 1, #ssdata[sst].snapshot[ss].data do
          local oc = ssdata[sst].snapshot[ss].data[d].ctl
          local ocid = ssdata.ctltab[oc]
          if ocid then
            ssdata[sst].snapshot[ss].data[d].ctl = ocids[ocid].ctl
            ssdata[sst].snapshot[ss].data[d].c_id = ocids[ocid].cid
          end

          if ssdata[sst].snapshot[ss].data[d].mf then
            local oc = ssdata[sst].snapshot[ss].data[d].mfdata.ctl
            local ocid = ssdata.ctltab[oc]
            if ocid then
              ssdata[sst].snapshot[ss].data[d].mfdata.ctl = ocids[ocid].ctl
              ssdata[sst].snapshot[ss].data[d].mfdata.c_id = ocids[ocid].cid
            end
          end
        end
      end
    end

    local snaps = stripdata.snapshots
    if not snaps then
      stripdata.snapshots = Snapshots_sst_INIT()
      snaps = stripdata.snapshots
    end
    for sst = 2, #ssdata+1 do
      snaps[sst] = ssdata[sst-1]
    end
  end

  function DM_EdModeSS(swid)

    local ctltab = DM_GetSwitcherCtls_ocid(swid)
    local strip = tracks[track_select].strip
    local snaps = snapshots[strip][page]
    local ctls = strips[strip][page].controls
    local validsubsets = {}

    local subsets = {}
    if #snaps > 1 then
      for sst = 2, #snaps do
        --DBG('checking sst '..sst)
        local invalid
        for c = 1, #snaps[sst].ctls do
          --DBG(snaps[sst].ctls[c].ctl)
          local ctl = ctls[snaps[sst].ctls[c].ctl]
          if not ctltab[snaps[sst].ctls[c].ctl] then
            --DBG('invalid '..snaps[sst].ctls[c].ctl)
            invalid = true
            break
          end
        end
        if not invalid then
          validsubsets[#validsubsets+1] = sst
        end
      end
    end

    if #validsubsets > 0 then
      for vss = 1, #validsubsets do
        local sst = #subsets+1
        subsets[sst] = table.deepcopy(snaps[validsubsets[vss]])
      end
      subsets.ctltab = ctltab
      return subsets
    end

  end

  function DM_GetStripDataCtls_ocid(stripdata)

    local ctltab = {} --, ctltabidx = {},{}
    local ctls = stripdata.controls
    local cnt = 1
    for c = 1, #ctls do
      ctltab[ctls[c].o_cid] = {ctl = c, cid = ctls[c].c_id}
      cnt = cnt + 1
    end
    return ctltab--, ctltabidx

  end

  function DM_GetStripCtls_ocid(strip)

    local ctltab = {} --, ctltabidx = {},{}
    local ctls = strips[strip][page].controls
    local cnt = 1
    for c = 1, #ctls do
      ctltab[ctls[c].o_cid] = {ctl = c, cid = ctls[c].c_id}
      cnt = cnt + 1
    end
    return ctltab--, ctltabidx

  end

  function DM_GetSwitcherCtls_ocid(swid)

    local ctltab = {} --, ctltabidx = {},{}
    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local cnt = 1
    for c = 1, #ctls do
      if ctls[c].switcher == swid then
        ctltab[c] = ctls[c].o_cid
        --ctltabidx[c] = cnt
        cnt = cnt + 1
      end
    end
    return ctltab--, ctltabidx

  end

  function GetOEMData(ctl, swid, edit_trn, p_sfn)

    if ctl and not swid then
      swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
    end
    --local edit_trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1

    local dmemd = {swid = swid,
                   ctl = ctl,
                   edit_trn = edit_trn,
                   ret_trn = track_select,
                   ret_page = page,
                   plist_w = plist_w,
                   show_editbar = show_editbar}

    if p_sfn then
      local stripfn = string.match(p_sfn, '.+[\\/](.*).strip')
      if stripfn then
        dmemd.sfn = p_sfn
        dmemd.stripfn = stripfn
      end
    end

    if not ctl and not swid then
      return dmemd
    end

    if swid then
      local sw_ctl = switchers[swid]
      local pos = sw_ctl.extendpos-1

      dmemd.extid = switchers[swid].extendid

      local grpid = sw_ctl.current

      local grpids = switchers[swid].grpids
      local grpididx
      for g = 1, #grpids do
        if grpids[g].id == grpid then
          grpididx = g
          break
        end
      end

      if grpididx then
        local sfn = sw_ctl.grpids[grpididx].stripfn
        local plugname = string.match(sw_ctl.grpids[grpididx].name,"^%s*(.-)%s*$")
        if sfn then
          local stripfn = string.match(sfn, '.+[\\/](.*).strip')

          --force full path name
          if not string.match(sfn,'/strips/') then
            sfn = paths.strips_path..sfn
          end

          dmemd.sfn = sfn
          dmemd.stripfn = stripfn
          dmemd.plugname = plugname
          dmemd.pos = pos

        end
      end
    end

    return dmemd

  end

  function DM_OpenEditMode_old(ctl, swid)

    --find edit track
    local track = GetTrackByName('__LBXEDIT')

    --if not found - create edit track
    if not track then
      reaper.InsertTrackAtIndex(reaper.GetNumTracks(), false)
      track = GetTrack(reaper.GetNumTracks()-1)
      reaper.GetSetMediaTrackInfo_String(track, "P_NAME", '__LBXEDIT', true)
      reaper.SetMediaTrackInfo_Value(track,'B_MAINSEND',0)
      reaper.SetMediaTrackInfo_Value(track,'D_VOL',0)
      reaper.SetMediaTrackInfo_Value(track,'B_SHOWINTCP',0)
      --reaper.SetMediaTrackInfo_Value(track,'B_SHOWINMIXER',0)
      PopulateTracks()
    end

    --copy fx plugin

    if not swid then
      swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
    end
    local edit_trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1

    local dmemd = {swid = swid,
                   ctl = ctl,
                   edit_trn = edit_trn,
                   ret_trn = track_select,
                   ret_page = page}

    local success

    if swid then
      local sw_ctl = switchers[swid]
      local pos = sw_ctl.extendpos-1

      local grpid = sw_ctl.current

      local grpids = switchers[swid].grpids
      local grpididx
      for g = 1, #grpids do
        if grpids[g].id == grpid then
          grpididx = g
          break
        end
      end

      if grpididx then
        local sfn = sw_ctl.grpids[grpididx].stripfn
        local plugname = string.match(sw_ctl.grpids[grpididx].name,"^%s*(.-)%s*$")
        if sfn then
          local stripfn = string.match(sfn, '.+[\\/](.*).strip')

          dmemd.sfn = sfn
          dmemd.stripfn = stripfn
          dmemd.plugname = plugname
          dmemd.pos = pos

          setmode(2)
          ChangeTrack2(edit_trn, 1)

          local strip = tracks[track_select].strip
          for fx = 0, reaper.TrackFX_GetCount(track)-1 do
            reaper.TrackFX_Delete(track, 0)
          end
          ClearPage(page, true)

          if stripfn == 'dynamic_placeholder' then
            --load template
            local srctrack = GetTrack(lvar.dynamicmode_trn)
            reaper.TrackFX_CopyToTrack(srctrack,pos,track,0,false)

            success = true

          elseif stripfn then
            --load strip
            local loadstrip = LoadStripFN(nil, sfn)
            if loadstrip then

              reaper.PreventUIRefresh(1)
              local w, h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
              local gs = settings_gridsize
              local x = math.floor(obj.sections[10].w/2) - math.floor(w/2)
              local y = math.floor(obj.sections[10].h/2) - math.floor(h/2)
              x = round(x/gs)*gs
              y = round(y/gs)*gs
              Strip_AddStrip(loadstrip,x,y,true, nil, nil, 0)
              reaper.PreventUIRefresh(-1)

            end
            success = true
          end
        end
      end
    end
    if success then
      lvar.dm_editmode_data = dmemd
    end

  end

  function SetExtState(ctl)
    local extname = ctl.stateinfo.extname
    local key = ctl.stateinfo.key
    if extname and key then

      local v = F_limit(ctl.stateinfo.min + round((ctl.val * (ctl.stateinfo.max-ctl.stateinfo.min))/ctl.stateinfo.step)*ctl.stateinfo.step,
                        ctl.stateinfo.min, ctl.stateinfo.max)
      --DBG(extname..'  '..key..'  '..v..'  '..ctl.val..'  ')
      reaper.SetExtState(extname,key,tostring(v), true)

    end

  end

  function SendAction(acttype, commandid, commandname)

    local cmd
    if commandid == nil then
      cmd = commandname
      if cmd ~= nil then
        if string.sub(cmd,1,1) ~= '_' then
          cmd = '_'..cmd
        end
      end
    end
    if tonumber(acttype) == 32060 then
      local hwnd = reaper.MIDIEditor_GetActive()
      if hwnd then
        if commandid then
          reaper.MIDIEditor_OnCommand(hwnd, commandid)
        else
          reaper.MIDIEditor_OnCommand(hwnd, reaper.NamedCommandLookup(cmd))
        end
      end
    else
      if commandid then
        reaper.Main_OnCommand(commandid, 0)
      elseif cmd then
        reaper.Main_OnCommand(reaper.NamedCommandLookup(cmd), 0)
      end
    end
  end

  function SetThreshold(strip, page, c)

    local ctl = strips[strip][page].controls[c]
    local thresh_on = ctl.thresh.thresh_on/128
    local thresh_off = ctl.thresh.thresh_off/128

    local onval = ctl.thresh.val_on
    local offval = ctl.thresh.val_off
    if ctl.thresh.invert == true then
      offval = ctl.thresh.val_on
      onval = ctl.thresh.val_off
    end

    local track = GetTrack(ctl.tracknum or strips[strip].track.tracknum)
    local curval = reaper.TrackFX_GetParam(track,ctl.fxnum,ctl.param)

    if ctl.val <= thresh_off and curval ~= offval then

      --if ctl.threshval ~= false then
        --local track = GetTrack(ctl.tracknum or strips[strip].track.tracknum)
        reaper.TrackFX_SetParam(track, ctl.fxnum, ctl.param, offval)
        ctl.threshval = false
      --end

    elseif ctl.val >= thresh_on and curval ~= onval then

      --if ctl.threshval ~= true then
        --local track = GetTrack(ctl.tracknum or strips[strip].track.tracknum)
        reaper.TrackFX_SetParam(track, ctl.fxnum, ctl.param, onval)
        ctl.threshval = true
      --end

    end

  end

  function MacroUC_Click(ctl)

    local macro = ctl.macroctl
    if macro then
      local strip = tracks[track_select].strip

      for i = 1, #macro do
        local cctl = strips[strip][page].controls[macro[i].ctl]
        if cctl then
          if macro[i].c_id == cctl.c_id then

            A_SetParam(strip,page,macro[i].ctl,cctl)

          end
        end
      end

    end

  end

  function Switcher_ClickPageButton(c)

    --local t = reaper.time_precise()
    local ctls = strips[tracks[track_select].strip][page].controls
    local gfxx = strips[tracks[track_select].strip][page].graphics
    local switchid = ctls[c].switcherid
    local grpid = ctls[c].param

    if switchers[switchid] then
      local grpids = switchers[switchid].grpids

      local grpididx
      for g = 1, #grpids do
        if grpids[g].id == grpid then
          grpididx = g
          break
        end
      end

      if grpididx then
        --local ocurrent = switchers[switchid].current
        switchers[switchid].current = switchers[switchid].grpids[grpididx].id
        local ubg
        for i = 1, #ctls do
          if ctls[i].ctlcat == ctlcats.switcher then
            if ctls[i].switcherid == switchid then
              ctls[i].param_info.paramname = string.format('%i',grpididx)..': '..switchers[switchid].grpids[grpididx].name
              SetCtlDirty(i)
            end
          elseif ctls[i].ctlcat == ctlcats.switcher_pagesel then
            if ctls[i].switcherid == switchid and (ctls[i].param ~= grpid --[[or ctls[i].param == ocurrent]]) then
              ctls[i].val = 0
              SetCtlDirty(i)
              if ctls[i].animatetime then
                if lvar.ctltype_buttons[ctls[i].ctltype] then
                  SetAnimate_Ctl(ctls[i])
                end
              end
            end
          elseif ctls[i].switcher == switchid then
            SetCtlDirty(i)
            if ctls[i].grpid ~= grpid then
              ctls[i].forceredraw = true
            end
            if ctls[i].gauge then
              ubg = true
            end
          end
        end
        if not ubg then
          for i = 1, #gfxx do
            if gfxx[i].switcherid == switchid then
              ubg = true
              break
            end
          end
        end
        
        if ubg then
          lupd.update_bg = true
          lupd.update_gfx = true
        else
          --lupd.update_bg = true
          --lupd.update_gfx = true
          lupd.update_ctls = true
          lupd.update_surface = true
          lvar.forceredraw = true
        end
        SetCtlBitmapRedraw()

      end
    end
    --DBG(reaper.time_precise() - t)
  end

  function SendAllNotesOffToTrack(trn)

    reaper.PreventUIRefresh(1)
    local osel = reaper.GetSelectedTrack(0, 0)
    local track = GetTrack(trn)
    if track then
      reaper.SetOnlyTrackSelected(track)
      reaper.Main_OnCommand(reaper.NamedCommandLookup('_S&M_CC123_SEL_TRACKS'),0)
      if osel then
        reaper.SetOnlyTrackSelected(osel)
      end
    end
    reaper.PreventUIRefresh(-1)

  end

  function SendAllNotesOff()

    reaper.Main_OnCommand(40345,0)

  end

  function SetFader(f, val)
    if LBX_CTL_TRACK then
      local track = GetTrack(LBX_CTL_TRACK)
      if track then
        local fxnum = math.floor((f-1) / 32)
        local p = (f-1) % 32
        reaper.TrackFX_SetParam(track, fxnum, p, val)
        faders[f].oval = round(val,5)
      end
    end
  end

  function OpenFXGUI(ctl)
    local track
    if ctl.tracknum == nil then
      track = GetTrack(tracks[track_select].tracknum)
    else
      track = GetTrack(ctl.tracknum)
    end
    local fxnum = ctl.fxnum
    reaper.TrackFX_Show(track, fxnum, 3)
    ctl.val = 1
    ctl.dirty = true
  end

  function CloseFXGUI(ctl)
    local track
    if ctl.tracknum == nil then
      track = GetTrack(tracks[track_select].tracknum)
    else
      track = GetTrack(ctl.tracknum)
    end
    local fxnum = ctl.fxnum
    reaper.TrackFX_Show(track, fxnum, 2)
    ctl.val = 0
    ctl.dirty = true
  end

  function SetItemTake(strip, page, c)
    local ctl = strips[strip][page].controls[c]
    if ctl.iteminfo then
    --DBG(ctl.iteminfo.guid)
      local item = GetMediaItemByGUID(ctl.iteminfo.guid)
      local takeval = math.min(math.floor(ctl.val * takeswitch_max),ctl.iteminfo.numtakes-1)
      --DBG(takeval)
      ctl.val = takeval/takeswitch_max
      if item then

        if ctl.iteminfo.noteoff then
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if trn then
            if ctl.iteminfo.utilfxn then
              local track = GetTrack(trn)
              if track and ctl.iteminfo.utilguid == reaper.TrackFX_GetFXGUID(track,ctl.iteminfo.utilfxn) then
                reaper.TrackFX_SetParamNormalized(track,ctl.iteminfo.utilfxn,0,1)
              end

            else
              --SendAllNotesOff()
            end
          end
        end

        reaper.SetMediaItemInfo_Value(item,'I_CURTAKE',takeval)

        local take = reaper.GetTake(item, takeval)
        if take then
          _, ctl.iteminfo.curtake = reaper.GetSetMediaItemTakeInfo_String(take, 'P_NAME', '', false)
        else
          ctl.iteminfo.curtake = 'empty'
        end

        reaper.UpdateArrange()
        --DBG(takeval)sf
      end
      --DBG(takeval)

    end

  end

  function SetItemTake2(strip, page, c)

    local ctl = strips[strip][page].controls[c]
    if ctl.iteminfo then
    --DBG(ctl.iteminfo.guid)
      local item = GetMediaItemByGUID(ctl.iteminfo.guid)
      local takeval = math.min(math.floor(ctl.val * takeswitch_max),ctl.iteminfo.numtakes-1)

      ctl.val = takeval/takeswitch_max
      if item then

        if ctl.iteminfo.noteoff then
          local trn = ctl.tracknum or tracks[track_select].tracknum
          if trn then
            --SendAllNotesOffToTrack(trn)
            if ctl.iteminfo.utilfxn then
              local track = GetTrack(trn)
              if track and ctl.iteminfo.utilguid == reaper.TrackFX_GetFXGUID(track,ctl.iteminfo.utilfxn) then
                reaper.TrackFX_SetParamNormalized(track,ctl.iteminfo.utilfxn,0,1)
              end

            else
              SendAllNotesOff()
            end
          end
        end

        reaper.SetMediaItemInfo_Value(item,'I_CURTAKE',takeval)

        local take = reaper.GetTake(item, takeval)
        if take then
          _, ctl.iteminfo.curtake = reaper.GetSetMediaItemTakeInfo_String(take, 'P_NAME', '', false)
        else
          ctl.iteminfo.curtake = 'empty'
        end

        reaper.UpdateArrange()
        --DBG(takeval)sf
      end
      --DBG(takeval)

    end

  end

------------------------------------------------------------
--replace with A_SetParam
  function SetParam()

    if strips and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[trackfxparam_select] then
      local val = strips[tracks[track_select].strip][page].controls[trackfxparam_select].val
      local track
      if strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum == nil then
        track = GetTrack(strips[tracks[track_select].strip].track.tracknum)
      else
        track = GetTrack(strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum)
      end
      local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
      if cc == ctlcats.fxparam then

        local fxnum = strips[tracks[track_select].strip][page].controls[trackfxparam_select].fxnum
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,trackfxparam_select)
        --reaper.Undo_BeginBlock2(0)
        reaper.TrackFX_SetParam(track, nz(fxnum,-1), param, DenormalizeValue(min, max, val))
        --reaper.Undo_EndBlock2(0,"RRR",-1)
      elseif cc == ctlcats.trackparam then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,true,trackfxparam_select)
        SMTI_norm(track,param,val,min,max)

      elseif cc == ctlcats.tracksend then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,true,trackfxparam_select)
        STSI_norm(track,param,val,min,max,trackfxparam_select, tracks[track_select].strip, page)

      elseif cc == ctlcats.action then

        --[[local dcmd = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramnum
        if dcmd ~= nil then
          reaper.Main_OnCommand(dcmd, 0)
        else
          local cmd = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramidx
          if cmd ~= nil then
            if string.sub(cmd,1,1) ~= '_' then
              cmd = '_'..cmd
            end
            reaper.Main_OnCommand(reaper.NamedCommandLookup(cmd), 0)
          end
        end ]]
        local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
        SendAction(ctl.param_info.paramstr, ctl.param_info.paramnum, ctl.param_info.paramidx)

      elseif cc == ctlcats.fxoffline then
        ToggleFXOffline(tracks[track_select].strip, page, trackfxparam_select, tracks[track_select].tracknum)
      elseif cc == ctlcats.macro then
        SetMacro(tracks[track_select].strip, page, trackfxparam_select)
      elseif cc == ctlcats.sk2ctl then
        local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
        ctl.val = val
        SK2Ctl_Click(ctl, trackfxparam_select)
      elseif cc == ctlcats.threshold then
        SetThreshold(tracks[track_select].strip, page, trackfxparam_select)
      end
    end

  end

------------------------------------------------------------

  function SetParam2(force)

    if strips and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[trackfxparam_select] then
      local val = strips[tracks[track_select].strip][page].controls[trackfxparam_select].val
      if strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum == nil then
        track = GetTrack(strips[tracks[track_select].strip].track.tracknum)
      else
        track = GetTrack(strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum)
      end
      local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
      if cc == ctlcats.fxparam then
        local fxnum = strips[tracks[track_select].strip][page].controls[trackfxparam_select].fxnum
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        --local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,trackfxparam_select)
        if force and force == true then
          reaper.TrackFX_SetParam(track, nz(fxnum,-1), param, DenormalizeValue(min, max, 1-math.abs(val-0.1)))
        end
        reaper.TrackFX_SetParam(track, nz(fxnum,-1), param, DenormalizeValue(min, max, val))

      elseif cc == ctlcats.trackparam then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,true,trackfxparam_select)
        if force and force == true then
          SMTI_norm(track,param,1-math.abs(val-0.1),min,max)
        end
        SMTI_norm(track,param,val,min,max)

      elseif cc == ctlcats.tracksend then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,true,trackfxparam_select)
        if force and force == true then
          STSI_norm(track,param,1-math.abs(val-0.1),min,max,trackfxparam_select, tracks[track_select].strip, page)
        end
        STSI_norm(track,param,val,min,max,trackfxparam_select, tracks[track_select].strip, page)
      end
    end

  end

------------------------------------------------------------

  function SetParam3(strip,page,c,ctl,v)

    if strips and strips[strip] and ctl then
      if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end
      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam then

        if not track then return end

        local fxnum = nz(ctl.fxnum,-1)

        local param = ctl.param
        local min, max = A_GetParamMinMax(cc,track,ctl,fxnum,param,true,c)
        ctl.val = DenormalizeValue(min, max, v)
        reaper.TrackFX_SetParam(track, fxnum, param, ctl.val)

      elseif cc == ctlcats.trackparam then

        if not track then return end

        local param = ctl.param
        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        ctl.val = SMTI_norm(track,param,v,min,max)

      elseif cc == ctlcats.tracksend then

        if not track then return end

        local param = ctl.param
        ctl.dirty = true
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        ctl.val = STSI_norm(track,param,v,min,max,c,strip,page)

      elseif cc == ctlcats.fxoffline then

        if not track then return end
        SetFXOffline2(strip, page, c, track, v)

      elseif cc == ctlcats.takeswitcher then
        local vv = math.floor(v*takeswitch_max)/takeswitch_max
        if vv ~= ctl.val then
          ctl.val = vv
          SetItemTake2(strip, page, c)
          if strip == tracks[track_select].strip and page == page then
            SetCtlDirty(c)
          end
        end

      elseif cc == ctlcats.midictl then
        ctl.val = v
        ctl.dirty = true

      elseif cc == ctlcats.statectl then
        ctl.val = v
        ctl.dirty = true

      elseif cc == ctlcats.rs5k then

        ctl.val = v
        local v = math.min(math.floor(ctl.val * (lvar.maxsamples-1))+1,#ctl.rsdata.samples)
        if rs5k_select == c and sample_select ~= v then
          if show_samplemanager == true then
            lupd.update_samplemanager = true
            if lvar.followsample then
              FollowSample(v,#ctl.rsdata.samples)
            end
          end
          sample_select = v
        end

        if ctl.rsdata.samples[v] and ctl.rsdata.samples[v].fn then
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', ctl.rsdata.samples[v].fol..ctl.rsdata.samples[v].fn)
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        else
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', '')
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        end

        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end

      elseif cc == ctlcats.macro then

        ctl.val = v
        SetMacro(strip, page, c)
        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end
      end

      if ctl.midiout then SendMIDIMsg(ctl.midiout,v) end
    end

  end

  --[[function DM_GetFXGUID(track, fxguid)
    for f = 0, reaper.TrackFX_GetCount(track)-1 do
      if fxguid == reaper.TrackFX_GetFXGUID(track, f) then
        return f
      end
    end

  end]]

  function DM_SetParam3(guid,c,v)

    local dm_strip = lvar.stripstore[guid]
    if dm_strip == nil then return end
    local ctl = dm_strip.controls[c]

    if ctl and v ~= ctl.val then
      local track
      local strip = tracks[track_select].strip
      if ctl.tracknum == nil then
        local trn
        if not dm_strip.trn then
          dm_strip.trn, track = GetTRNfromGUID(guid)
        else
          track = GetTrack(dm_strip.trn)
          if not dm_strip.trn == GetTrackGUID(track) then
            dm_strip.trn, track = GetTRNfromGUID(guid)
          end
        end
      else
        track = GetTrack(ctl.tracknum)
      end

      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam then

        if not track then return end

        local fxnum = nz(ctl.fxnum,-1)
        if reaper.TrackFX_GetFXGUID(track,fxnum) ~= ctl.fxguid then
          fxnum = GetFXNFromGUID(track, ctl.fxguid)
          if not fxnum then return end
          ctl.fxnum = fxnum
        end

        local param = ctl.param
        local min, max = A_GetParamMinMax(cc,track,ctl,fxnum,param,true,c)
        ctl.val = DenormalizeValue(min, max, v)
        reaper.TrackFX_SetParam(track, fxnum, param, ctl.val)

      elseif cc == ctlcats.trackparam then

        if not track then return end

        local param = ctl.param
        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        ctl.val = SMTI_norm(track,param,v,min,max)

      elseif cc == ctlcats.tracksend then

        if not track then return end

        local param = ctl.param
        ctl.dirty = true
        local min, max = A_GetParamMinMax(cc,track,ctl,nil,param,true,c)
        ctl.val = STSI_norm(track,param,v,min,max,c,strip,page)

      elseif cc == ctlcats.fxoffline then

        if not track then return end
        SetFXOffline2(strip, page, c, track, v)

      elseif cc == ctlcats.takeswitcher then
        local vv = math.floor(v*takeswitch_max)/takeswitch_max
        if vv ~= ctl.val then
          ctl.val = vv
          SetItemTake2(strip, page, c)
          if strip == tracks[track_select].strip and page == page then
            SetCtlDirty(c)
          end
        end

      elseif cc == ctlcats.midictl then
        ctl.val = v
        ctl.dirty = true

      elseif cc == ctlcats.statectl then
        ctl.val = v
        ctl.dirty = true

      elseif cc == ctlcats.rs5k then

        ctl.val = v
        local v = math.min(math.floor(ctl.val * (lvar.maxsamples-1))+1,#ctl.rsdata.samples)
        if rs5k_select == c and sample_select ~= v then
          if show_samplemanager == true then
            lupd.update_samplemanager = true
            if lvar.followsample then
              FollowSample(v,#ctl.rsdata.samples)
            end
          end
          sample_select = v
        end

        if ctl.rsdata.samples[v] and ctl.rsdata.samples[v].fn then
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', ctl.rsdata.samples[v].fol..ctl.rsdata.samples[v].fn)
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        else
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', '')
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        end

        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end

      elseif cc == ctlcats.macro then

        ctl.val = v
        SetMacro(strip, page, c)
        if (settings_enablednu ~= true or ctl.dnu ~= true) and strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end
      end

      if ctl.midiout then SendMIDIMsg(ctl.midiout,v) end
    end

  end

  function SetParam3_Denorm2_Safe(track, v, strip, page)

    local ctl = strips[strip][page].controls[trackfxparam_select]
    if strips and strips[strip] and ctl then
      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam then
        local fxnum = ctl.fxnum
        local param = ctl.param
        reaper.TrackFX_SetParam(track, fxnum or -1, param, v)

      elseif cc == ctlcats.trackparam then
        local param = ctl.param
        ctl.dirty = true
        SMTI_denorm(track,param,v)

      elseif cc == ctlcats.tracksend then
        local param = strips[strip][page].controls[trackfxparam_select].param
        ctl.dirty = true
        STSI_denorm(track,param,v,trackfxparam_select,strip,page)
      end
      if ctl.midiout then SendMIDIMsg(ctl.midiout,v) end
    end

  end

  function SetParam3_Denorm2_Safe2(track, v, strip, page, reaper, c, nv)

    local ctl = strips[strip][page].controls[c]
    if strips and strips[strip] and ctl then
      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam then
        if not track then return end

        local fxnum = ctl.fxnum
        local param = ctl.param
        reaper.TrackFX_SetParam(track, fxnum or -1, param, v)
        ctl.val = nv
        ctl.dirty = true

      elseif cc == ctlcats.trackparam then
        if not track then return end
        local param = ctl.param
        ctl.val = v
        ctl.dirty = true

        SMTI_denorm(track,param,v)

      elseif cc == ctlcats.tracksend then
        if not track then return end
        local param = ctl.param
        --ctl.val = v
        --ctl.dirty = true
        STSI_denorm(track,param,v,c,strip,page)

      elseif cc == ctlcats.takeswitcher then
        ctl.val = v
        SetItemTake(strip, page, c)
        if strip == tracks[track_select].strip and page == page then
          SetCtlDirty(c)
        end

      elseif cc == ctlcats.fxoffline then
        if not track then return end
        SetFXOffline2(strip, page, c, track, v)

      elseif cc == ctlcats.rs5k then

        ctl.val = v
        local v = math.min(math.floor(ctl.val * (lvar.maxsamples))+1,#ctl.rsdata.samples)
        if rs5k_select == c and sample_select ~= v then
          if show_samplemanager == true then
            lupd.update_samplemanager = true
            if lvar.followsample then
              FollowSample(v,#ctl.rsdata.samples)
            end
          end
          sample_select = v
        end

        if ctl.rsdata.samples[v] and ctl.rsdata.samples[v].fn then
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', ctl.rsdata.samples[v].fol..ctl.rsdata.samples[v].fn)
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        else
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', '')
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        end

        SetCtlDirty(c)

      elseif cc == ctlcats.midictl then
        ctl.val = v
        ctl.dirty = true

      elseif cc == ctlcats.fxmulti then
        ctl.val = v
        local state = FXMulti_GetState2(v)
        FXMulti_SetMainFX(ctl, state)

        --local state = FXMulti_GetState(track, ctl)
        FXMulti_SetAddFX(ctl, state)
      
      elseif cc == ctlcats.switcher_pagesel and v == 1 then
        Switcher_ClickPageButton(c)
        ctl.val = 1
        SetCtlDirty(c)
        
      end
      if ctl.midiout then SendMIDIMsg(ctl.midiout,v) end

    end

  end

  function SetParam4(v)

    if strips and strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[trackfxparam_select] then
      if strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum == nil then
        track = GetTrack(strips[tracks[track_select].strip].track.tracknum)
      else
        track = GetTrack(strips[tracks[track_select].strip][page].controls[trackfxparam_select].tracknum)
      end
      local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
      if cc == ctlcats.fxparam then
        local fxnum = strips[tracks[track_select].strip][page].controls[trackfxparam_select].fxnum
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        local cc = strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat
        local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param)
        reaper.TrackFX_SetParam(track, nz(fxnum,-1), param, DenormalizeValue(min, max, v))

      elseif cc == ctlcats.trackparam then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        --local min, max = trctls_table[param].min,trctls_table[param].max
        SMTI_norm(track,param,v,0,1)

      elseif cc == ctlcats.tracksend then
        local param = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        --local min, max = trctls_table[param].min,trctls_table[param].max
        STSI_norm(track,param,v,0,1,trackfxparam_select, tracks[track_select].strip, page)
      end
    end

  end

------------------------------------------------------------
  --ignore internal minmax
  function SetParam5(v)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[trackfxparam_select]
    if strips and strips[strip] and ctl then
      if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end
      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam then
        local fxnum = ctl.fxnum
        local param = ctl.param
        local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,false,trackfxparam_select)
        reaper.TrackFX_SetParam(track, nz(fxnum,-1), param, DenormalizeValue(min, max, v))

      elseif cc == ctlcats.trackparam then
        local param = ctl.param
        ctl.dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,false,trackfxparam_select)
        SMTI_norm(track,param,v,min,max)

      elseif cc == ctlcats.tracksend then
        local param = ctl.param
        ctl.dirty = true
        local min, max = GetParamMinMax(cc,track,nil,param,false,trackfxparam_select)
        STSI_norm(track,param,v,min,max,trackfxparam_select,strip,page)
      end
      if ctl.midiout then SendMIDIMsg(ctl.midiout,v) end
    end

  end

  ------------------------------------------------------------
  function Lasso_Select_Gfx(shift)

    gfx4_select = table.copy(lasso.gfx4_select) or nil
    
    local l = {l = lasso.l, r = lasso.r, t = lasso.t, b = lasso.b}
    if lasso.r < lasso.l then
      l.l = lasso.r
      l.r = lasso.l
    end
    if lasso.b < lasso.t then
      l.b = lasso.t
      l.t = lasso.b
    end

    local strip = tracks[track_select].strip
    if strips and strips[strip] then

      if #strips[tracks[track_select].strip][page].graphics > 0 then

        for i = 1, #strips[tracks[track_select].strip][page].graphics do
          local g
          local gfxx = strips[tracks[track_select].strip][page].graphics[i]
          g = {x = gfxx.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                     y = gfxx.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                     w = gfxx.stretchw*lvar.zoom,
                     h = gfxx.stretchh*lvar.zoom,
                     p = gfxx.gfxpage or 0}
          if g.p == 0 and ((l.l <= g.x and l.r >= g.x+g.w) or (l.l <= g.x+g.w and l.r >= g.x)) and ((l.t <= g.y and l.b >= g.y+g.h) or (l.t <= g.y+g.h and l.b >= g.y)) then

            if Switcher_CtlsHidden(gfxx.switcher, gfxx.grpid) == false then
              if gfx4_select == nil then
                gfx4_select = {}
                gfx4_selectidx = {}
              end
              local cs = #gfx4_select+1
              gfx4_select[cs] = {}
              gfx4_select[cs] = i
              gfx4_selectidx[i] = cs
              --gfx4_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[i].x
              --gfx4_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[i].y
            end
          end
        end
      end

    end

  end

  function Lasso_Select(shift)

    ctl_select = table.copy(lasso.ctl_select) or nil
    gfx3_select = table.copy(lasso.gfx3_select) or nil

    local l = {l = lasso.l, r = lasso.r, t = lasso.t, b = lasso.b}
    if lasso.r < lasso.l then
      l.l = lasso.r
      l.r = lasso.l
    end
    if lasso.b < lasso.t then
      l.b = lasso.t
      l.t = lasso.b
    end

    if strips and strips[tracks[track_select].strip] then
      if #strips[tracks[track_select].strip][page].controls > 0 then

        for i = 1, #strips[tracks[track_select].strip][page].controls do
          local ctl
          local cctl = strips[tracks[track_select].strip][page].controls[i]
          ctl = {x = cctl.xsc*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                     y = cctl.ysc*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                     w = cctl.wsc*lvar.zoom,
                     h = cctl.hsc*lvar.zoom}
          if ((l.l <= ctl.x and l.r >= ctl.x+ctl.w) or (l.l <= ctl.x+ctl.w and l.r >= ctl.x)) and ((l.t <= ctl.y and l.b >= ctl.y+ctl.h) or (l.t <= ctl.y+ctl.h and l.b >= ctl.y)) then

            if Switcher_CtlsHidden(cctl.switcher, cctl.grpid) == false then
              if ctl_select == nil then
                ctl_select = {}
                ctl_select[1] = {ctl = i}
              else
                local cs = #ctl_select+1
                ctl_select[cs] = {}
                ctl_select[cs].ctl = i
                ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
                ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
              end
            end
          end
        end
      end

      if shift and ctl_select then

        if #strips[tracks[track_select].strip][page].graphics > 0 then

          for i = 1, #strips[tracks[track_select].strip][page].graphics do
            local g
            local gfxx = strips[tracks[track_select].strip][page].graphics[i]
            g = {x = gfxx.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                       y = gfxx.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                       w = gfxx.stretchw*lvar.zoom,
                       h = gfxx.stretchh*lvar.zoom}
            if ((l.l <= g.x and l.r >= g.x+g.w) or (l.l <= g.x+g.w and l.r >= g.x)) and ((l.t <= g.y and l.b >= g.y+g.h) or (l.t <= g.y+g.h and l.b >= g.y)) then

              if Switcher_CtlsHidden(gfxx.switcher, gfxx.grpid) == false then
                if gfx3_select == nil then
                  gfx3_select = {}
                end
                local cs = #gfx3_select+1
                gfx3_select[cs] = {}
                gfx3_select[cs].ctl = i
                gfx3_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[i].x
                gfx3_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[i].y
              end
            end
          end
        end


      end
    end
  end

  ------------------------------------------------------------

  function StoreSnapshotControls()

    if strips then
      for s = 1, #strips do
        if strips[s] then
          for p = 1, lvar.maxpage do
            StoreSnapshotControlIdxs(s, p)
          end
        end
      end
    end
  end

  function StoreSnapshotControlIdxs(s, p)
    if strips and strips[s] and strips[s][p] then
      strips[s][p].snapctls = {}
      if #strips[s][p].controls > 0 then
        for c = 1, #strips[s][p].controls do
          local ctl = strips[s][p].controls[c]
          if ctl.ctlcat == ctlcats.snapshot then
            local sst = ctl.param
            strips[s][p].snapctls[#strips[s][p].snapctls+1] = c
          end
        end
      end
    end

  end
  
  function RefreshSnapshotControls(s, p)
    if strips and strips[s] and strips[s][p].snapctls then
      local ctls = strips[s][p].controls
      for sc = 1, #strips[s][p].snapctls do
        local c = strips[s][p].snapctls[sc]
        local sst = ctls[c].param
        local snaps = snapshots[s][p][sst]
        if sst == 1 then
        else
          local ssmatch 
          for s = 1, #snaps.snapshot do
            ssmatch = s
            local snapdata = snaps.snapshot[s].data
            for d = 1, #snapdata do
              local ctl = ctls[snapdata[d].ctl]
              if tostring(snapdata[d].val) ~= tostring(ctl.val) then
                ssmatch = nil
                break
              end
            end
            if ssmatch then
              break
            end
          end
          if ssmatch then
            snaps.selected = ssmatch
          else
            snaps.selected = 0
          end
        end
      end
    end
  end

  function GetSnapshotMatch(sst, s, p)
    local ssmatch 
    if strips and strips[s] then
      local ctls = strips[s][p].controls
      if sst then
        local snaps = snapshots[s][p][sst]
        if sst == 1 then
        else
          for s = 1, #snaps.snapshot do
            ssmatch = s
            local snapdata = snaps.snapshot[s].data
            for d = 1, #snapdata do
              local ctl = ctls[snapdata[d].ctl]
              if tostring(snapdata[d].val) ~= tostring(ctl.val) then
                ssmatch = nil
                break
              end
            end
            if ssmatch then
              break
            end
          end
        end
      end
    end
    return ssmatch
  end

  function CheckDataTables(allstrips, verbose, ts, pg)
    --DBG('CheckDataTables '..tostring(allstrips))
    if lvar.checkdatatables_active == true then
      if allstrips == true then

        for s = 1, #strips do
          CheckStripControls(s)
          for p = 1, lvar.maxpage do
            Snapshots_Check(s,p,verbose)
            Macros_Check(s,p)
            Faders_Check(s,p)
            StoreSnapshotControlIdxs(s,p)
            CheckRandom(s, p)
          end
        end
        IndexAllExtIdentifiers()
      else
        if not ts then
          ts = track_select
          pg = page
        end
        Snapshots_Check(tracks[ts].strip,pg,verbose)
        Macros_Check(tracks[ts].strip,pg)
        Faders_Check(tracks[ts].strip,pg)
        StoreSnapshotControlIdxs(tracks[ts].strip,pg)
        CheckRandom(tracks[ts].strip,pg)
        IndexExtIdentifiers(tracks[ts].strip,pg)
      end
      CheckFaders()
      modulators = CheckMods(modulators, true)
      --Controls_ModCheck()
      Switcher_Check()
      SetCtlBitmapRedraw()
      lupd.update_gfx = true
      lupd.update_bg = true
    end
    --DBG('CheckDataTables EXIT')

  end

  function Controls_ModCheck()

    if strips and #strips > 0 then
      for s = 1, #strips do
        for p = 1, lvar.maxpage do
          if #strips[s][p].controls > 0 then

            for c = 1, #strips[s][p].controls do
              local ctl = strips[s][p].controls[c]
              if ctl.mod then

                if modulators[ctl.mod] then

                  local fnd
                  local mod = modulators[ctl.mod]
                  if #mod.targets > 0 then
                    for t = 1, #mod.targets do

                      local ms = mod.targets[t].strip
                      local mp = mod.targets[t].page
                      local mc = mod.targets[t].ctl

                      if ms == s and mp == p and mc == c then

                        fnd = true
                        break
                      end

                    end
                  else
                    --no targets
                  end

                  if not fnd then
                    ctl.mod = nil
                  end
                else
                  --mod not found
                  ctl.mod = nil
                end

              end

            end

          end
        end
      end
    end
  end

  function DeleteStrip(stripid, delfx_flag, force)
    if stripid then
      SelectStripElements(stripid)
      DeleteSelectedCtls(delfx_flag, force)
      lupd.update_gfx = true
    end
  end

  function DeleteSwitcherStrip(switchid, delfx_flag, force, fxdata)

    if switchid then
      SelectSwitchElements2(switchid)
      if delfx_flag == true and switchers[switchid].fxguids then
        DeleteSwitcherFX(switchid, fxdata)
        delfx_flag = nil
      end
      DeleteSelectedCtls(delfx_flag, force)
      lupd.update_gfx = true
    end
  end

  function GetTrackFXGUIDs(trn)
    local guids = {}
    local track = GetTrack(trn)
    for i = 0, reaper.TrackFX_GetCount(track)-1 do
      local guid = reaper.TrackFX_GetFXGUID(track, i)
      guids[guid] = {trn = trn, fxn = i}
    end
    return guids
  end

  function GetAllTrackFXGUIDs()
    local guids = {}
    for t = -1, reaper.GetNumTracks()-1 do
      local track = GetTrack(t)
      for i = 0, reaper.TrackFX_GetCount(track)-1 do
        local guid = reaper.TrackFX_GetFXGUID(track, i)
        guids[guid] = {trn = t, fxn = i}
      end
    end
    return guids
  end

  function DeleteSwitcherFX(switchid, fxdata)

    local fxguids = switchers[switchid].fxguids
    if fxguids and #fxguids > 0 then

      local trfxguids = GetTrackFXGUIDs(tracks[track_select].tracknum)
      local delfx = {}
      local delfxtracks = {idx = {},
                           tracks = {}}
      local alltrackguidsread = false

      for f = 1, #fxguids do

        local tfg = trfxguids[fxguids[f]]
        if not tfg and alltrackguidsread == false then
          alltrackguidsread = true
          trfxguids = GetAllTrackFXGUIDs()
          tfg = trfxguids[fxguids[f]]
        end

        if tfg then
          local fxnum = tfg.fxn
          if fxnum then

            local delfxcnt = #delfx+1
            local trn = tfg.trn
            delfx[delfxcnt] = {tracknum = trn,
                               guid = fxguids[f]}
            if not delfxtracks.tracks[trn] then
              delfxtracks.tracks[trn] = true
              delfxtracks.idx[#delfxtracks.idx+1] = trn
            end

          end
        end
      end

      if #delfx > 0 then
        DeleteFXPlugins(delfx, delfxtracks, true, fxdata)
      end

    end

  end

  function MoveSelectedCtls(dx, dy)

    if ctl_select then
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

        ctl.x = ctl.x + dx
        ctl.y = ctl.y + dy
        ctl.xsc = ctl.xsc + dx
        ctl.ysc = ctl.ysc + dy

      end
    end
    if gfx3_select then
      for i = 1, #gfx3_select do
        local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]

        ctl.x = ctl.x + dx
        ctl.y = ctl.y + dy
        --ctl.xsc = ctl.xsc + dx
        --ctl.ysc = ctl.ysc + dy

      end
    end

  end

  function DeleteSelectedCtls(delfx_flag, force, track_sel)

    local i
    local switchdel = false
    local delswitches = {}
    local delfx = {}
    local delfxidx = {}
    local delfxtracks = {idx = {},
                         tracks = {}}
    local ctlsdeleted = false
    local repos, extid

    --to delete - need to cycle through all selected controls - add any switcher contained controls to ctl_select 
    -- if any new switchers - add those contained controls etc...
    -- also need to check whether safe to reset grpids and current for switcher data
    
    --what to do regarding deleted fx???  hmmm - would need to store the fx chain

    if ctl_select or gfx3_select or gfx4_select then
      --Undo_Set(nil, 'Delete controls', lvar.undotypeflag_table.delete)
    end

    local strip = tracks[track_sel or track_select].strip
    --DBG('before'..#strips[tracks[track_select].strip][page].controls)
    if ctl_select then
      local cnt = #strips[strip][page].controls
      for i = 1, #ctl_select do
        local ctl = strips[strip][page].controls[ctl_select[i].ctl]
        if ctl and ctl.ctlcat == ctlcats.switcher then
          if switchers[ctl.switcherid] then
            local extpos
            if switchers[ctl.switcherid].switchmode == 1 and switchers[ctl.switcherid].extendmode == true then
              extid = switchers[ctl.switcherid].extendid
              extpos = switchers[ctl.switcherid].extendpos
              Switcher_CheckExt(extid, extpos)
              repos = true
            end

            switchdel = true
            switchers[ctl.switcherid].grpids = {}
            switchers[ctl.switcherid].current = -1
            switchers[ctl.switcherid].deleted = true
          end
        end

        if delfx_flag and settings_deletefxwithstrip then

          if ctl and ctl.fxguid and ctl.ctlcat == ctlcats.fxparam and delfxidx[ctl.fxguid] == nil then
            local delfxcnt = #delfx+1
            local trn = nz(ctl.tracknum, tracks[track_sel or track_select].tracknum)
            delfx[delfxcnt] = {tracknum = trn,
                               guid = ctl.fxguid}
            delfxidx[ctl.fxguid] = delfxcnt
            if not delfxtracks.tracks[trn] then
              delfxtracks.tracks[trn] = true
              delfxtracks.idx[#delfxtracks.idx+1] = trn
            end
          end
        end

        strips[strip][page].controls[ctl_select[i].ctl] = nil
      end

      local tbl = {}
      for i = 1, cnt do
        if strips[strip][page].controls[i] ~= nil then
          table.insert(tbl, strips[strip][page].controls[i])
        end
      end
      strips[strip][page].controls = tbl
    --DBG('after'..#strips[tracks[track_select].strip][page].controls)

     -- Snapshots_Check(tracks[track_select].strip,page)
     -- Macros_Check(tracks[track_select].strip,page)
     -- Faders_Check(tracks[track_select].strip,page)

      ctl_select = nil
      ctlsdeleted = true
     -- SetCtlBitmapRedraw()

    end

    if gfx3_select then
      local cnt = #strips[strip][page].graphics
      for i = 1, #gfx3_select do
        strips[strip][page].graphics[gfx3_select[i].ctl] = nil
      end
      local tbl = {}
      for i = 1, cnt do
        if strips[strip][page].graphics[i] ~= nil then
          table.insert(tbl, strips[strip][page].graphics[i])
        end
      end
      strips[strip][page].graphics = tbl
      gfx3_select = nil
    end

    if gfx4_select then
      local cnt = #strips[strip][page].graphics
      for i = 1, #gfx4_select do
        strips[strip][page].graphics[gfx4_select[i]] = nil
      end
      local tbl = {}
      for i = 1, cnt do
        if strips[strip][page].graphics[i] ~= nil then
          table.insert(tbl, strips[strip][page].graphics[i])
        end
      end
      strips[strip][page].graphics = tbl
    else
      if gfx2_select then
        local cnt = #strips[strip][page].graphics
        strips[strip][page].graphics[gfx2_select] = nil
        local tbl = {}
        for i = 1, cnt do
          if strips[strip][page].graphics[i] ~= nil then
            table.insert(tbl, strips[strip][page].graphics[i])
          end
        end
        strips[strip][page].graphics = tbl
      end
    end
    gfx4_select = nil
    gfx4_selectidx = nil
    gfx2_select = nil

    if switchdel == true then

      local ret
      if force then
        ret = 6
      else
        ret = reaper.MB('Delete all child controls of removed strip switcher?', 'Remove Child Controls', 4)
      end
      if ret == 6 then
        --yes
        local cnt = #strips[strip][page].controls
        for c = 1, cnt do
          local ctl = strips[strip][page].controls[c]
          if ctl.ctlcat == ctlcats.switcher_pagesel then
            local swid = ctl.switcherid
            if switchers[swid].deleted == true then
              strips[strip][page].controls[c] = nil
            end
          end
          local ctl = strips[strip][page].controls[c]
          if ctl then
            _, deleted = Switcher_CtlsDeleted(ctl.switcher,ctl.grpid)

            if deleted == true then
              if delfx_flag and (settings_deletefxwithstrip or force == true) then
                if ctl.ctlcats == ctlcats.fxparam and delfxidx[ctl.fxsguid] == nil then
                  local delfxcnt = #delfx+1
                  local trn = nz(ctl.tracknum, tracks[track_sel or track_select].tracknum)
                  delfx[delfxcnt] = {tracknum = trn,
                                     guid = ctl.fxguid}
                  delfxidx[ctl.fxguid] = delfxcnt
                  if not delfxtracks.tracks[trn] then
                    delfxtracks.tracks[trn] = true
                    delfxtracks.idx[#delfxtracks.idx+1] = trn
                  end
                end
              end
              strips[strip][page].controls[c] = nil
            end
          end
        end

        --Go through deleted switchers and add fxguids if not already in deletefx tables
        --[[for sw = 1, #switchers do
          if switchers[sw].deleted == true then
            local swfxguids = switchers[sw].fxguids
            if swfxguids and #swfxguids > 0 then
              for f = 1, #swfxguids do
                DBG(swfxguids[f])
                if delfxidx[swfxguids[f] ] == nil then

                end
              end
            end
          end
        end]]

        local tbl = {}
        for i = 1, cnt do
          if strips[strip][page].controls[i] ~= nil then
            table.insert(tbl, strips[strip][page].controls[i])
          end
        end
        strips[strip][page].controls = tbl

        local cnt = #strips[strip][page].graphics
        for c = 1, cnt do
          local ctl = strips[strip][page].graphics[c]
          _, deleted = Switcher_CtlsDeleted(ctl.switcher,ctl.grpid)
          if deleted == true then
            strips[strip][page].graphics[c] = nil
          end
        end

        local tbl = {}
        for i = 1, cnt do
          if strips[strip][page].graphics[i] ~= nil then
            table.insert(tbl, strips[strip][page].graphics[i])
          end
        end
        strips[strip][page].graphics = tbl


      else
        --no - check switcher controls first
        local cnt = #strips[strip][page].controls
        for c = 1, cnt do
          local ctl = strips[strip][page].controls[c]
          if ctl.ctlcat == ctlcats.switcher then
            _, deleted = Switcher_CtlsDeleted(ctl.switcher,ctl.grpid)
            if deleted == true then
              strips[strip][page].controls[c].switcher = nil
            end
          elseif ctl.ctlcat == ctlcats.switcher_pagesel then
            local swid = ctl.switcherid
            if switchers[swid].deleted == true then
              strips[strip][page].controls[c] = nil
            end
          end
        end
        local tbl = {}
        for i = 1, cnt do
          if strips[strip][page].controls[i] ~= nil then
            table.insert(tbl, strips[strip][page].controls[i])
          end
        end
        strips[strip][page].controls = tbl

        -- check rest of controls
        local cnt = #strips[strip][page].controls
        for c = 1, cnt do
          local ctl = strips[strip][page].controls[c]
          if ctl then
            _, deleted = Switcher_CtlsDeleted(ctl.switcher,ctl.grpid)
            if deleted == true then
              strips[strip][page].controls[c].switcher = nil
            end
          end
        end
        local cnt = #strips[strip][page].graphics
        for c = 1, cnt do
          local ctl = strips[strip][page].graphics[c]
          _, deleted = Switcher_CtlsDeleted(ctl.switcher,ctl.grpid)
          if deleted == true then
            strips[strip][page].graphics[c].switcher = nil
          end
        end
      end

    end

    if ctlsdeleted then

      if repos == true then
        Strip_ReposSwitcher_Ext(extid, 1)
      end

      if track_sel then
        CheckDataTables(true, true)
      else
        CheckDataTables(nil, true)
      end
      CheckCopyCtls()

      if delfx_flag and settings_deletefxwithstrip and #delfx > 0 and #delfxtracks.idx > 0 then
        DeleteFXPlugins(delfx, delfxtracks)
      end

      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      Snapshot_DeleteOrphanedSubsets(strip, page)
    end
    show_samplemanager = false

  end

  function CheckCopyCtls()

    if copy_ctls then
      local strip = copy_ctls.strip
      local pg = copy_ctls.page
      local cnt = #copy_ctls.ctls
      local del = false
      for i = 1, cnt do
        local c = copy_ctls.ctls[i]
        if strips[strip] and strips[strip][pg].controls[c] == nil then
          copy_ctls.ctls[i] = nil
          del = true
        end
      end
      if del == true then
        copy_ctls.ctls = Table_RemoveNils(copy_ctls.ctls, cnt)
        if #copy_ctls.ctls == 0 and #copy_ctls.gfx == 0 then
          copy_ctls = nil
        end
      end
    end
  end

  function GetFXGUIDS(track)

    local guids = {}
    for i = 1, reaper.TrackFX_GetCount(track) do
      guids[i] = reaper.TrackFX_GetFXGUID(track, i-1)
    end
    return guids

  end

  function DeleteFXPlugins(delfx, delfxtracks, skipctlcheck, fxdata)
    for ti = 1, #delfxtracks.idx do

      local idxtrn = delfxtracks.idx[ti]
      local track = GetTrack(idxtrn)

      if track then
        local removed = 0
        local fxnums = {}

        local fxkeep = {}
        if fxdata then
          for i = 1, #fxdata do
            if fxdata[i] and fxdata[i].fxguid then
              fxkeep[fxdata[i].fxguid] = true
            end
          end
        end

        for i = 1, #delfx do

          local trn = delfx[i].tracknum
          if trn == idxtrn then

            local fxguid = delfx[i].guid
            local fnd
            if skipctlcheck ~= true then
              for s = 1, #strips do
                for p = 1, lvar.maxpage do

                  if strips[s] and strips[s][p].controls then
                    for c = 1, #strips[s][p].controls do

                      local ctl = strips[s][p].controls[c]
                      if ctl.fxguid == fxguid then
                        fnd = true
                        break
                      end

                    end
                  end
                  if fnd then
                    break
                  end
                end
                if fnd then
                  break
                end
              end
            end
            if not fnd then

              --Delete fx plugin
              local fxnum
              for f = 0, reaper.TrackFX_GetCount(track)-1 do
                local fxg = reaper.TrackFX_GetFXGUID(track,f)
                if fxg == fxguid and not fxkeep[fxg] then

                  fxnums[#fxnums+1] = f+1

                  break
                end
              end
            end

          end

        end

        if reaper.APIExists('TrackFX_Delete') == true then
          if #fxnums > 0 then
            table.sort(fxnums)
            for i = #fxnums, 1, -1 do
              reaper.TrackFX_Delete(track,fxnums[i]-1)
            end
          end
        else
          local trchunk
          if #fxnums > 0 then
            --sort and iterate through backwards
            table.sort(fxnums)
            trchunk = GetTrackChunk(track, settings_usetrackchunkfix)

            for i = #fxnums, 1, -1 do
              _, trchunk = RemoveFXChunkFromTrackChunk(trchunk, fxnums[i])
              removed = removed+1
            end
          end

          if trchunk and removed > 0 then
            SetTrackChunk(track, trchunk, false)
          end
        end
      end
    end
  end

  ------------------------------------------------------------

  --[[function EditSSName(eb)

    local sizex,sizey = 400,200
    editbox={title = 'Please enter new snapshot name:',
      x=400, y=100, w=120, h=20, l=4, maxlen=20,
      fgcol=0x000000, fgfcol=0x00FF00, bgcol=0x808080,
      txtcol=0x000000, curscol=0x000000,
      font=1, fontsz=14, caret=0, sel=0, cursstate=0,
      text="",
      hasfocus=true
    }

    EB_Open = eb

  end]]

  function EditSubName(txt)

    if sstype_select > 1 then
      if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
        snapshots[tracks[track_select].strip][page][sstype_select].subsetname = txt
        lvar.snapsubsets_table[sstype_select] = txt
      end
    end

  end

  function EditSSName2(txt)
    local sst, ss

    sst = sstype_select
    ss = ss_select

    if sst == 1 then
      if ss and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sst][ss] then
        snapshots[tracks[track_select].strip][page][sst][ss].name = txt
      end
    elseif sst > 1 then
      if ss and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sst].snapshot[ss] then
        snapshots[tracks[track_select].strip][page][sst].snapshot[ss].name = txt
      end
      
      if lvar.livemode == 2 and lvar.dm_autoupdatesnaps then
        local strip = tracks[track_select].strip
        local c = snapshots[strip][page][sst].ctls[1].ctl
        local ctl = strips[strip][page].controls[c]
        if ctl then
          local switchid = Switcher_GetTopLevelSwitcher(ctl.switcher)
          if switchid then
            DM_SaveSnapsToStrip(switchid)
            --DM_RefreshPage(true)
          end
        end
      end
    end
  end

  function EditSSName3(txt)
    local sst, ss

    local ss_overwrite
    if mouse.shift then
      ss_overwrite = ss_select
    end
    Snapshots_CREATE(tracks[track_select].strip, page, sstype_select, ss_overwrite, true)
    --SetCtlDirty(i)
    local sctls = strips[tracks[track_select].strip][page].snapctls
    if sctls and #sctls > 0 then
      for sn = 1, #sctls do
        SetCtlDirty(sctls[sn])
      end
    end
    lupd.update_snaps = true
    lupd.update_ctls = true

    sst = sstype_select
    ss = ss_select

    if sst == 1 then
      if ss and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sst][ss] then
        snapshots[tracks[track_select].strip][page][sst][ss].name = txt
      end
    elseif sst > 1 then
      if ss and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sst].snapshot[ss] then
        snapshots[tracks[track_select].strip][page][sst].snapshot[ss].name = txt
      end
      
      if lvar.livemode == 2 and lvar.dm_autoupdatesnaps then
        local strip = tracks[track_select].strip
        local c = snapshots[strip][page][sst].ctls[1].ctl
        local ctl = strips[strip][page].controls[c]
        if ctl then
          local switchid = Switcher_GetTopLevelSwitcher(ctl.switcher)
          if switchid then
            DM_SaveSnapsToStrip(switchid)
            DM_RefreshPage(true)
          end
        end
      end
    end
  end

  function DeleteSS()

    if sstype_select == 1 then
      if ss_select and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select][ss_select] then

        local cnt = #snapshots[tracks[track_select].strip][page][sstype_select]
        snapshots[tracks[track_select].strip][page][sstype_select][ss_select] = nil
        local tbl = {}
        for i = 1, cnt do
          if snapshots[tracks[track_select].strip][page][sstype_select][i] ~= nil then
            table.insert(tbl, snapshots[tracks[track_select].strip][page][sstype_select][i])
          end
        end
        tbl.morph_time = snapshots[tracks[track_select].strip][page][sstype_select].morph_time
        tbl.morph_sync = snapshots[tracks[track_select].strip][page][sstype_select].morph_sync
        tbl.morph_syncv = snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv
        tbl.morph_scale = snapshots[tracks[track_select].strip][page][sstype_select].morph_scale
        tbl.capturefaders = snapshots[tracks[track_select].strip][page][sstype_select].capturefaders
        tbl.capturemods = snapshots[tracks[track_select].strip][page][sstype_select].capturemods
        tbl.ignorevals = snapshots[tracks[track_select].strip][page][sstype_select].ignorevals

        snapshots[tracks[track_select].strip][page][sstype_select] = tbl
        ss_select = nil

      end
    elseif sstype_select > 1 then
      if ss_select and snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select].snapshot[ss_select] then

        local cnt = #snapshots[tracks[track_select].strip][page][sstype_select].snapshot
        snapshots[tracks[track_select].strip][page][sstype_select].snapshot[ss_select] = nil
        local tbl = {}
        for i = 1, cnt do
          if snapshots[tracks[track_select].strip][page][sstype_select].snapshot[i] ~= nil then
            table.insert(tbl, snapshots[tracks[track_select].strip][page][sstype_select].snapshot[i])
          end
        end
        snapshots[tracks[track_select].strip][page][sstype_select].snapshot = tbl
        DeleteXXY(ss_select)
        ss_select = nil

        if lvar.livemode == 2 and lvar.dm_autoupdatesnaps then
          local strip = tracks[track_select].strip
          local snaps = snapshots[strip][page][sstype_select]
          if snaps.ctls and #snaps.ctls > 0 then
            local c = snaps.ctls[1].ctl
            local ctl = strips[strip][page].controls[c]
            if ctl then
              local switchid = Switcher_GetTopLevelSwitcher(ctl.switcher)
              if switchid then
                DM_SaveSnapsToStrip(switchid)
                DM_RefreshPage(true)
              end
            end
          end
        end
      end
    end
  end

  function DeleteSnaps(mode)

    local msg
    if mode == 1 then
      msg = 'Delete all snapshots (except selected)?'
    else
      msg = 'Delete all snapshots?'
    end
    if reaper.MB(msg,'Delete Snapshots',4) == 6 then
      if sstype_select == 1 then
        if snapshots and snapshots[tracks[track_select].strip] and #snapshots[tracks[track_select].strip][page][sstype_select] > 0 then

          local tbl = {}
          if mode == 1 and ss_select and snapshots[tracks[track_select].strip][page][sstype_select][ss_select] then
            table.insert(tbl, snapshots[tracks[track_select].strip][page][sstype_select][ss_select])
          end
          tbl.morph_time = snapshots[tracks[track_select].strip][page][sstype_select].morph_time
          tbl.morph_sync = snapshots[tracks[track_select].strip][page][sstype_select].morph_sync
          tbl.morph_syncv = snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv
          tbl.morph_scale = snapshots[tracks[track_select].strip][page][sstype_select].morph_scale
          tbl.capturefaders = snapshots[tracks[track_select].strip][page][sstype_select].capturefaders
          tbl.capturemods = snapshots[tracks[track_select].strip][page][sstype_select].capturemods
          tbl.ignorevals = snapshots[tracks[track_select].strip][page][sstype_select].ignorevals

          snapshots[tracks[track_select].strip][page][sstype_select] = tbl
          ss_select = nil

        end
      elseif sstype_select > 1 then
        if snapshots and snapshots[tracks[track_select].strip] and #snapshots[tracks[track_select].strip][page][sstype_select].snapshot > 0 then

          local tbl = {}
          local cnt = #snapshots[tracks[track_select].strip][page][sstype_select].snapshot
          if mode == 1 and ss_select and snapshots[tracks[track_select].strip][page][sstype_select].snapshot[ss_select] then
            table.insert(tbl, snapshots[tracks[track_select].strip][page][sstype_select].snapshot[ss_select])
          end
          snapshots[tracks[track_select].strip][page][sstype_select].snapshot = tbl

          for ss = 1, cnt do
            if ss ~= ss_select then
              DeleteXXY(ss)
            end
          end
          ss_select = nil
  
          if lvar.livemode == 2 and lvar.dm_autoupdatesnaps then
            local strip = tracks[track_select].strip
            local snaps = snapshots[strip][page][sstype_select]
            if snaps.ctls and #snaps.ctls > 0 then
              local c = snaps.ctls[1].ctl
              local ctl = strips[strip][page].controls[c]
              if ctl then
                local switchid = Switcher_GetTopLevelSwitcher(ctl.switcher)
                if switchid then
                  DM_SaveSnapsToStrip(switchid)
                  DM_RefreshPage(true)
                end
              end
            end
          end
        end
      end
    end

  end

  function DeleteXXY(ss)

      if sstype_select == 1 then

      elseif sstype_select > 1 then
        local strip = tracks[track_select].strip
        if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then

          local cnt = #xxy[strip][page][sstype_select].points
          local tbl = {}
          for i = 1, cnt do
            if xxy[strip][page][sstype_select].points[i].ss ~= ss then
              if xxy[strip][page][sstype_select].points[i].ss > ss then
                xxy[strip][page][sstype_select].points[i].ss = xxy[strip][page][sstype_select].points[i].ss-1
              end
              table.insert(tbl, xxy[strip][page][sstype_select].points[i])
            else
              --DBG('deleted')
            end
          end
          xxy[strip][page][sstype_select].points = tbl
          --ss_select = nil

        end
      end
    end

  function XXY_PtToggleActive(pt)

    if sstype_select == 1 then

    elseif sstype_select > 1 then
      local strip = tracks[track_select].strip
      if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then

        xxy[strip][page][sstype_select].points[pt].inactive = not nz(xxy[strip][page][sstype_select].points[pt].inactive,false)
        XXY_Set(strip, page, sstype_select)
        lupd.update_xxypos = true
      end
    end

  end

  function DeleteXXY_pt(pt)

    if sstype_select == 1 then

    elseif sstype_select > 1 then
      local strip = tracks[track_select].strip
      if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then

        local cnt = #xxy[strip][page][sstype_select].points
        local tbl = {}
        for i = 1, cnt do
          if i ~= pt then
            table.insert(tbl, xxy[strip][page][sstype_select].points[i])
          end
        end
        xxy[strip][page][sstype_select].points = tbl
        ss_select = nil

      end
    end
  end

  ------------------------------------------------------------

  function OpenEB(eb, t, def, liveupdatefunc, cancelfunc)

    local sizex,sizey = 400,200

    if def == nil then
      def = ""
    end

    editbox={title = t,
      x=400, y=100, w=120, h=20, l=4, maxlen=99,
      fgcol=0x000000, fgfcol=0x00FF00, bgcol=0x808080,
      txtcol=0x000000, curscol=0x000000,
      font=1, fontsz=14, caret=string.len(def), sel=-string.len(def), cursstate=0,
      text=def,
      hasfocus=true,
      liveupdate = liveupdatefunc,
      cancelfunc = cancelfunc,
    }

    EB_Open = eb
    
    lvar.delayfunction.ebopen = reaper.time_precise()+0.2 

  end

  ------------------------------------------------------------

  function EditValue2(txt)

    if strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat == ctlcats.snapshot then

      local sst = strips[tracks[track_select].strip][page].controls[trackfxparam_select].param

      txt = string.upper(txt)..' '

      local temp_t = {}
      for word in string.gmatch(txt, '(.-)[%s]') do table.insert(temp_t, word) end
      local fnd_ss = -1
      if sst == 1 then
        if snapshots[tracks[track_select].strip][page][sst] and #snapshots[tracks[track_select].strip][page][sst] > 0 then
          for i = 1, #snapshots[tracks[track_select].strip][page][sst] do

            local nm = string.upper(snapshots[tracks[track_select].strip][page][sst][i].name)
            local match = true
            for w = 1, #temp_t do
              local m = string.match(nm,temp_t[w])
              if m == nil then
                match = false
                break
              end
            end

            if match then
              fnd_ss = i
              break
            end

          end
          if fnd_ss > -1 then
            if sst == sstype_select then
              sstype_select = sst
              ss_select = fnd_ss
            end
            Snapshot_Set(tracks[track_select].strip, page, sst, fnd_ss)
            lupd.update_gfx = true
          end
        end
      elseif sst > 1 then
        if snapshots[tracks[track_select].strip][page][sst] and #snapshots[tracks[track_select].strip][page][sst].snapshot > 0 then
          for i = 1, #snapshots[tracks[track_select].strip][page][sst].snapshot do

            local nm = string.upper(snapshots[tracks[track_select].strip][page][sst].snapshot[i].name)
            local match = true
            for w = 1, #temp_t do
              local m = string.match(nm,temp_t[w])
              if m == nil then
                match = false
                break
              end
            end

            if match then
              fnd_ss = i
              break
            end

          end
          if fnd_ss > -1 then
            if sst == sstype_select then
              sstype_select = sst
              ss_select = fnd_ss
            end
            Snapshot_Set(tracks[track_select].strip, page, sst, fnd_ss)
            lupd.update_gfx = true
          end
        end

      end

    elseif strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat == ctlcats.macro then
      local v = tonumber(txt)
      if v then
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].val = F_limit(v,0,1)
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        SetParam()
      end

    elseif strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctlcat == ctlcats.threshold then
      local v = tonumber(txt)/127
      if v then
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].val = F_limit(v,0,1)
        strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
        SetParam()
        SetCtlDirty(trackfxparam_select)
        lupd.update_ctls = true
      end

    else
      if strips[tracks[track_select].strip][page].controls[trackfxparam_select].ctltype == 4 then
        --cycle
        if strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata.statecnt > 0 then
          for i = 1, strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata.statecnt do

            if string.upper(txt) == string.sub(string.upper(strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata[i].dispval),1,string.len(txt)) then

              strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata.pos = i
              strips[tracks[track_select].strip][page].controls[trackfxparam_select].val =
                  strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata[i].val
              SetParam()
              strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
              lupd.update_ctls = true
              break
            end

          end

        end
      else
        local mo = tonumber(txt)
        if mo then
          local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
          if ctl then
            if (ctl.maxdp or -1) >= 0 then
              local mult = 10^ctl.maxdp
              txt = math.floor(txt * mult) / mult
              if ctl.maxdp == 0 then
                txt = string.format('%i',txt)
              end
            end
            local nval = GetValFromDVal(trackfxparam_select,txt)
            ctl.val = nval
            ctl.dirty = true
            SetParam()
          end
        end
      end
    end

  end

  function EditCycleDV(txt)

    cycle_select[cycle_select.selected].dispval = txt

  end

  function EditMinDVal2(txt)

    local mo = tonumber(txt)
    if mo then
      --local test = GetValFromDVal(ctl_select[1].ctl,txt,true)
      minov_select = mo
      for i = 1, #ctl_select do
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].minov = minov_select
      end
    end
  end

  function EditMaxDVal2(txt)

    local mo = tonumber(txt)
    if mo then
      --local test = GetValFromDVal(ctl_select[1].ctl,txt,false)
      maxov_select = mo
      for i = 1, #ctl_select do
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].maxov = maxov_select
      end
    end
  end

  function EditDValOffset2(txt)

    local dv = tonumber(txt)
    if dv then
      dvaloff_select = dv
      if ctl_select then
        for i = 1, #ctl_select do
          strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dvaloffset = dv
        end
      end
    else
      dvaloff_select = ''
      if ctl_select then
        for i = 1, #ctl_select do
          strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dvaloffset = nil
        end
      end
    end
  end

  function EditCtlName2(txt)

    for i = 1, #ctl_select do
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctlname_override = txt
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
    end

  end

  function EditLimitText2(txt)

    for i = 1, #ctl_select do
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].limittext = tonumber(txt) or 0
    end

  end

  function EditWWText2(txt)

    for i = 1, #ctl_select do
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwtext = tonumber(txt) or 0
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
    end

  end

  function EditAnimateText2(txt)

    for i = 1, #ctl_select do
      if lvar.ctltype_buttons[strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctltype] then
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].animatetime = tonumber(txt) or 0
      end
    end

  end

  function EditFlagText2(txt)

    for i = 1, #ctl_select do
      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textflags = tonumber(txt)
    end

  end

  function SaveStrip()

    if strips and strips[tracks[track_select].strip] then

      local verify = true
      if strips[tracks[track_select].strip][page].controls and #strips[tracks[track_select].strip][page].controls > 0 then

        for i = 1, #strips[tracks[track_select].strip][page].controls do
          if strips[tracks[track_select].strip][page].controls[i].fxfound == false then
            verify = false
            break
          end
        end

        OpenEB(1,'Please enter a filename for the strip:')

      else
        OpenMsgBox(1, 'No controls on strip.', 1)
      end
    else
      OpenMsgBox(1, 'No controls on strip.', 1)
    end

  end

  function SaveStrip_CreateThumb(fn)

    local osg = settings_showgrid
    settings_showgrid = false

    ctl_select = nil
    gfx2_select = nil
    gfx3_select = nil
    gfx4_select = nil

    lupd.update_gfx = true
    lupd.update_bg = true
    GUI_draw(obj, gui)
    gfx.update()

    lvar.ss3_bmp = {fn = fn, osg = osg, delay = reaper.time_precise()+0.5}

  end

  function SaveStrip_CreateThumb2(ss3)

    local fn = ss3.fn
    local osg = ss3.osg

    local strip = tracks[track_select].strip
    local l,t,r,b = lvar.maxdim,lvar.maxdim,0,0
    if strips[strip] then
      for c = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[c]
        l = math.min(ctl.xsc, l)
        t = math.min(ctl.ysc, t)
        r = math.max(ctl.xsc+ctl.wsc, r)
        b = math.max(ctl.ysc+ctl.hsc, b)
      end

      for g = 1, #strips[strip][page].graphics do
        local ctl = strips[strip][page].graphics[g]
        l = math.min(ctl.x, l)
        t = math.min(ctl.y, t)
        r = math.max(ctl.x+ctl.stretchw, r)
        b = math.max(ctl.y+ctl.stretchh, b)
      end

      local pad = 0
      local x = l-pad
      local y = t-pad
      local w = r-l+pad*2
      local h = b-t+pad*2

      local win_hwnd = reaper.JS_Window_Find('- LBX Stripper -', true)
      if win_hwnd then
        local gdi_dc = reaper.JS_GDI_GetClientDC(win_hwnd)
        --gfx.blit(strip_image,1,0,x,y,w,h,0,0)
        --gfx.update()
        local xx = math.floor(math.max(0, x-surface_offset.x))
        local yy = math.floor(math.max(0, y-surface_offset.y))
        local rr = math.floor(math.min(x-surface_offset.x+w,obj.sections[10].w))
        local bb = math.floor(math.min(y-surface_offset.y+h,obj.sections[10].h))
        local ww = math.floor(rr-xx)
        local hh = math.floor(bb-yy)

        local lice_bmp = reaper.JS_LICE_CreateBitmap(true, ww, hh)
        local lice_dc = reaper.JS_LICE_GetDC(lice_bmp)
        reaper.JS_GDI_Blit(lice_dc, 0, 0, gdi_dc, obj.sections[10].x+xx, obj.sections[10].y+yy, ww, hh)

        reaper.JS_GDI_ReleaseDC(win_hwnd, gdi_dc)
        fn = string.match(fn, '(.+).strip')..'.png'
        local ret = reaper.JS_LICE_WritePNG(fn, lice_bmp, false)
        reaper.JS_LICE_DestroyBitmap(lice_bmp)
      end

      lupd.update_gfx = true
      settings_showgrid = osg

    end
    OpenMsgBox(1,'Strip saved.',1)

    if lvar.dm_return_set then
      lvar.dm_return_set = nil
      local ret_page = lvar.dm_editmode_data.ret_page
      local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
      navigate = true

      if lvar.dm_editmode_data.plist_w == 0 then
        plist_w = lvar.dm_editmode_data.plist_w
        show_editbar = false
        resize_display = true
      end
      lvar.dm_editmode_data = nil
      setmode(1)
      ChangeTrack2(ret_trn, ret_page, true)
      obj = PosTrBtns(obj)
    end
    --gfx.update()

  end

  function ReplaceSnapshotContentInStripFile(content, stripdata)

  end
  
  function Strip_AddDummyGFX(strip, page, x, y, w, h)
    gfxnum = #strips[strip][page].graphics + 1
    strips[strip][page].graphics[gfxnum] = {g_id = GenID(),
                                      gfxtype = lvar.gfxtype.img,
                                      fn = 'LBX_Invisible.png',
                                      imageidx = 1020,
                                      x = x,
                                      y = y,
                                      w = w,
                                      h = h,
                                      scale = 1,
                                      stretchw = w,
                                      stretchh = h,
                                      font = {idx = nil,
                                              name = nil,
                                              size = nil,
                                              bold = nil,
                                              italics = nil,
                                              underline = nil,
                                              vertical = nil,
                                              shadow = nil
                                              },
                                      text = nil,
                                      text_col = nil,
                                      poslock = false,
                                      bright = 0.5,
                                      contr = 0.5,
                                      rmult = 0.5,
                                      gmult = 0.5,
                                      bmult = 0.5,
                                      alpha = 1,
                                      shadow = false,
                                      stretchmode = 1,
                                      edgesz = 8,
                                     }
  end
  
  function CreateTrackTemplateStrips()
  
    local tr_count = reaper.CountSelectedTracks(0)
    for t = 0, tr_count-1 do
    
      local tr = reaper.GetSelectedTrack(0, t)
      if tr then
    
        local trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')
        local _, trname = reaper.GetTrackName(tr)
        local strip_fn = 'TT_'..trname
        local strip_ffn = paths.strips_path..paths.ttstrip_folder..'/'..strip_fn..'.strip'
    
        --save strip
        local track_select = trn-1
        local strip = tracks[track_select].strip or -1
        if strip ~= -1 then
        
          --add graphics lbx_invisible at 0,0 to force correct positioning of strip
          --first check if required
          local fnd
          for g = 1, #strips[strip][page].graphics do
            local gfxx = strips[strip][page].graphics[g]
            if gfxx.x == 0 and gfxx.y == 0 then
              fnd = true
              break
            end
          end
          if not fnd then
            Strip_AddDummyGFX(strip, page, 0, 0, 16, 16)
          end
          SaveStrip3(strip_fn, nil, strip_ffn, true, trn-1)
          
          --rename track
          local ntrname = trname..' LBXSTRIP['..strip_fn..']'
          reaper.GetSetMediaTrackInfo_String(tr, 'P_NAME', ntrname, true)
        end
        
      end
    end

    --save template
    reaper.Main_OnCommand(40392, 0)
  
    --restore track names
    for t = 0, tr_count-1 do
    
      local tr = reaper.GetSelectedTrack(0, t)
      if tr then
    
        local trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')
        local _, trname = reaper.GetTrackName(tr)
        local ntrname = string.match(trname, '(.*) LBXSTRIP.*')
        if ntrname ~= trname then
          reaper.GetSetMediaTrackInfo_String(tr, 'P_NAME', ntrname, true)
        end
      end
    end
  end

  function CreateTrackStrips()
  
    local tr_count = reaper.CountSelectedTracks(0)
    local opage = page
    
    for t = 0, tr_count-1 do
    
      local tr = reaper.GetSelectedTrack(0, t)
      if tr then
    
        local trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')
        local _, trname = reaper.GetTrackName(tr)
    
        --save strip
        local track_select = trn-1
        local strip = tracks[track_select].strip or -1
        if strip ~= -1 and strips[strip] then
        
          for p = 1, lvar.maxpage do
          
            page = p
            
            if #strips[strip][page].controls > 0 then 
              --add graphics lbx_invisible at 0,0 to force correct positioning of strip
              --first check if required
              local fnd
              for g = 1, #strips[strip][page].graphics do
                local gfxx = strips[strip][page].graphics[g]
                if gfxx.x == 0 and gfxx.y == 0 then
                  fnd = true
                  break
                end
              end
              if not fnd then
                Strip_AddDummyGFX(strip, page, 0, 0, 16, 16)
              end
              
              local strip_fn = 'TT_'..trname..'_'..string.format('%i',p)
              local strip_ffn = paths.strips_path..paths.ttstrip_folder..'/'..strip_fn..'.strip'
              SaveStrip3(strip_fn, nil, strip_ffn, true, trn-1)
              
              if not lvar.trackstrips[trname] then
                lvar.trackstrips[trname] = {}
              end
              lvar.trackstrips[trname][p] = strip_fn
            end
            
          end
          
        end
        
      end
    end
    
    page = opage
    
    --save template
    reaper.Main_OnCommand(40392, 0)
    
    --save trackstrips
    SaveTrackStrips()

  end

  function SetStripQuickLoadSetting_ss(stripfol_select, strip_select, quickload)

    if strip_select then
      --single
      local sfn = strip_folders[stripfol_select].fn..'/'..strip_files[strip_select].fn
      if SetStripQuickLoadSetting(sfn, quickload) then
        if quickload then
          DBG('QUICKLOAD ACTIVATED: '..sfn)
        else
          DBG('QUICKLOAD DEACTIVATED: '..sfn)
        end
      else
        DBG('QUICKLOAD SETTING FAILED: '..sfn)
      end
    else
      --all
      for s = 1, #strip_files do
        local sfn = strip_folders[stripfol_select].fn..'/'..strip_files[s].fn
        if SetStripQuickLoadSetting(sfn, quickload) then
          if quickload then
            DBG('QUICKLOAD ACTIVATED: '..sfn)
          else
            DBG('QUICKLOAD DEACTIVATED: '..sfn)
          end
        else
          DBG('QUICKLOAD SETTING FAILED: '..sfn)
        end
      end
    end
  
  end
  
  function SetStripQuickLoadSetting(sfn, quickload)
  
    local t = reaper.time_precise()
  
    --load strip
    local loadstrip, content = LoadStripFN(sfn)
    if loadstrip and loadstrip.version >= 4 then

      local save
      if quickload == true then
        if not string.match(content,'%[quickload%]') then
          content = string.gsub(content,'%[STRIPDATA%]\n','[STRIPDATA]\n[quickload]1\n')
          save = true
        end
      else
        content = string.gsub(content,'\n(%[quickload%].-)\n','\n')
        save = true
      end

      if save then
        file = io.open(paths.strips_path..sfn,'w')
        if file then

          file:write(content)
  
          file:close()

          UpdateStripFileHeader(sfn)
          return true
        end
      else
        return true
      end
    else
      OpenMsgBox(1,'Strip file version too old.  Please update first.',1)
    end
  
  end
  
  --new version
  function SaveStrip3(fn, fixactionstring, ffn, nothumb, track_sel)

    --test
    local track_select = track_sel or track_select
    if fn and string.len(fn)>0 then
      Snapshot_DeleteOrphanedSubsets(tracks[track_select].strip, page)
      CheckDataTables(nil, nil, track_select)

      local save_path=paths.strips_path..strip_folders[stripfol_select].fn..'/'
      local fn = ffn or (save_path..fn..".strip")
      local file
      file=io.open(fn,"w")

      if file then

        local tr = GetTrack(strips[tracks[track_select].strip].track.tracknum)
        local i, j
        local fxcnt = 1
        local fxtbl = {}
        local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
        for i = 0, reaper.TrackFX_GetCount(tr)-1 do
          if settings_saveallfxinststrip then
            --local _, fxname = reaper.TrackFX_GetFXName(tr, i, '')
            local _, fxchunk = GetFXChunkFromTrackChunk(chunk, i+1)
            --local fxn = GetPlugNameFromChunk(fxchunk)
            fxtbl[i+1] = {fxname = nil,
                          fxchunk = fxchunk,
                          fxguid = convertguid(reaper.TrackFX_GetFXGUID(tr, i)),
                          fxenabled = reaper.TrackFX_GetEnabled(tr, i)
                          }
          else
            --check fx has controls in strip
            local instrip = false
            for j = 1, #strips[tracks[track_select].strip][page].controls do
              if reaper.TrackFX_GetFXGUID(tr, i) == strips[tracks[track_select].strip][page].controls[j].fxguid then
                instrip = true
                break
              end
              if strips[tracks[track_select].strip][page].controls[j].ctlcat == ctlcats.eqcontrol then
                local bands = strips[tracks[track_select].strip][page].controls[j].eqbands
                if bands and #bands > 0 then
                  for b = 1, #bands do

                    if reaper.TrackFX_GetFXGUID(tr, i) == bands[b].fxguid then
                      instrip = true
                      break
                    end

                  end
                  if instrip then
                    break
                  end
                end
              end
            end
            if instrip then
              --local _, fxname = reaper.TrackFX_GetFXName(tr, i, '')
              local _, fxchunk = GetFXChunkFromTrackChunk(chunk, i+1)
              --local fxn = GetPlugNameFromChunk(fxchunk)
              fxtbl[fxcnt] = {fxname = nil,
                              fxchunk = fxchunk,
                              fxguid = convertguid(reaper.TrackFX_GetFXGUID(tr, i)),
                              fxenabled = reaper.TrackFX_GetEnabled(tr, i)
                              }
              fxcnt = fxcnt + 1
            end
          end
        end

        --check tracknums
        for j = 1, #strips[tracks[track_select].strip][page].controls do
          local ctl = strips[tracks[track_select].strip][page].controls[j]
          if ctl.tracknum and ctl.tracknum == strips[tracks[track_select].strip].track.tracknum then
            ctl.tracknum = nil
          end
        end

        local savestrip = {}
        local switchtab = {}
        local saveswitchers = {}
        local switchcnt = 1

        local atab = GetActionListTables()

        for j = 1, #strips[tracks[track_select].strip][page].controls do
          local ctl = strips[tracks[track_select].strip][page].controls[j]
          if ctl.ctlcat == ctlcats.pkmeter then
            ctl.val = -150
          end

          if ctl.ctlcat == ctlcats.switcher then
            if ctl.switcherid and switchers[ctl.switcherid] then
              switchtab[ctl.switcherid] = switchcnt
              saveswitchers[switchcnt] = switchers[ctl.switcherid]
              --savestrip.strip.controls[i].switcherid = switchcnt -- eek
              switchcnt = switchcnt + 1
            end
          elseif ctl.ctlcat == ctlcats.action then

            if ctl.param_info.paramstr2 == nil or ctl.param_info.paramstr == nil then

              local a1, a2, a3 = AssAction_GetNameFromID2(ctl.param_info.paramnum or ctl.param_info.paramidx, atab, ctl.param_info.paramstr)
              if a2 then
                ctl.param_info.paramstr = a3
                ctl.param_info.paramstr2 = a2
              end

            end

          end

        end

        savestrip.switchers = saveswitchers
        savestrip.switchconvtab = switchtab
        savestrip.fx = fxtbl
        local pickledfx = pickle(savestrip)

        file:write('[STRIPFILE_VERSION]5\n')
        file:write('[FXDATA]\n'..pickledfx..'\n[\\FXDATA]\n')
        file:write('[STRIPDATA]\n')
        local t = GenStripSaveData2(strips[tracks[track_select].strip][page],nil,file)
        file:write('[\\STRIPDATA]\n')

        if snapshots and snapshots[tracks[track_select].strip] then
          file:write('[SNAPSHOTDATA]\n')
          SaveSnapshotDataX(snapshots[tracks[track_select].strip][page],nil,file,true)
          file:write('[\\SNAPSHOTDATA]\n')
        end

        file:close()

        file = io.open(fn,'r')
        if file then
          local datastr = file:read("*a")
          file:close()
          local t = reaper.time_precise()

          local fx_s, fx_e = string.find(datastr,'(%[FXDATA%].-%[\\FXDATA%]\r?\n)')
          local sd_s, sd_e = string.find(string.sub(datastr,fx_e),'(%[STRIPDATA%].-%[\\STRIPDATA%]\r?\n)')
          sd_s = sd_s + fx_e -1
          sd_e = sd_e + fx_e -1
          local sn_s, sn_e = string.find(string.sub(datastr,sd_e),'(%[SNAPSHOTDATA%].-%[\\SNAPSHOTDATA%]\r?\n)')
          sn_s = sn_s + sd_e -1
          sn_e = sn_e + sd_e -1

          local header = '[STRIPFILE_VERSION]6\n'
          header = header .. '[FXDATA_LOC]'..fx_s-fx_s..' '..fx_e-fx_s..'\n'
          header = header .. '[STRIPDATA_LOC]'..sd_s-fx_s..' '..sd_e-fx_s..'\n'
          header = header .. '[SNAPSHOTDATA_LOC]'..sn_s-fx_s..' '..sn_e-fx_s..'\n'
          header = header .. '[DATA]\n'

          file = io.open(fn,'w')
          if file then
            file:write(header..string.sub(datastr,fx_s,sn_e))
          end
          file:close()

 --         DBG(tostring(fx_s)..'  '..tostring(fx_e)..'  '..tostring(sd_s)..'  '..tostring(sd_e)..'  '..tostring(sn_s)..'  '..tostring(sn_e))
        end

        if not reaper.JS_LICE_WritePNG then
          OpenMsgBox(1,'Strip saved.',1)
        elseif not nothumb then
          SaveStrip_CreateThumb(fn)
        end
      else
        OpenMsgBox(1,'Error opening file for saving.  Possibly invalid filename.',1)
      end
    else
      return nil
    end
    PopulateStrips()

  end

  function GetPlugNameFromChunk(fxchunk)

    local fxn
    local fxc = string.match(fxchunk,'<(.-)\n')
    if fxc then
      fxchunk = fxc
    else
      fxc = string.match(fxchunk,'(.-)\n')
      if fxc then
        fxchunk = fxc
      end
    end
    if string.sub(fxchunk,1,3) == 'VST' then
      fxn = string.match(fxchunk, '.*: (.-) %(')
      if fxn == nil then
        fxn = string.match(fxchunk, '.*: (.-)%"')
      end
    elseif string.sub(fxchunk,1,2) == 'JS' then
      fxn = string.match(fxchunk, 'JS.*%/+(.-) \"')
      if fxn == nil then
        fxn = string.match(fxchunk, 'JS%s(.-)%s')  -- gets full path of effect
        fxn = string.match(fxn, '([^/]+)$') -- gets filename
      end
      --remove final " if exists
      if string.sub(fxn,string.len(fxn)) == '"' then
        fxn = string.sub(fxn,1,string.len(fxn)-1)
      end

      --[[if fxn == nil then
        --JS \"AB Level Matching JSFX [2.5]/AB_LMLT_cntrl\" \"MSTR /B\"\
        fxn = string.match(fxchunk, 'JS.*%/(.-)%"%\"')
        fxn = string.sub(fxn,1,string.len(fxn)-2)
      end]]
    end

    return fxn

  end

  function GetPlugNameFromChunk2(fxchunk)

    local fxn
    local fxc = string.match(fxchunk,'<(.-)\n')
    if fxc then
      fxchunk = fxc
    else
      fxc = string.match(fxchunk,'(.-)\n')
      if fxc then
        fxchunk = fxc
      end
    end
    if string.sub(fxchunk,1,3) == 'VST' then
      fxn = string.match(fxchunk, '.*(VST.-%))')
      if fxn == nil then
        fxn = string.match(fxchunk, '.*(VST.-)%"')
      end
    elseif string.sub(fxchunk,1,2) == 'JS' then
      fxn = string.match(fxchunk, '.*(JS.*%/+.-) \"')
      if fxn == nil then
        fxn = string.match(fxchunk, '(JS%s.-)%s')  -- gets full path of effect
        --fxn = string.match(fxn, '([^/]+)$') -- gets filename
      end
      --remove final " if exists
      if string.sub(fxn,string.len(fxn)) == '"' then
        fxn = string.sub(fxn,1,string.len(fxn)-1)
      end

      --[[if fxn == nil then
        --JS \"AB Level Matching JSFX [2.5]/AB_LMLT_cntrl\" \"MSTR /B\"\
        fxn = string.match(fxchunk, 'JS.*%/(.-)%"%\"')
        fxn = string.sub(fxn,1,string.len(fxn)-2)
      end]]
    end

    return fxn

  end

  function GetPlugNameFromChunk3(fxchunk)

    local fxn
    local fxc = string.match(fxchunk,'<(.-)\n')
    if fxc then
      fxchunk = fxc
    else
      fxc = string.match(fxchunk,'(.-)\n')
      if fxc then
        fxchunk = fxc
      end
    end
    if string.sub(fxchunk,1,3) == 'VST' then
      fxn = string.match(fxchunk, '.*%s0%s\"(.-)\"%s')
      if fxn then
        fxn = string.gsub(fxn,'%"','')
      else
        fxn = string.match(fxchunk, '.*%s0%s(.-)%s')
      end
      if fxn == '' then
        fxn = string.match(fxchunk, '.*(VST.-%))')
        if fxn == nil then
          fxn = string.match(fxchunk, '.*(VST.-)%"')
        end
      end

    elseif string.sub(fxchunk,1,2) == 'JS' then
      fxn = string.match(fxchunk, 'JS \".-\"%s(.*)$')
      if fxn == nil then
        fxn = string.match(fxchunk, 'JS%s.-%s(.*)$')
      end
      if string.sub(fxn,string.len(fxn)) == '"' then
        fxn = string.gsub(fxn,'\"','')
      end
      if fxn == '' or fxn == '\"\"' then
        fxn = string.match(fxchunk, '.*(JS%s\".-\")')
        if fxn == nil then
          fxn = string.match(fxchunk, '(JS%s.-)%s')  -- gets full path of effect
        end

        if string.sub(fxn,string.len(fxn)) == '"' then
          fxn = string.sub(fxn,1,string.len(fxn)-1)
        end
      end

      --[[fxn = string.match(fxchunk, '.*(JS.*%/+.-) \"')
      if fxn == nil then
        fxn = string.match(fxchunk, '(JS%s.-)%s')  -- gets full path of effect
        --fxn = string.match(fxn, '([^/]+)$') -- gets filename
      end]]
      --remove final " if exists
      --[[if fxn == nil then
        --JS \"AB Level Matching JSFX [2.5]/AB_LMLT_cntrl\" \"MSTR /B\"\
        fxn = string.match(fxchunk, 'JS.*%/(.-)%"%\"')
        fxn = string.sub(fxn,1,string.len(fxn)-2)
      end]]
    end

    return fxn

  end

  function GetPlugIdentifierFromChunk(fxchunk)

    local fxn, plugtype
    if fxchunk then
      local fxc = string.match(fxchunk,'<(.-)\n')
      if fxc then
        fxchunk = fxc
      else
        fxc = string.match(fxchunk,'(.-)\n')
        if fxc then
          fxchunk = fxc
        end
      end
      if string.sub(fxchunk,1,3) == 'VST' then
        plugtype = 'VST'
        fxn = string.match(fxchunk, '.*%s"(.-%.dll)"')
        if fxn == nil then
          fxn = string.match(fxchunk, '.*%s(.-%.dll)')
          if fxn == nil then
            fxn = string.match(fxchunk, '.*%s"(.-%.vst3)"')
            if fxn == nil then
              fxn = string.match(fxchunk, '.*%s(.-%.vst3)')
              if fxn == nil then
                fxn = string.match(fxchunk, '.*%s"(.-%.vst)"')
                if fxn == nil then
                  fxn = string.match(fxchunk, '.*%s(.-%.vst)')
                end
              end
            end
          end
        end
      elseif string.sub(fxchunk,1,2) == 'JS' then
        plugtype = 'JS'
        fxn = string.match(fxchunk, 'JS%s"(.-)"%s')
        if not fxn then
          fxn = string.match(fxchunk, 'JS%s(.-)%s')
        end
        --remove final " if exists
        if string.sub(fxn,string.len(fxn)) == '"' then
          fxn = string.sub(fxn,1,string.len(fxn)-1)
        end
      end

      return fxn, plugtype
    end
  end

  function GenID()

    local l = false
    local id
    while l == false do
      id = math.floor(math.random() * 0xFFFFFFFF)
      if g_cids[id] == nil then
        g_cids[id] = true
        l = true
      end
    end

    return id

  end

  function LoadStripShareFN(sfn,ffn,path)

    DBGOut('LoadStripShareFN: sfn='..tostring(sfn)..'  ffn='..tostring(ffn))

    local content, sharestripdata
    local stripdata = nil
    local load_path, fn
    if ffn == nil then
      load_path=paths.strips_path
      fn=load_path..sfn
    else
      fn = (path or '')..ffn
    end

    DBGOut('LoadStripShareFN: fn='..tostring(fn))

    if reaper.file_exists(fn) then

      DBGOut('LoadStripShareFN: FileExists')
      if string.match(fn,'%.sharestrip') == nil then
        OpenMsgBox(1,'Not a sharestrip file',1,'')
        return
      end

      local find = string.find
      local match = string.match
      local file
      file=io.open(fn,"r")
      content=file:read("*a")
      file:close()
      local _,e = find(content,'.-\n')
      local line = string.sub(content,0,e)


      local newvers = string.match(line,'[[STRIPSHAREFILE_VERSION]](%d)')
      if newvers then

        GUI_DrawStateWin(obj,gui,'Splitting sharestrip file... ',true)
        GUI_DrawStateWin(obj,gui,'Reading share data... ')
        local sharedata = string.match(content,'%[SHAREDATA%](.-)%[\\SHAREDATA%]')
        GUI_DrawStateWin(obj,gui,'Reading share strip data... ')
        sharestripdata = string.match(content,'%[SHARESTRIPDATA%](.-)%[\\SHARESTRIPDATA%]')
        GUI_DrawStateWin(obj,gui,'Reading fx data... ')
        local fxdata = string.match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
        GUI_DrawStateWin(obj,gui,'Reading strip content... ')
        local stripcontent = string.match(sharestripdata,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
        GUI_DrawStateWin(obj,gui,'Reading snapshot content... ')
        local snapcontent = string.match(sharestripdata,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')

        --SNAPSHOTS --only load if strip imported?
        if fxdata and stripcontent then

          DBGOut('LoadStripShareFN: FXData and StripContent valid')
          GUI_DrawStateWin(obj,gui,'Transferring strip data... ',true)

          stripdata = unpickle(fxdata)
          stripdata.sharedata = unpickle(sharedata)
          stripdata.version = tonumber(newvers)
          stripdata.snapcontent = snapcontent
          local data = {}
          local cnt = 0
          local lines = splitln(stripcontent)
          if lines and #lines > 0 then
            --DBGOut('LoadStripShareFN: stripcontent lines='..tostring(#lines))
            local opc
            for ln = 1, #lines do
              local pc = math.floor(ln/#lines*100)
              if pc ~= opc then
                GUI_DrawStateWin(obj,gui,'Transferring strip data... '..pc..'%',true)
                opc = pc
              end
              local idx, val = match(lines[ln],'%[(.-)%](.*)')
              if idx then
                data[idx] = val
              end
            end
          end

          DBGOut('LoadStripShareFN: Calling LoadStripDataX')

          stripdata.strip = LoadStripDataX(nil,data)

          if snapcontent then
            GUI_DrawStateWin(obj,gui,'Transferring snapshot data... ',true)
            local data = {}
            local cnt = 0
            local lines = splitln(snapcontent)
            if lines and #lines > 0 then
              local opc
              for ln = 1, #lines do
                local pc = math.floor(ln/#lines*100)
                if pc ~= opc then
                  GUI_DrawStateWin(obj,gui,'Transferring snapshot data... '..pc..'%',true)
                  opc = pc
                end

                local idx, val = match(lines[ln],'%[(.-)%](.*)')
                if idx then
                  data[idx] = val
                end
              end
            end

            DBGOut('LoadStripShareFN: Calling LoadSnapDataX')
            stripdata.snapshots = LoadSnapDataX(nil,data)

          end
        end

      else
        DBGOut('LoadStripShareFN: Old Version')

        stripdata = unpickle(content)
      end

      if newvers == nil or tonumber(newvers) < 2 then

        DBGOut('LoadStripShareFN: Compatibility section')

        --compatibility
        local ctls = stripdata.strip.controls
        if ctls and #ctls > 0 then

          for c = 1, #ctls do
            gfx.setfont(1, ctls[c].font, gui.fontsz_knob + ctls[c].textsize-4)
            local _, th = gfx.measurestr('|')
            ctls[c].textoff = ctls[c].textoff - math.floor(th/2)
          end

        end

      end
    else
      OpenMsgBox(1,'File not found.',1)
    end
    --DBGOut('LoadStripShareFN: stripdata='..tostring(stripdata))
    --DBGOut('LoadStripShareFN: sharestripdata='..tostring(sharestripdata))

    return stripdata, sharestripdata

  end

  function LoadStrip(strip_select, sfol, sfil, verbose)

    local find = string.find
    local match = string.match

    if sfol == nil and stripfol_select and strip_folders[stripfol_select] then
      sfol = strip_folders[stripfol_select].fn
    end
    if sfil == nil and strip_select and strip_files[strip_select] then
      sfil = strip_files[strip_select].fn
    end

    local stripdata = nil
    local load_path=paths.strips_path
    if sfol and sfil then
      local fn=load_path..sfol..'/'..sfil

      if reaper.file_exists(fn) then

        if not verbose then
          GUI_DrawMsgX(obj, gui, 'Generating Preview...')
        end

        local file
        file=io.open(fn,"r")
        local content=file:read("*a")
        file:close()
        local _,e = find(content,'.-\n')
        local line = string.sub(content,0,e)
        local newvers = tonumber(match(line,'[[STRIPFILE_VERSION]](%d+)'))
        if newvers then
          local pickledcontent, stripcontent, snapcontent
          if newvers == 5 then

            pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
            stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
            snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
          elseif newvers == 6 then

            local s, e = find(content, '%[DATA%]\r?\n')
            local header = string.sub(content, 1, s-1)
            local body = string.sub(content, e)
            local fx_s, fx_e = match(header, '%[FXDATA_LOC%](%d+) (%d+)')
            local sd_s, sd_e = match(header, '%[STRIPDATA_LOC%](%d+) (%d+)')
            local sn_s, sn_e = match(header, '%[SNAPSHOTDATA_LOC%](%d+) (%d+)')

            pickledcontent = string.sub(body,fx_s+2,fx_e)
            pickledcontent = match(pickledcontent,'.-({.*})')
            stripcontent = string.sub(body,sd_s,sd_e)
            snapcontent = string.sub(body,sn_s,sn_e)

            --Required due to messed up calculations to load version 6 strips with incorrect encoding...
            if not match(string.sub(stripcontent,1,20),'.-%[STRIPDATA%].*') or
               not match(string.sub(stripcontent,string.len(stripcontent)-15,string.len(stripcontent)),'.-%[\\STRIPDATA') or
               not match(string.sub(snapcontent,1,20),'.-%[SNAPSHOTDATA%].*') or
               not match(string.sub(snapcontent,string.len(snapcontent)-15,string.len(snapcontent)),'.-%[\\SNAPSHOTDATA') then
              pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
              stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
              snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
              DBGOut('String parsing old way')
              --Option to reencode here
              UpdateStripFileHeader(fn)
            else
              DBGOut('String parsing new way')
            end
          else
            --try old way
            pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
            stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
            snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
            DBGOut('String parsing old way')
          end
          --SNAPSHOTS --only load if strip imported?
          if pickledcontent and stripcontent then
            stripdata = unpickle(pickledcontent)
            stripdata.version = tonumber(newvers)
            stripdata.snapcontent = snapcontent
            local data = {}
            local cnt = 0
            local lines = splitln(stripcontent)
            if lines and #lines > 0 then
              for ln = 1, #lines do
                local idx, val = match(lines[ln],'%[(.-)%](.*)')
                if idx then
                  data[idx] = val
                end
              end
            end
            stripdata.strip = LoadStripDataX(nil,data)

          end
          --return nil --remove
        else
          stripdata = unpickle(content)
        end

        if stripdata == nil then
          OpenMsgBox(1,'Invalid strip file.',1)
          return
        end

        if stripdata then
          stripdata.fn = fn
        end

        if newvers == nil or tonumber(newvers) < 5 then
          --compatibility

          local ctls = stripdata.strip.controls
          if ctls and #ctls > 0 then

            for c = 1, #ctls do
              gfx.setfont(1, ctls[c].font, gui.fontsz_knob + ctls[c].textsize-4)
              local _, th = gfx.measurestr('|')
              ctls[c].textoff = ctls[c].textoff - math.floor(th/2)
            end

          end

          local gfx = stripdata.strip.graphics
          if gfx and #gfx > 0 then

            for g = 1, #gfx do

              if gfx[g].stretchmode == nil then gfx[g].stretchmode = 1 end
              if gfx[g].edgesz == nil then gfx[g].edgesz = 8 end

            end
          end

        end
      else
        OpenMsgBox(1,'File not found.',1)
      end
      return stripdata
    end

  end

  function UpdateStripFileHeader(fn)

    if reaper.file_exists(fn) then

      local find = string.find
      local match = string.match

      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      local _,e = find(content,'.-\n')
      local line = string.sub(content,0,e)
      local newvers = tonumber(match(line,'[[STRIPFILE_VERSION]](%d+)'))
      if newvers then
        if newvers == 6 then

          local s, e = find(content, '%[DATA%]\r?\n')
          local header = string.sub(content, 1, s-1)
          local body = string.sub(content, e+1)

          DBGOut(header)
          --DBGOut('*'..string.sub(body,1,20))

          local fx_s, fx_e = string.find(body,'(%[FXDATA%].-%[\\FXDATA%]\r?\n)')
          fx_s = fx_s
          fx_e = fx_e
          local sd_s, sd_e = string.find(string.sub(body,fx_e),'(%[STRIPDATA%].-%[\\STRIPDATA%]\r?\n)')
          sd_s = sd_s + fx_e -1
          sd_e = sd_e + fx_e -1
          local sn_s, sn_e = string.find(string.sub(body,sd_e),'(%[SNAPSHOTDATA%].-%[\\SNAPSHOTDATA%]\r?\n)')
          sn_s = sn_s + sd_e -1
          sn_e = sn_e + sd_e -1

          --DBGOut(fx_s..' '..fx_e..'  '..sd_s..'  '..sd_e..'  '..sn_s..'  '..sn_e)
          --DBGOut('*'..string.sub(body,fx_s,fx_s+10))
          --DBGOut('*'..string.sub(body,sd_s,sd_s+10))
          --DBGOut('*'..string.sub(body,sn_s,sn_s+10))
          local header = '[STRIPFILE_VERSION]6\n'
          header = header .. '[FXDATA_LOC]'..fx_s-fx_s..' '..fx_e-fx_s..'\n'
          header = header .. '[STRIPDATA_LOC]'..sd_s-fx_s..' '..sd_e-fx_s..'\n'
          header = header .. '[SNAPSHOTDATA_LOC]'..sn_s-fx_s..' '..sn_e-fx_s..'\n'
          header = header .. '[DATA]\n'

          file = io.open(fn,'w')
          if file then
            file:write(header..body)
          end
          file:close()

        end
      end
    end

  end

  function LoadStripFN_ContentOnly(sfn, ffn)
    local find = string.find
    local match = string.match

    local content
    local stripdata = nil
    local load_path, fn
    if ffn == nil then
      load_path=paths.strips_path
      fn=load_path..sfn
    else
      fn = ffn
    end

    if reaper.file_exists(fn) then
      local file
      file=io.open(fn,"r")
      content=file:read("*a")
      file:close()
      local _,e = find(content,'.-\n')
      local line = string.sub(content,0,e)
      local newvers = tonumber(match(line,'[[STRIPFILE_VERSION]](%d+)'))
      if newvers then
        local pickledcontent, stripcontent, snapcontent
        if newvers == 5 then
          pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
          stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
          snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
        elseif newvers == 6 then
          local s, e = find(content, '%[DATA%]\r?\n')
          local header = string.sub(content, 1, s-1)
          local body = string.sub(content, e)
          local fx_s, fx_e = match(header, '%[FXDATA_LOC%](%d+) (%d+)')
          local sd_s, sd_e = match(header, '%[STRIPDATA_LOC%](%d+) (%d+)')
          local sn_s, sn_e = match(header, '%[SNAPSHOTDATA_LOC%](%d+) (%d+)')

          pickledcontent = string.sub(body,fx_s+2,fx_e)
          pickledcontent = match(pickledcontent,'.-({.*})')
          stripcontent = string.sub(body,sd_s,sd_e)
          snapcontent = string.sub(body,sn_s,sn_e)
          --Required due to messed up calculations to load version 6 strips with incorrect encoding...
          if not match(string.sub(stripcontent,1,20),'.-%[STRIPDATA%].*') or
             not match(string.sub(stripcontent,string.len(stripcontent)-15,string.len(stripcontent)),'.-%[\\STRIPDATA') or
             not match(string.sub(snapcontent,1,20),'.-%[SNAPSHOTDATA%].*') or
             not match(string.sub(snapcontent,string.len(snapcontent)-15,string.len(snapcontent)),'.-%[\\SNAPSHOTDATA') then
            pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
            stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
            snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
            DBGOut('String parsing old way')
            --Option to reencode here
            UpdateStripFileHeader(fn)
          else
            DBGOut('String parsing new way')
          end
        else
          pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
          stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
          snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
          DBGOut('String parsing old way')
        end
        --SNAPSHOTS --only load if strip imported?
        if pickledcontent and stripcontent then
          stripdata = unpickle(pickledcontent)
          stripdata.version = tonumber(newvers)
          stripdata.snapcontent = snapcontent
          stripdata.stripcontent = stripcontent
          if string.match(stripcontent, '%[quickload%]1') then
            stripdata.quickload = true
          end
        end
        --return nil --remove
      else
        stripdata = unpickle(content)
      end

      if stripdata then
        stripdata.fn = fn
      end

    end

    return stripdata
  end



  function LoadStripFN(sfn, ffn, skipcompat)
    local find = string.find
    local match = string.match

    local content
    local stripdata = nil
    local load_path, fn
    if ffn == nil then
      load_path=paths.strips_path
      fn=load_path..sfn
    else
      fn = ffn
    end

    if reaper.file_exists(fn) then
      local file
      file=io.open(fn,"r")
      content=file:read("*a")
      file:close()
      local _,e = find(content,'.-\n')
      local line = string.sub(content,0,e)
      local newvers = tonumber(match(line,'[[STRIPFILE_VERSION]](%d+)'))
      if newvers then
        local pickledcontent, stripcontent, snapcontent
        if newvers == 5 then
          pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
          stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
          snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
        elseif newvers == 6 then
          local s, e = find(content, '%[DATA%]\r?\n')
          local header = string.sub(content, 1, s-1)
          local body = string.sub(content, e)
          local fx_s, fx_e = match(header, '%[FXDATA_LOC%](%d+) (%d+)')
          local sd_s, sd_e = match(header, '%[STRIPDATA_LOC%](%d+) (%d+)')
          local sn_s, sn_e = match(header, '%[SNAPSHOTDATA_LOC%](%d+) (%d+)')

          pickledcontent = string.sub(body,fx_s+2,fx_e)
          pickledcontent = match(pickledcontent,'.-({.*})')
          stripcontent = string.sub(body,sd_s,sd_e)
          snapcontent = string.sub(body,sn_s,sn_e)

          --Required due to messed up calculations to load version 6 strips with incorrect encoding...
          if not match(string.sub(stripcontent,1,20),'.-%[STRIPDATA%].*') or
             not match(string.sub(stripcontent,string.len(stripcontent)-15,string.len(stripcontent)),'.-%[\\STRIPDATA') or
             not match(string.sub(snapcontent,1,20),'.-%[SNAPSHOTDATA%].*') or
             not match(string.sub(snapcontent,string.len(snapcontent)-15,string.len(snapcontent)),'.-%[\\SNAPSHOTDATA') then
            pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
            stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
            snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
            DBGOut('String parsing old way')
            --Option to reencode here
            UpdateStripFileHeader(fn)
          else
            DBGOut('String parsing new way')
          end
        else
          pickledcontent = match(content,'%[FXDATA%](.-)%[\\FXDATA%]')
          stripcontent = match(content,'%[STRIPDATA%](.-)%[\\STRIPDATA%]')
          snapcontent = match(content,'%[SNAPSHOTDATA%](.-)%[\\SNAPSHOTDATA%]')
          DBGOut('String parsing old way')
        end
        --SNAPSHOTS --only load if strip imported?
        if pickledcontent and stripcontent then
          stripdata = unpickle(pickledcontent)
          stripdata.version = tonumber(newvers)
          stripdata.snapcontent = snapcontent
          local data = {}
          local cnt = 0
          local lines = splitln(stripcontent)
          if lines and #lines > 0 then
            for ln = 1, #lines do
              local idx, val = match(lines[ln],'%[(.-)%](.*)')
              if idx then
                data[idx] = val
              end
            end
          end
        --DBG('strip lines'..reaper.time_precise()-t)
        --local t= reaper.time_precise()

          stripdata.strip = LoadStripDataX(nil,data)
        --DBG('loadstripdatax'..reaper.time_precise()-t)
        --local t= reaper.time_precise()
        end
        --return nil --remove
      else
        stripdata = unpickle(content)
      end

      if stripdata then
        stripdata.fn = fn
      end

      if nz(skipcompat,false) == false then

        if newvers == nil or tonumber(newvers) < 5 then
          --compatibility

          local ctls = stripdata.strip.controls
          if ctls and #ctls > 0 then

            for c = 1, #ctls do
              gfx.setfont(1, ctls[c].font, gui.fontsz_knob + ctls[c].textsize-4)
              local _, th = gfx.measurestr('|')
              ctls[c].textoff = ctls[c].textoff - math.floor(th/2)

            end

          end

          local gfx = stripdata.strip.graphics
          if gfx and #gfx > 0 then

            for g = 1, #gfx do

              if gfx[g].stretchmode == nil then gfx[g].stretchmode = 1 end
              if gfx[g].edgesz == nil then gfx[g].edgesz = 8 end

            end
          end
        end
      end
    else
      OpenMsgBox(1,'File not found.',1)
    end

    return stripdata, content

  end

  function LogData(fn, infostr, data)

    local file = io.open(fn,"a+")
    if file then
      file:write('\n\n********************************************\n')
      file:write(infostr)
      file:write('\n********************************************\n\n')
      file:write(tostring(data))
      file:close()
    end

  end

  function GetNewLogFN()

    local path = paths.resource_path..'LogFiles/'
    reaper.RecursiveCreateDirectory(path,1)
    local fn = ''

    local fnum = 0

    local f = 0
    local cfn = reaper.EnumerateFiles(path,f)
    while cfn do

      local num = string.match(cfn,'.*_(.-)%..*')
      if (tonumber(num) or 0) > fnum then
        fnum = tonumber(num) or 0
      end

      f = f + 1
      cfn = reaper.EnumerateFiles(path,f)
    end

    return path..'Log_'..string.format('%04d',fnum+1)..'.txt'
  end

  function FindInsertFX(guid, trn, fxnum)

    if not guid or not fxnum then return end

    local fnd, rfxnum, rfxguid, rtrn, rtrguid
    local track = GetTrack(trn)

    local fxguid = reaper.TrackFX_GetFXGUID(track, fxnum)
    if fxguid == guid then
      fnd = true
      rfxnum = fxnum
      rfxguid = fxguid
      rtrn = trn
      rtrguid = GetTrackGUID(track)
    else
      local fxcnt = reaper.TrackFX_GetCount(track)
      for i = 0, fxcnt-1 do
        local fxguid = reaper.TrackFX_GetFXGUID(track, i)
        if fxguid == guid then
          fnd = true
          rfxnum = i
          rfxguid = fxguid
          rtrn = trn
          rtrguid = GetTrackGUID(track)
          break
        end
      end
      if not fnd then

        for t = -1, reaper.GetNumTracks() do
          local track = GetTrack(t)
          if track then

            local fxcnt = reaper.TrackFX_GetCount(track)
            for i = 0, fxcnt-1 do
              local fxguid = reaper.TrackFX_GetFXGUID(track, i)
              if fxguid == guid then
                fnd = true
                rfxnum = i
                rfxguid = fxguid
                rtrn = t
                rtrguid = GetTrackGUID(track)
                break
              end
            end
            if fnd then
              break
            end
          end
        end
      end
    end
    return rtrn, rtrguid, rfxnum, rfxguid
  end

  --fxdata = {fxnum, fxguid, fxname, fxfn, ofxguid}

  function Strip_AddStrip(stripdata, x, y, ignoregrid, ptrnum, ptrguid, targetfxpos, pinmaps, fxdata, dm_create, templateload, dm_data, pstripid)
    if track_select == nil then return end
    if ignoregrid == nil then ignoregrid = false end

    x = round(x/2)*2
    y = round(y/2)*2
    --DBG(x..'  '..y)


    local i, j
    local strip = Strip_INIT()

    --[[local tr, trnum, trguid
    if (mouse.alt or mouse.ctrl) and ptrnum == nil then
      trnum = strips[strip].track.tracknum
      local retval, tt = reaper.GetUserInputs('Select target track number for fx plugins',1,'Track number (0 = Master):',trnum+1)
      if retval ~= true then
        return
      end
      if tonumber(tt) then
        trnum = tonumber(tt)-1
      end
      tr = GetTrack(trnum)
      if tr then
        trguid = GetTrackGUID(tr)
      else
        return
      end
    else]]
      trnum = ptrnum or strips[strip].track.tracknum
      trguid = ptrguid or strips[strip].track.guid
      tr = GetTrack(trnum)
    --end

    local fxcnt = reaper.TrackFX_GetCount(tr)
    local fxguids, ofxguids, retfxguids = {}, {}, {}
    if stripdata.strip.nchan then
      local nchan = reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN")
      if stripdata.strip.nchan > nchan then
        --DBG('setting chans to '..stripdata.strip.nchan)
        reaper.SetMediaTrackInfo_Value( tr, "I_NCHAN", stripdata.strip.nchan )
      end
    end

    if stripdata.version == nil then

      local retfx
      --create new fx
      local missing = 0
      for i = 1, #stripdata.fx do

        local fxpos
        if stripdata.plugpos == nil then

          fxpos = fxcnt+i-1-missing
          local fxn
          if stripdata.fx[i].fxname then
            fxn = stripdata.fx[i].fxname
          else
            fxn = GetPlugNameFromChunk(stripdata.fx[i].fxchunk)
          end
          if fxn then
            retfx = reaper.TrackFX_AddByName(tr, fxn, 0, -1)
          else
            retfx = -1
          end

          if retfx ~= -1 then
            --set guid in stripdata.strip
            nguid = reaper.TrackFX_GetFXGUID(tr, fxpos)
            stripdata.fx[i].nfxguid = nguid
            retfxguids[#retfxguids+1] = nguid
          else
            stripdata.fx[i].nfxguid = ''
            missing = missing + 1
          end

        else

          fxpos = stripdata.plugpos
          local track
          if stripdata.plugtrack and tracks[stripdata.plugtrack] then
            track = GetTrack(tracks[stripdata.plugtrack].tracknum)
            tr = track
          end
          stripdata.fx[i].nfxguid = reaper.TrackFX_GetFXGUID(tr, fxpos)
          fxguids[stripdata.fx[i].fxguid] = {guid = nfxguid, found = true, fxnum = fxpos}
          retfxguids[#retfxguids+1] = nfxguid
        end

        for j = 1, #stripdata.strip.controls do
          if stripdata.strip.controls[j].fxguid == stripdata.fx[i].fxguid then
            stripdata.strip.controls[j].fxguid = stripdata.fx[i].nfxguid
            if stripdata.fx[i].nfxguid == '' then
              stripdata.strip.controls[j].fxfound = false
              stripdata.strip.controls[j].fxnum = -1
            else
              stripdata.strip.controls[j].fxfound = true
              stripdata.strip.controls[j].fxnum = fxpos
            end
          end
        end

        if stripdata.plugpos == nil then
          if retfx ~= -1 then
            local fxen = nz(stripdata.fx[i].fxenabled, true)
            reaper.TrackFX_SetEnabled(tr, fxpos, fxen)
          end
        end
      end

      if stripdata.plugpos == nil then
        local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
        missing = 0
        for i = 1, #stripdata.fx do
          if stripdata.fx[i].nfxguid ~= '' then
            chunk = ReplaceChunkPresetData(chunk, i-1+fxcnt-missing, stripdata.fx[i].fxchunk)
          else
            missing = missing + 1
          end
        end
        if chunk ~= nil then
          SetTrackChunk(tr, chunk, false)
        end
      end

    elseif stripdata.version >= 3 then

      local logfn
      if logflag == true then
        logfn = GetNewLogFN()
      end

      local rcmflag = false

      --V4? - Load snapshot data
      if stripdata.version >= 4 and stripdata.snapcontent then
        local snapcontent = stripdata.snapcontent
        local data = {}
        local cnt = 0
        local lines = splitln(snapcontent)
        if lines and #lines > 0 then
          for ln = 1, #lines do
            local idx, val = string.match(lines[ln],'%[(.-)%](.*)')
            if idx then
              data[idx] = val
            end
          end
        end
        stripdata.snapshots = LoadSnapDataX(nil,data)
      end

      local retfx

      ---------------------------

      if targetfxpos ~= -1 and not templateload and (lvar.livemode ~= 2 or dm_create) then

        --create new fx
        local missing = 0
        local fxskipadd = 0

        --local t = reaper.time_precise()
        -------------------------

        local t = reaper.time_precise()
        local fxpos
        local nchunk, nchunk2
        local quickAPI, qAPIflag
        for i = 1, #stripdata.fx do
          
          --DBG('fx '..i)
          local nfxguid, ofxguid
          if stripdata.plugpos == nil then

            if fxdata == nil or not fxdata[i].fxguid then
              
              --force plugin gui closed
              if lvar.forcestrippluginguisclosed then
                stripdata.fx[i].fxchunk = string.gsub(stripdata.fx[i].fxchunk, '\nFLOAT ', '\nFLOATPOS ')
              end
              
              if targetfxpos and reaper.APIExists('TrackFX_CopyToTrack') ~= true then
                nchunk = GetTrackChunk(tr, settings_usetrackchunkfix)
                
                fxpos = targetfxpos+i
                nchunk, nfxguid, ofxguid = InsertFXChunk(nchunk, trnum, stripdata.fx[i].fxchunk, fxpos, fxcnt+i)
              else
                if (mouse.ctrl or stripdata.strip.quickload == 1) and not qAPIflag then
                  quickAPI = true
                elseif nchunk == nil then
                  nchunk = GetTrackChunk(tr, settings_usetrackchunkfix)
                end
                
                if targetfxpos then
                  fxpos = targetfxpos+i
                else
                  fxpos = fxcnt+i-1-missing
                end
                nchunk, nfxguid, ofxguid, nchunk2, qAPI = Chunk_InsertFXChunkAtEndOfFXChain(trnum, nchunk, stripdata.fx[i].fxchunk, nil, --[[logfn]] quickAPI)
                if qAPI ~= true then
                  quickAPI = false
                  qAPIflag = true
                end
              end

              if nchunk ~= nil or quickAPI then

                ofxguids[fxpos] = ofxguid
                fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = fxpos}
                retfxguids[#retfxguids+1] = nfxguid

              end
            else
              fxpos = targetfxpos+i
              ofxguids[fxpos] = fxdata[i].ofxguid
              fxguids[fxdata[i].ofxguid] = {guid = fxdata[i].fxguid, found = true, fxnum = fxpos}
              retfxguids[#retfxguids+1] = fxdata[i].fxguid
              fxskipadd = fxskipadd + 1
              --DBG('ofxguid '..fxdata[i].ofxguid)
              --DBG('nfxguid '..fxdata[i].fxguid)

            end
          end
        end

        if logfn then
          LogData(logfn, 'NCHUNK\n\n '..nchunk, '')
        end
        if nchunk or quickAPI then
          if not quickAPI then
            --DBG(nchunk)
            retval = SetTrackChunk(tr, nchunk, false)
          end
          reaper.PreventUIRefresh(1)
          if targetfxpos and reaper.APIExists('TrackFX_CopyToTrack') == true then

            local fxcnt2 = reaper.TrackFX_GetCount(tr)
            if fxdata then
              local t = fxcnt2
              for i = 1, #fxdata do
                if fxdata[i].fxguid then
                  local s
                  for f = 0, fxcnt-1 do
                    if reaper.TrackFX_GetFXGUID(tr,f) == fxdata[i].fxguid then
                      s = f
                      break
                    end
                  end
                  if s then
                    if s ~= t then
                      reaper.TrackFX_CopyToTrack(tr,s,tr,t,true)
                    end
                  end
                else
                  local s
                  for f = 0, fxcnt2-1 do
                    if reaper.TrackFX_GetFXGUID(tr,f) == fxguids[fxdata[i].ofxguid].guid then
                      s = f
                      break
                    end
                  end
                  if s then
                    if s ~= t then
                      reaper.TrackFX_CopyToTrack(tr,s,tr,t,true)
                    end
                  end
                end
              end
            end

            local lastfx = fxcnt2-1
            for i = 1, #stripdata.fx do
              if lastfx ~= targetfxpos then
                reaper.TrackFX_CopyToTrack(tr,lastfx,tr,targetfxpos,true)
              end
            end

          end
          reaper.PreventUIRefresh(-1)
        
        end

        for i = 1, #stripdata.fx do

          if stripdata.plugpos == nil then

            if targetfxpos then
              fxpos = targetfxpos+i
              ofxguid = ofxguids[fxpos]
            else
              fxpos = fxcnt+i-1-missing
              ofxguid = ofxguids[fxpos]
            end

            if pinmaps then

              SetPinMap(tr, fxpos-1, pinmaps.inLo, pinmaps.inHi, pinmaps.outLo, pinmaps.outHi)

            end

          else

            fxpos = stripdata.plugpos
            ofxguid = '{'..stripdata.fx[i].fxguid..'}'
            local track
            if stripdata.plugtrack and tracks[stripdata.plugtrack] then
              track = GetTrack(tracks[stripdata.plugtrack].tracknum)
              tr = track
            end

            nfxguid = reaper.TrackFX_GetFXGUID(tr, fxpos)
            fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = fxpos}

          end

          --check guid
          if settings_usetrackchunkfix == false then
            nguid = reaper.TrackFX_GetFXGUID(tr, fxpos)
            if nguid == nil then
              missing = missing + 1
              if fxguids[ofxguid] then
                fxguids[ofxguid].found = false
                fxguids[ofxguid].fxnum = -1
              end
            end
          else
            if targetfxpos then
              fxpos = fxpos -1
            end
            nguid = reaper.TrackFX_GetFXGUID(tr, fxpos)
            if nguid == nil then
              missing = missing + 1
              if fxguids[ofxguid] then
                fxguids[ofxguid].found = false
                fxguids[ofxguid].fxnum = -1
              end
            else
              --fxguids[ofxguid].found = true
              fxguids[ofxguid].guid = nguid

            end

          end
        end
        --DBG('Check data: '..reaper.time_precise() - t)
        --------------------------------------

        if logfn then
          LogData(logfn, 'ALL FX ADDED TO CHUNK', '')
        end

      elseif lvar.livemode ~= 2 and not templateload then
        -- do NOT add new FX - link to existing

        local linktab = {}
        local linkcntidx = {}

        --local tar_fxtbl = GetFXChunks(trnum)
        local tar_fxtbl = {}
        for i = 1, reaper.TrackFX_GetCount(track) do
        --for i = 1, #tar_fxtbl do
          tar_fxtbl[i] = {}
          local _, idnt = reaper.BR_TrackFX_GetFXModuleName(tr, i-1, '', 64)
          tar_fxtbl[i].identifier = idnt
          tar_fxtbl[i].guid = reaper.TrackFX_GetFXGUID(tr, i-1)
          --tar_fxtbl[i].identifier = GetPlugIdentifierFromChunk(tar_fxtbl[i].chunk)
        end
        
        --DBG('tarcnt '..#tar_fxtbl)
        
        for i = 1, #stripdata.fx do
          local nfxguid, ofxguid
          ofxguid = '{'..stripdata.fx[i].fxguid..'}'
          local l_fxn = GetPlugIdentifierFromChunk(stripdata.fx[i].fxchunk)
          if l_fxn then
            linktab[i] = {fxn = l_fxn}
            linkcntidx[l_fxn] = (linkcntidx[l_fxn] or 0) +1

            local cntr = 0
            for j = 1, #tar_fxtbl do
              if tar_fxtbl[j].identifier == l_fxn then
                cntr = cntr + 1
                if cntr == linkcntidx[l_fxn] then
                  nfxguid = tar_fxtbl[j].guid
                  retfxguids[#retfxguids+1] = nfxguid
                  fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = j}
                  break
                end
              end
            end

          end
        end

      elseif lvar.livemode == 2 or templateload then
        -- do NOT add new FX - link to existing
        
        if dm_data then
          for i = 1, #stripdata.fx do
            local nfxguid, ofxguid
            ofxguid = '{'..stripdata.fx[i].fxguid..'}'
            nfxguid = dm_data.fxguids[i]
            retfxguids[#retfxguids+1] = nfxguid
            if dm_data.fxns[nfxguid] then
              local j = dm_data.fxns[nfxguid].fxn
              fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = j}
            else

            end
          end
        else
          if fxdata then

            for i = 1, #stripdata.fx do
              local nfxguid, ofxguid
              ofxguid = fxdata[i].ofxguid --'{'..stripdata.fx[i].fxguid..'}'
              nfxguid = fxdata[i].fxguid
              retfxguids[#retfxguids+1] = nfxguid
              local j = fxdata[i].fxnum
              fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = j}
              --DBG(ofxguid..'  '..nfxguid)
            end

          else
            --should be only one
            local nfxguid, ofxguid
            local fxnum = math.max((targetfxpos or 1)-1,0)
            if stripdata.fx[1] then
              ofxguid = '{'..stripdata.fx[1].fxguid..'}'
              local tr = GetTrack(trnum)
              nfxguid = reaper.TrackFX_GetFXGUID(tr, fxnum)
              fxguids[ofxguid] = {guid = nfxguid, found = true, fxnum = fxnum}
            end

            retfxguids[#retfxguids+1] = nfxguid

            if templateload then --only do for templates
              for j = 1, #stripdata.strip.controls do
                if stripdata.strip.controls[j].ctlcat == ctlcats.fxparam then
                  if stripdata.strip.controls[j].param == 0 then
                    --change fxbypass assignment 
                    local fxpcnt = reaper.TrackFX_GetNumParams(tr, fxnum)
                    stripdata.strip.controls[j].param = fxpcnt-3
                  elseif stripdata.strip.controls[j].param == 1 then
                    --change fxwet assignment
                    local fxpcnt = reaper.TrackFX_GetNumParams(tr, fxnum)
                    stripdata.strip.controls[j].param = fxpcnt-2
                  else
                    stripdata.strip.controls[j].param = -1
                  end
                end
              end
            end
          end
        end

      end

      
      for j = 1, #stripdata.strip.controls do
        stripdata.strip.controls[j].ctllock = nil
        stripdata.strip.controls[j].ext_identifier = nil
        if (stripdata.strip.controls[j].ctlcat == ctlcats.fxparam
            or stripdata.strip.controls[j].ctlcat == ctlcats.fxname
            or stripdata.strip.controls[j].ctlcat == ctlcats.fxoffline
            or stripdata.strip.controls[j].ctlcat == ctlcats.fxgui
            or stripdata.strip.controls[j].ctlcat == ctlcats.rcm_switch
            or stripdata.strip.controls[j].ctlcat == ctlcats.rs5k
            or stripdata.strip.controls[j].ctlcat == ctlcats.fxmulti
            or stripdata.strip.controls[j].ctlcat == ctlcats.switcher
            or stripdata.strip.controls[j].ctlcat == ctlcats.gr_meter)
            and stripdata.strip.controls[j].fxguid then
          if stripdata.version == 3 then
            stripdata.strip.controls[j].fxguid = '{'..stripdata.strip.controls[j].fxguid..'}'
          end
          --DBG('searching guid: '..stripdata.strip.controls[j].fxguid)
          if fxguids[stripdata.strip.controls[j].fxguid] then
            --DBG('found: '..tostring(fxguids[stripdata.strip.controls[j].fxguid].guid))
            if fxguids[stripdata.strip.controls[j].fxguid].found then
              stripdata.strip.controls[j].fxfound = true
              stripdata.strip.controls[j].fxnum = fxguids[stripdata.strip.controls[j].fxguid].fxnum
              stripdata.strip.controls[j].fxguid = fxguids[stripdata.strip.controls[j].fxguid].guid
            else
              stripdata.strip.controls[j].fxguid = fxguids[stripdata.strip.controls[j].fxguid].guid
              stripdata.strip.controls[j].fxfound = false
              stripdata.strip.controls[j].fxnum = -1
            end
          else
            stripdata.strip.controls[j].fxfound = false
            stripdata.strip.controls[j].fxnum = -1
          end

          if trnum ~= strips[strip].track.tracknum then
            stripdata.strip.controls[j].tracknum = trnum
            stripdata.strip.controls[j].trackguid = trguid
          end

          if stripdata.strip.controls[j].ctlcat == ctlcats.fxmulti then
            local addfx = stripdata.strip.controls[j].addfx
            if addfx and #addfx > 0 then
              local afxcnt = #addfx
              local ntab = {}
              for afx = 1, #addfx do

                if fxguids[addfx[afx].guid] then
                  ncnt = #ntab + 1
                  ntab[ncnt] = {}
                  ntab[ncnt].guid = fxguids[addfx[afx].guid].guid
                  ntab[ncnt].fxnum = fxguids[addfx[afx].guid].fxnum
                  ntab[ncnt].trn = trnum
                  ntab[ncnt].trguid = trguid
                  --DBG(afx..' '..ntab[ncnt].guid..' '..ntab[ncnt].fxnum..' '..ntab[ncnt].trn..' '..ntab[ncnt].trguid)
                end
              end
              stripdata.strip.controls[j].addfx = ntab
            end
          end

        else
          stripdata.strip.controls[j].fxfound = true
          stripdata.strip.controls[j].fxguid = nil
          if trnum ~= strips[strip].track.tracknum then
            stripdata.strip.controls[j].tracknum = trnum
            stripdata.strip.controls[j].trackguid = trguid
          end
        end

        if (stripdata.strip.controls[j].ctlcat == ctlcats.rcm_switch)
            and stripdata.strip.controls[j].rcmrefresh and stripdata.strip.controls[j].rcmrefresh.guid then
          stripdata.strip.controls[j].rcmrefresh.guid = fxguids[stripdata.strip.controls[j].rcmrefresh.guid].guid
          rcmflag = true
        end

        if stripdata.strip.controls[j].ctlcat == ctlcats.eqcontrol then
          local bands = stripdata.strip.controls[j].eqbands
          if bands and #bands > 0 then

            for k = 1, #bands do

              if fxguids[bands[k].fxguid].found then
                bands[k].fxnum = fxguids[bands[k].fxguid].fxnum
                bands[k].fxguid = fxguids[bands[k].fxguid].guid
              end

            end

          end
        end
      end

      if rcmflag == true then
        RCM_Neb_UpdateProgIDs(stripdata.strip.controls, false)
      end

    end

    local stripid = pstripid or GenID()
    local grpid = GenID()

    local cidtrack = {}
    local gidtrack = {}

    local ocids = {}

    --add switchers
    local switchstart
    if stripdata.switchers and #stripdata.switchers > 0 then

      switchstart = #switchers+1
      local swtmp = {}
      for s = 1, #stripdata.switchers do

        local scnt = #switchers+1
        switchers[scnt] = stripdata.switchers[s]

        switchers[scnt].switchmode = switchers[scnt].switchmode or 0

        for g = 1, #switchers[scnt].grpids do
          local ngid = GenID()
          gidtrack[switchers[scnt].grpids[g].id] = ngid
          switchers[scnt].grpids[g].id = ngid
        end


        if switchers[scnt].extendid then
          if not swtmp[switchers[scnt].extendid] then
            swtmp[switchers[scnt].extendid] = GenID()
          end
          switchers[scnt].extendid = swtmp[switchers[scnt].extendid]
        end
      end
    end

    local cstart = #strips[strip][page].controls + 1
    local gstart = #strips[strip][page].graphics + 1

    local stripids
    if lvar.addstrip_keepseparateids == true and lvar.livemode == 0 then
      stripids = {}
      for j = 1, #stripdata.strip.controls do
        if stripdata.strip.controls[j].id and not stripids[stripdata.strip.controls[j].id] then
          stripids[stripdata.strip.controls[j].id] = GenID()
        end
      end
    end

    for j = 1, #stripdata.strip.controls do
      stripdata.strip.controls[j].x = stripdata.strip.controls[j].x + offsetx + x + surface_offset.x
      stripdata.strip.controls[j].y = stripdata.strip.controls[j].y + offsety + y + surface_offset.y

      if lvar.addstrip_keepseparateids == true and lvar.livemode == 0 then
        if stripdata.strip.controls[j].id and stripids[stripdata.strip.controls[j].id] then
          stripdata.strip.controls[j].id = stripids[stripdata.strip.controls[j].id]
        else
          stripdata.strip.controls[j].id = stripid
        end
      else
        stripdata.strip.controls[j].id = stripid
      end

      local cc = #strips[strip][page].controls + 1
      strips[strip][page].controls[cc] = stripdata.strip.controls[j]
      strips[strip][page].controls[cc].xsc = stripdata.strip.controls[j].x + math.floor(stripdata.strip.controls[j].w/2
                                                                            - stripdata.strip.controls[j].w*stripdata.strip.controls[j].scale/2)
      strips[strip][page].controls[cc].ysc = stripdata.strip.controls[j].y + math.floor(stripdata.strip.controls[j].ctl_info.cellh/2
                                                                            - stripdata.strip.controls[j].ctl_info.cellh*stripdata.strip.controls[j].scale/2)
      strips[strip][page].controls[cc].wsc = math.floor(stripdata.strip.controls[j].w*stripdata.strip.controls[j].scale)
      strips[strip][page].controls[cc].hsc = math.floor(stripdata.strip.controls[j].ctl_info.cellh*stripdata.strip.controls[j].scale)

      local ocid = strips[strip][page].controls[cc].c_id
      strips[strip][page].controls[cc].c_id = GenID() --give a new control id
      if ocid then
        cidtrack[ocid] = {c_id = strips[strip][page].controls[cc].c_id,
                          ctl = cc}
      end

      ocids[strips[strip][page].controls[cc].c_id] = strips[strip][page].controls[cc].o_cid

      local ogid = strips[strip][page].controls[cc].grpid
      if ogid and gidtrack[ogid] then
        strips[strip][page].controls[cc].grpid = gidtrack[ogid]
      else
        strips[strip][page].controls[cc].grpid = grpid --give main group id
      end

      if strips[strip][page].controls[cc].ctlcat == ctlcats.switcher_pagesel then
        local ogid = strips[strip][page].controls[cc].param
        if ogid then

          if gidtrack[ogid] then
            strips[strip][page].controls[cc].param = gidtrack[ogid]
          else
            strips[strip][page].controls[cc].param = GenID() --give a new group id
            gidtrack[ogid] = strips[strip][page].controls[cc].param
          end
        end
      end

      if switchstart and strips[strip][page].controls[cc].switcher then

        local swid = stripdata.switchconvtab[strips[strip][page].controls[cc].switcher]
        if swid then
          swid = swid + switchstart-1
          strips[strip][page].controls[cc].switcher = swid
        end
      end
      if switchstart and strips[strip][page].controls[cc].switcherid then

        local swid = stripdata.switchconvtab[strips[strip][page].controls[cc].switcherid]

        if swid then
          swid = swid + switchstart-1
          strips[strip][page].controls[cc].switcherid = swid
        end
      end
      
      --TSP
      if switchstart and strips[strip][page].controls[cc].ctltype == 4 then
      
        local cd = strips[strip][page].controls[cc].cycledata
        if cd and #cd > 0 then
          for cdidx = 1, #cd do
            if cd[cdidx].tsp then

              local swid = stripdata.switchconvtab[cd[cdidx].tsp.swid]
              if swid and gidtrack[cd[cdidx].tsp.grpid] then
                swid = swid + switchstart-1
                cd[cdidx].tsp.swid = swid
                cd[cdidx].tsp.grpid = gidtrack[cd[cdidx].tsp.grpid]
              else
                cd[cdidx].tsp = nil --error finding data !!
              end
            end
          end
        end
      
      end

      --compatibility
      if strips[strip][page].controls[cc].gauge and strips[strip][page].controls[cc].gauge.font == nil then
        strips[strip][page].controls[cc].gauge.font = fontname_def
      end
      if strips[strip][page].controls[cc].font == nil then strips[strip][page].controls[cc].font = fontname_def end
      if strips[strip][page].controls[cc].xydata == nil then strips[strip][page].controls[cc].xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5} end
      if strips[strip][page].controls[cc].textoffx == nil then strips[strip][page].controls[cc].textoffx = 0 end
      if strips[strip][page].controls[cc].textoffvalx == nil then strips[strip][page].controls[cc].textoffvalx = 0 end
      if strips[strip][page].controls[cc].poslock == nil then strips[strip][page].controls[cc].poslock = false end
      if strips[strip][page].controls[cc].textsizev == nil then strips[strip][page].controls[cc].textsizev = strips[strip][page].controls[cc].textsize end
      if strips[strip][page].controls[cc].textcolv == nil then strips[strip][page].controls[cc].textcolv = strips[strip][page].controls[cc].textcol end
      if strips[strip][page].controls[cc].scalemode == nil then strips[strip][page].controls[cc].scalemode = 8 end
      if strips[strip][page].controls[cc].framemode == nil then strips[strip][page].controls[cc].framemode = 1 end
      if strips[strip][page].controls[cc].ctlcat == nil then strips[strip][page].controls[cc].ctlcat = ctlcats.fxparam end
      if strips[strip][page].controls[cc].maxdp == nil then strips[strip][page].controls[cc].maxdp = -1 end
      if strips[strip][page].controls[cc].cycledata == nil then
        strips[strip][page].controls[cc].cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}}
      end
      if strips[strip][page].controls[cc].cycledata.mapptof == nil then strips[strip][page].controls[cc].cycledata.mapptof = false end
      if strips[strip][page].controls[cc].cycledata.draggable == nil then strips[strip][page].controls[cc].cycledata.draggable = false end
      if strips[strip][page].controls[cc].cycledata.spread == nil then strips[strip][page].controls[cc].cycledata.spread = false end

      for k = 1, #strips[strip][page].controls[cc].cycledata do
        if strips[strip][page].controls[cc].cycledata[k].dv == nil then
          strips[strip][page].controls[cc].cycledata[k].dv = strips[strip][page].controls[cc].cycledata[k].dispval
        end
      end

      if strips[strip][page].controls[cc].membtn == nil then
        strips[strip][page].controls[cc].membtn = {state = false, mem = 0}
      end
      if strips[strip][page].controls[cc].knobsens == nil then
        strips[strip][page].controls[cc].knobsens = {norm = settings_defknobsens.norm,
                                                     fine = settings_defknobsens.fine,
                                                     wheel = settings_defknobsens.wheel,
                                                     wheelfine = settings_defknobsens.wheelfine,
                                                     m_norm = settings_defknobsens.m_norm,
                                                     m_fine = settings_defknobsens.m_fine,
                                                     m_wheel = settings_defknobsens.m_wheel,
                                                     m_wheelfine = settings_defknobsens.m_wheelfine}
      end

      if stripdata.plugtrack ~= nil and tracks[stripdata.plugtrack] then
        if stripdata.plugtrack ~= track_select then

          strips[strip][page].controls[cc].tracknum = tracks[stripdata.plugtrack].tracknum
          strips[strip][page].controls[cc].trackguid = tracks[stripdata.plugtrack].guid
        end
      end

      strips[strip][page].controls[cc].macrofader = nil
      strips[strip][page].controls[cc].switchfader = nil
      strips[strip][page].controls[cc].mod = nil

    end
    for j = cstart, #strips[strip][page].controls do

      if strips[strip][page].controls[j].ctlcat == ctlcats.macro then

        local macro = strips[strip][page].controls[j].macroctl
        if macro then
          for m = 1, #macro do

            if cidtrack[macro[m].c_id] then

              macro[m].ctl = cidtrack[macro[m].c_id].ctl
              macro[m].c_id = cidtrack[macro[m].c_id].c_id

            end

          end
        end
      end

      if strips[strip][page].controls[j].ctlcat == ctlcats.snapshotrand then
        if strips[strip][page].controls[j].random then
          local random = strips[strip][page].controls[j].random
          if #random.ctls > 0 then
            if cidtrack[random.parent_cid] then
              random.parent = cidtrack[random.parent_cid].ctl
              random.parent_cid = cidtrack[random.parent_cid].c_id
            end
            for rc = 1, #random.ctls do

              if cidtrack[random.ctls[rc].c_id] then

                random.ctls[rc].ctl = cidtrack[random.ctls[rc].c_id].ctl
                random.ctls[rc].c_id = cidtrack[random.ctls[rc].c_id].c_id

              end

            end
          end
        end
      end
    end

    local lctl = GetLeftControlInStrip(strips[strip][page].controls, stripid)
    local dx, dy = 0, 0
    if lctl ~= -1 then
      if ignoregrid == false then
        local nx, ny = round(strips[strip][page].controls[lctl].x/settings_gridsize)*settings_gridsize,
                       round(strips[strip][page].controls[lctl].y/settings_gridsize)*settings_gridsize
        dx, dy = strips[strip][page].controls[lctl].x-nx,strips[strip][page].controls[lctl].y-ny
      end
      for j = cstart, #strips[strip][page].controls do
        if strips[strip][page].controls[j].id == stripid then
          strips[strip][page].controls[j].x = strips[strip][page].controls[j].x - dx
          strips[strip][page].controls[j].y = strips[strip][page].controls[j].y - dy
          strips[strip][page].controls[j].xsc = strips[strip][page].controls[j].xsc -dx
          strips[strip][page].controls[j].ysc = strips[strip][page].controls[j].ysc -dy
        end
      end
    end

    for j = 1, #stripdata.strip.graphics do
      if stripdata.strip.graphics[j].w > 0 and stripdata.strip.graphics[j].h > 0 then
        stripdata.strip.graphics[j].x = stripdata.strip.graphics[j].x + offsetx + x + surface_offset.x -dx
        stripdata.strip.graphics[j].y = stripdata.strip.graphics[j].y + offsety + y + surface_offset.y -dy
        if lvar.addstrip_keepseparateids == true and lvar.livemode == 0 then
          if stripids[stripdata.strip.graphics[j].id] then
            stripdata.strip.graphics[j].id = stripids[stripdata.strip.graphics[j].id]
          else
            stripdata.strip.graphics[j].id = stripid
          end
        else
          stripdata.strip.graphics[j].id = stripid
        end

        local ogid = stripdata.strip.graphics[j].grpid
        if ogid then
          if gidtrack[ogid] then
            stripdata.strip.graphics[j].grpid = gidtrack[ogid]
          else
            stripdata.strip.graphics[j].grpid = grpid --GenID() --give a new group id
            gidtrack[ogid] = stripdata.strip.graphics[j].grpid
          end
        else
          stripdata.strip.graphics[j].grpid = grpid --give main group id
        end

        if switchstart and stripdata.strip.graphics[j].switcher then

          local swid = stripdata.switchconvtab[stripdata.strip.graphics[j].switcher]
          if swid then
            swid = swid + switchstart-1
            stripdata.strip.graphics[j].switcher = swid
          end
        end

        stripdata.strip.graphics[j].g_id = GenID() --give a new graphic id

        --compatibility
        if stripdata.strip.graphics[j].poslock == nil then stripdata.strip.graphics[j].poslock = false end
        if stripdata.strip.graphics[j].stretchw == nil then stripdata.strip.graphics[j].stretchw = w end
        if stripdata.strip.graphics[j].stretchh == nil then stripdata.strip.graphics[j].stretchh = h end
        if stripdata.strip.graphics[j].bright == nil then stripdata.strip.graphics[j].bright = 0.5 end
        if stripdata.strip.graphics[j].contr == nil then stripdata.strip.graphics[j].contr = 0.5 end
        if stripdata.strip.graphics[j].rmult == nil then stripdata.strip.graphics[j].rmult = 0.5 end
        if stripdata.strip.graphics[j].gmult == nil then stripdata.strip.graphics[j].gmult = 0.5 end
        if stripdata.strip.graphics[j].bmult == nil then stripdata.strip.graphics[j].bmult = 0.5 end
        if stripdata.strip.graphics[j].alpha == nil then stripdata.strip.graphics[j].alpha = 1 end

        if stripdata.strip.graphics[j].gfxtype == nil then stripdata.strip.graphics[j].gfxtype = lvar.gfxtype.img end
        if stripdata.strip.graphics[j].font == nil then
          stripdata.strip.graphics[j].font = {idx = nil,
                                              name = nil,
                                              size = nil,
                                              bold = nil,
                                              italics = nil,
                                              underline = nil,
                                              vertical = nil,
                                              shadow = nil
                                              }
          stripdata.strip.graphics[j].text = nil
          stripdata.strip.graphics[j].text_col = nil
        end

        strips[strip][page].graphics[#strips[strip][page].graphics + 1] = stripdata.strip.graphics[j]
      end
    end

    if switchstart then
      for s = switchstart, #switchers do
        if switchers[s].parent then
          local swid = stripdata.switchconvtab[switchers[s].parent.switcherid]

          if swid then
            local nswid = swid + switchstart-1
            switchers[s].parent.switcherid = nswid
          end
          if gidtrack[switchers[s].parent.grpid] then
            switchers[s].parent.grpid = gidtrack[switchers[s].parent.grpid]
          end
        end

        for g = 1, #switchers[s].grpids do
          if gidtrack[switchers[s].grpids[g].id] then
            local gid = gidtrack[switchers[s].grpids[g].id]
            if gid then
              switchers[s].grpids[g].id = gid
            end
          end
        end

        if gidtrack[switchers[s].current] then
          switchers[s].current = gidtrack[switchers[s].current]
        end
      end
    end

    Snapshots_INIT()
    if stripdata.snapshots and #stripdata.snapshots > 0 then
      local paramchange = {}
      for i = 1, #stripdata.snapshots do

        if stripdata.snapshots[i] then
          if i == 1 then
            --page - convert to subset
            if #stripdata.snapshots[i] > 0 then
              local sstcnt = #snapshots[strip][page] + 1
              if sstcnt == 1 then
                --skip page snapshots
                sstcnt = 2
              end
              paramchange[i] = sstcnt
              snapshots[strip][page][sstcnt] = {subsetname = '##Page Snapshots',
                                                morph_time = nz(stripdata.snapshots[i].morph_time,0),
                                                morph_scale = nz(stripdata.snapshots[i].morph_scale,1),
                                                morph_sync = nz(stripdata.snapshots[i].morph_sync,false),
                                                morph_syncv = nz(stripdata.snapshots[i].morph_syncv,15),
                                                snapshot = {},
                                                ctls = {}}

              snapshots[strip][page][sstcnt].sorted = false
              snapshots[strip][page][sstcnt].mult = true
              snapshots[strip][page][sstcnt].stages = 1
              snapshots[strip][page][sstcnt].delay = {}
              snapshots[strip][page][sstcnt].mtime = {}
              snapshots[strip][page][sstcnt].deltype = {}
              snapshots[strip][page][sstcnt].delay[1] = 0
              snapshots[strip][page][sstcnt].mtime[1] = 15
              snapshots[strip][page][sstcnt].deltype[1] = 0
              snapshots[strip][page][sstcnt].stripid = stripid
              
              for ss = 1, #stripdata.snapshots[i] do

                snapshots[strip][page][sstcnt].snapshot[ss] = stripdata.snapshots[i][ss]
                snapshots[strip][page][sstcnt].selected = stripdata.snapshots[i].selected

                if snapshots[strip][page][sstcnt].snapshot[ss] then
                  if #snapshots[strip][page][sstcnt].snapshot[ss].data > 0 then
                    for d = 1, #snapshots[strip][page][sstcnt].snapshot[ss].data do
                      local ocid = snapshots[strip][page][sstcnt].snapshot[ss].data[d].c_id
                      if cidtrack[ocid] then
                        snapshots[strip][page][sstcnt].snapshot[ss].data[d].o_cid = ocids[cidtrack[ocid].c_id]
                        snapshots[strip][page][sstcnt].snapshot[ss].data[d].c_id = cidtrack[ocid].c_id
                        snapshots[strip][page][sstcnt].snapshot[ss].data[d].ctl = cidtrack[ocid].ctl
                      else
                        DBG('Erk')
                      end
                    end
                  end

                  if ss == 1 then
                    --do just once
                    if #snapshots[strip][page][sstcnt].snapshot[ss].data > 0 then
                      for d = 1, #snapshots[strip][page][sstcnt].snapshot[ss].data do
                        snapshots[strip][page][sstcnt].ctls[d] = {o_cid = snapshots[strip][page][sstcnt].snapshot[ss].data[d].o_cid,
                                                                  c_id = snapshots[strip][page][sstcnt].snapshot[ss].data[d].c_id,
                                                                  ctl = snapshots[strip][page][sstcnt].snapshot[ss].data[d].ctl,
                                                                  stage = 1,
                                                                  mem = false}
                      end
                    end
                  end

                  --faddata
                  if snapshots[strip][page][sstcnt].snapshot[ss].faddata and #snapshots[strip][page][sstcnt].snapshot[ss].faddata > 0 then
                    local fdcnt = #snapshots[strip][page][sstcnt].snapshot[ss].faddata
                    for d = 1, fdcnt do

                      local ocid = snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].c_id
                      if cidtrack[ocid] then
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].o_cid = ocids[cidtrack[ocid].c_id]
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].c_id = cidtrack[ocid].c_id
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].ctl = cidtrack[ocid].ctl
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].strip = strip
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].page = page
                      else
                        --probably from another strip = need to delete
                        snapshots[strip][page][sstcnt].snapshot[ss].faddata[d] = {}

                      end

                    end
                    --snapshots[strip][page][sstcnt].snapshot[ss].faddata = Table_RemoveNils(snapshots[strip][page][sstcnt].snapshot[ss].faddata, fdcnt)
                  end

                end

              end
            end
          else
            --subset
            local sstcnt = #snapshots[strip][page] + 1
            paramchange[i] = sstcnt
            snapshots[strip][page][sstcnt] = stripdata.snapshots[i]
            if snapshots[strip][page][sstcnt] then
              snapshots[strip][page][sstcnt].morph_time = nz(stripdata.snapshots[i].morph_time,0)
              snapshots[strip][page][sstcnt].morph_scale = nz(stripdata.snapshots[i].morph_scale,1)
              snapshots[strip][page][sstcnt].morph_sync = nz(stripdata.snapshots[i].morph_sync,false)
              snapshots[strip][page][sstcnt].morph_syncv = nz(stripdata.snapshots[i].morph_syncv,15)
              snapshots[strip][page][sstcnt].stripid = stripid
            end

            if snapshots[strip][page][sstcnt] and #snapshots[strip][page][sstcnt].ctls > 0 then

              for ctl = 1, #snapshots[strip][page][sstcnt].ctls do
                local ocid = snapshots[strip][page][sstcnt].ctls[ctl].c_id
                if cidtrack[ocid] then
                  snapshots[strip][page][sstcnt].ctls[ctl].c_id = cidtrack[ocid].c_id
                  snapshots[strip][page][sstcnt].ctls[ctl].ctl = cidtrack[ocid].ctl
                else
                  DBG('Erk')
                end
              end
            end

            if snapshots[strip][page][sstcnt] and #snapshots[strip][page][sstcnt].snapshot > 0 then
              for ss = 1, #snapshots[strip][page][sstcnt].snapshot do
                if #snapshots[strip][page][sstcnt].snapshot[ss].data > 0 then
                  for d = 1, #snapshots[strip][page][sstcnt].snapshot[ss].data do
                    local ocid = snapshots[strip][page][sstcnt].snapshot[ss].data[d].c_id
                    if cidtrack[ocid] then
                      snapshots[strip][page][sstcnt].snapshot[ss].data[d].o_cid = ocids[cidtrack[ocid].c_id]
                      snapshots[strip][page][sstcnt].snapshot[ss].data[d].c_id = cidtrack[ocid].c_id
                      snapshots[strip][page][sstcnt].snapshot[ss].data[d].ctl = cidtrack[ocid].ctl
                    else
                      DBG('Erk')
                    end
                  end
                end

                --faddata
                if snapshots[strip][page][sstcnt].snapshot[ss].faddata and #snapshots[strip][page][sstcnt].snapshot[ss].faddata > 0 then
                  local fdcnt = #snapshots[strip][page][sstcnt].snapshot[ss].faddata

                  for d = 1, fdcnt do

                    local ocid = snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].c_id

                    --[[local octl = snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].ctl
                    local fffff, ggggg
                    if ocid then
                      if cidtrack[tonumber(ocid)] then
                        fffff = cidtrack[ocid].c_id
                        ggggg = cidtrack[ocid].ctl
                      end
                      --DBG('ocid: '..tostring(ocid)..'  '..tostring(fffff)..' ctl: '..tostring(octl)..'  '..tostring(ggggg))
                    end]]

                    if cidtrack[ocid] then
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].o_cid = ocids[cidtrack[ocid].c_id]
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].c_id = cidtrack[ocid].c_id
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].ctl = cidtrack[ocid].ctl
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].strip = strip
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d].page = page
                    else
                      --probably from another strip = need to delete
                      snapshots[strip][page][sstcnt].snapshot[ss].faddata[d] = {}

                    end

                  end
                  --snapshots[strip][page][sstcnt].snapshot[ss].faddata = Table_RemoveNils(snapshots[strip][page][sstcnt].snapshot[ss].faddata, fdcnt)
                end

              end
            end

          end
        end
      end

      for j = cstart, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[j]
        if ctl.ctlcat == ctlcats.snapshot then
            if ctl.param_info.paramnum == 2 then
              --do not change ctl.param_info.paramidx - it identifies target snapshot
            else
              ctl.param_info.paramidx = paramchange[ctl.param] or 1
            end
            ctl.param = paramchange[ctl.param] or 1

        elseif ctl.ctlcat == ctlcats.xy then
            ctl.param_info.paramidx = paramchange[ctl.param]
            ctl.param = paramchange[ctl.param] or 1

        elseif ctl.ctlcat == ctlcats.snapshotrand then
          if paramchange[ctl.param] then
            if ctl.random then
              ctl.random.sst = paramchange[ctl.param]
            end
            ctl.param_info.paramidx = paramchange[ctl.param]
            ctl.param = paramchange[ctl.param] or 1
          end
        end

        --Fix missing ctl-switcher assignments
        if ctl.switcher and not switchers[ctl.switcher] then
          ctl.switcher = nil
        end
        if ctl.switcher and ctl.switcher == ctl.switcherid then
          ctl.switcher = nil
        end
      end

      StoreSnapshotControlIdxs(strip,page)

    end
    CheckDataTables(nil, true)

    PopulateTrackFX()

    --[[if lvar.livemode == 2 and lvar.popout_autoarrange and lvar.showpoponly and lvar.autoarrange_activefx then
      PopOut_AutoArrange_ActiveFX()
    end]]

    GUI_DrawCtlBitmap()
    ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
    lvar.readpeaks = PopReadPeaks()

    --lupd.update_gfx = true

    --ChangeTrack(track_select, true)
    return stripid, strip, grpid, retfxguids

  end

  function GenStripPreview_CtlsHidden(switchers, swconvtab, swid, ctl_grpid)
    local deleted
    if switchers and swconvtab and swid then
      local switchid = swconvtab[swid]

      if switchid and switchers[switchid] and switchers[switchid].deleted ~= true then
        if switchers[switchid].current ~= ctl_grpid then
          return true
        else
          if switchers[switchid].parent then
            local ret, deleted = Switcher_CtlsHidden(swconvtab[switchers[switchid].parent.switcherid], switchers[switchid].parent.grpid)
            return ret, deleted
          end
        end
      else
        if switchid and switchers[switchid] and switchers[switchid].deleted == true then
          deleted = true
        end
      end
    end
    return false, deleted
  end

  function GenStripPreview(gui, strip, switchers, switchconvtab)

    if strip then
      local i,j
      image_count_add = image_count
      local minx, miny, maxx, maxy = nil,nil,nil,nil
      if #strip.graphics > 0 then
        for i = 1, #strip.graphics do

          local gfxx = strip.graphics[i]
          if gfxx.stretchw == nil then gfxx.stretchw = gfxx.w end
          if gfxx.stretchh == nil then gfxx.stretchh = gfxx.h end
          if gfxx.stretchw > 0 and gfxx.stretchh > 0 then
            if minx == nil then
              minx = gfxx.x
              miny = gfxx.y
              maxx = gfxx.x + gfxx.stretchw
              maxy = gfxx.y + gfxx.stretchh
            else
              minx = math.min(minx, gfxx.x)
              miny = math.min(miny, gfxx.y)
              maxx = math.max(maxx, gfxx.x + gfxx.stretchw)
              maxy = math.max(maxy, gfxx.y + gfxx.stretchh)
            end
          end
          local fnd = false
          if (gfxx.gfxtype or lvar.gfxtype.img) == lvar.gfxtype.img then
            local j = lvar.gfxfiles_idx[gfxx.fn]
            --for j = 0, #graphics_files do
            if j then
              if graphics_files[j].fn == gfxx.fn then

                local iidx = LoadGraphics(gfxx.fn)
                if iidx then
                  if iidx ~= 1020 and iidx > image_count_add then
                    image_count_add = iidx
                  end
                  gfxx.imageidx = iidx
                  fnd = true
                end

                --break
              end
            else
              gfxx.imageidx = 1020
            end
          end
          --if not fnd then
          --end
        end
      end

      local fidx = lvar.ctlfiles_idx

      if #strip.controls > 0 then
        for i = 1, #strip.controls do
          local ctl = strip.controls[i]
          if minx == nil then
            minx = ctl.xsc
            miny = ctl.ysc
            maxx = ctl.xsc + ctl.wsc
            maxy = ctl.ysc + ctl.hsc --ctl_info.cellh
          else
            minx = math.min(minx, ctl.xsc)
            miny = math.min(miny, ctl.ysc)
            maxx = math.max(maxx, ctl.xsc + ctl.wsc)
            maxy = math.max(maxy, ctl.ysc + ctl.hsc) --ctl_info.cellh)
          end
          local fnd = false
          local j = fidx[ctl.ctl_info.fn]
          if j then
            if ctl_files[j].fn == ctl.ctl_info.fn then
              if ctl_files[j].imageidx ~= nil then
                fnd = true
                ctl.ctl_info.imageidx = ctl_files[j].imageidx
                ctl.knob_select = j
              else
                fnd = true
                image_count_add = F_limit(image_count_add + 1,0,image_max)
                gfx.loadimg(image_count_add, paths.controls_path..ctl.ctl_info.fn)
                ctl_files[j].imageidx = image_count_add
                ctl.ctl_info.imageidx = image_count_add
                ctl.knob_select = j
              end
            end
          else
            ctl.ctl_info.imageidx = 1020
            ctl.knob_select = -1
          end
        end
      end
      image_count = image_count_add
      offsetx, offsety = 0, 0
      if minx and miny then
        offsetx = -minx
        offsety = -miny
      elseif minx then
        offsetx = -minx
      elseif miny then
        offsety = -miny
      end

      if gui == nil then
        gui = GetGUI_vars()
      end
      maxx = maxx or 0
      maxy = maxy or 0

      gfx.dest = 1022
      --gfx.setimgdim(1022,-1,-1)
      Img_SetDim(1022,maxx+offsetx,maxy+offsety)

      --draw gfx
      if #strip.graphics > 0 then

        for i = 1, #strip.graphics do

          local gfxx = strip.graphics[i]

          local hidden = GenStripPreview_CtlsHidden(switchers, switchconvtab, gfxx.switcher, gfxx.grpid)
          if hidden ~= true then
            if (gfxx.gfxtype or lvar.gfxtype.img) == lvar.gfxtype.img then

              local x = gfxx.x+offsetx
              local y = gfxx.y+offsety
              local w = gfxx.w
              local h = gfxx.h
              local sw = gfxx.stretchw
              local sh = gfxx.stretchh
              local imageidx = gfxx.imageidx

              --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)

              if (gfxx.bright and gfxx.bright ~= 0.5) or (gfxx.contr and gfxx.contr ~= 0.5)
                 or (gfxx.rmult and gfxx.rmult ~= 0.5) or (gfxx.gmult and gfxx.gmult ~= 0.5) or (gfxx.bmult and gfxx.bmult ~= 0.5)
                 or (gfxx.alpha and gfxx.alpha ~= 1) then

                iidx = 899
                local ba = -F_limit((0.5-gfxx.bright)*2,-1,1)
                local bc = gfxx.contr
                if bc > 0.5 then
                  bc = 1+(bc-0.5)*10
                else
                  bc = bc*2
                end

                local mr = gfxx.rmult
                local mg = gfxx.gmult
                local mb = gfxx.bmult
                if mr > 0.5 then
                  mr = 1+(mr-0.5)*10
                else
                  mr = mr*2
                end
                if mg > 0.5 then
                  mg = 1+(mg-0.5)*10
                else
                  mg = mg*2
                end
                if mb > 0.5 then
                  mb = 1+(mb-0.5)*10
                else
                  mb = mb*2
                end

                local ma = gfxx.alpha

                --gfx.setimgdim(iidx, -1, -1)
                Img_SetDim(iidx, sw, sh)
                gfx.dest = iidx
                gfx.a = 1
                --gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
                if gfxx.stretchmode == 1 then
                  gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
                else
                  local edge = gfxx.edgesz
                  --corners
                  gfx.blit(imageidx,1,0, 0, 0, edge, edge, 0, 0)
                  gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, sw-edge, 0)
                  gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, sw-edge, sh-edge)
                  gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, 0, sh-edge)
                  --sides
                  gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, edge, 0, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, sw-edge, edge, edge, sh-edge-edge)
                  gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, edge, sh-edge, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, 0, edge, edge, sh-edge-edge)
                  --middle
                  gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, edge, edge, sw-edge-edge, sh-edge-edge)
                end

                gfx.muladdrect(0,0,sw,sh,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)
                gfx.dest = 1022
                gfx.a = ma
                gfx.blit(iidx,1,0, 0, 0, sw, sh, x, y)
              else
                --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
                if gfxx.stretchmode == 1 then
                  gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
                else
                  local edge = gfxx.edgesz
                  --corners
                  gfx.blit(imageidx,1,0, 0, 0, edge, edge, x+0, y+0)
                  gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, x+sw-edge, y+0)
                  gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, x+sw-edge, y+sh-edge)
                  gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, x+0, y+sh-edge)
                  --sides
                  gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, x+edge, y+0, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, x+sw-edge, y+edge, edge, sh-edge-edge)
                  gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, x+edge, y+sh-edge, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, x+0, y+edge, edge, sh-edge-edge)
                  --middle
                  gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, x+edge, y+edge, sw-edge-edge, sh-edge-edge)
                end
              end

            elseif gfxx.gfxtype == lvar.gfxtype.txt then

              local x = gfxx.x+offsetx
              local y = gfxx.y+offsety

              local text = gfxx.text
              local textcol = gfxx.text_col

              local flagb,flagi,flagu,flagv = 0,0,0,0
              if gfxx.font.bold then flagb = 98 end
              if gfxx.font.italics then flagi = 105 end
              if gfxx.font.underline then flagu = 117 end
              if gfxx.font.vertical then flagv = 122 end
              local flags = flagb + (flagi*256) + (flagu*(256^2)) + (flagv*(256^3))
              gfx.setfont(1,gfxx.font.name,
                            gfxx.font.size,flags)
              if gfxx.font.shadow then

                local shadx = gfxx.font.shadow_x or 1
                local shady = gfxx.font.shadow_y or 1

                f_Get_SSV(gui.color.black)
                gfx.a = 0.5
                gfx.x, gfx.y = x+shadx,y+shady
                gfx.drawstr(text)
              end

              gfx.a = 1
              gfx.x, gfx.y = x,y
              f_Get_SSV(textcol)

              gfx.drawstr(text)

            end
          end
        end
      end

      --draw controls
      if #strip.controls > 0 then

        for i = 1, #strip.controls do
          local ctl = strip.controls[i]
          local hidden = GenStripPreview_CtlsHidden(switchers, switchconvtab, ctl.switcher, ctl.grpid)
          if hidden ~= true and ctl.hidden ~= true then
            local scale = ctl.scale
            local x = ctl.x+offsetx
            local y = ctl.y+offsety
            local w = ctl.w
            local h = ctl.ctl_info.cellh
            local gh = h
            local val = math.floor(100*(ctl.val or 0))
            local fxnum = ctl.fxnum
            local param = ctl.param
            local iidx = ctl.ctl_info.imageidx
            local spn = ctl.show_paramname
            local spv = ctl.show_paramval
            local ctlnmov = ctl.ctlname_override or ''
            local tc = ctl.textcol
            local toff = ctl.textoff
            local toffx = math.floor(ctl.textoffx or 0)
            local tsze = ctl.textsize or 0
            local frames = ctl.ctl_info.frames
            local ctltype = ctl.ctltype
            local found = ctl.fxfound
            local gauge = ctl.gauge
            local font = ctl.font
            if not font then
              font = fontname_def
            end

            if gauge then
              gfx.dest = 1022
              GUI_DrawGauge2(gauge,x+w/2,y+h/2,ctl,nil, true)
            end

            local v2 = ctl.val or 0
            local val2 = F_limit(round(frames*v2,0),0,frames-1)
            gfx.a = 1

            if ctltype == 3 then
              --invert button
              val2 = 1-val2
            end

            gfx.setfont(1, font, gui.fontsz_knob +tsze-4)

            --load image
            gfx.dest = 1022
            gfx.a = 1
            gfx.blit(iidx,scale,0, 0, (val2)*gh, w, h, x + w/2-w*scale/2, y + h/2-h*scale/2)
            xywh = {x = x-toffx, y = y+(h/2)-toff, w = w, h = 1}
            if w > ctl.w/2 then
              local Disp_ParamV
              local Disp_Name
              if ctlnmov == '' and ctl.ctlcat ~= ctlcats.tracksend then
                Disp_Name = ctl.param_info.paramname
              else
                Disp_Name = ctlnmov
              end
              Disp_ParamV = ''

              local text_len1x, text_len1y = gfx.measurestr(Disp_Name)
              local mid = x+(w/2)

              local wwdata, wwc
              if (ctl.wwtext or 0) > 0 then

                if lupd.update_gfx or ctl.wwdata == nil then
                  wwdata = GetWWData(Disp_Name, ctl.wwtext)
                  ctl.wwdata = wwdata
                end
                wwdata = ctl.wwdata
                wwc = #wwdata

                xywh.w = ctl.wwtext
                xywh.x = math.floor(mid-(xywh.w/2)-toffx)
                xywh.h = text_len1y*(ctl.owwcnt or #wwdata)
                xywh.y = xywh.y-math.floor((text_len1y*wwc)/2)
                --t1y = xywh.y-math.ceil(text_len1y/2)
              elseif (ctl.limittext or 0) > 0 then
                xywh.w = ctl.limittext
                xywh.x = math.floor(mid-(xywh.w/2)-toffx)
                --t1y = xywh.y-math.ceil(text_len1y/2)
                xywh.y = xywh.y-math.floor(text_len1y/2)
                xywh.h = text_len1y
              end
              if spn then
                if (ctl.wwtext or 0) > 0 and ctl.wwdata then
                  local tflags = ctl.textflags or 5
                  local wwdata = ctl.wwdata
                  local box = {x = xywh.x, y = xywh.y, w = xywh.w, h = text_len1y}
                  for wwt = 1, #wwdata do
                    if wwdata[wwt].t then
                      GUI_textCtl2(gui, box, wwdata[wwt].t , tc,-4 + tsze, alpha, tflags)
                      box.y = box.y + text_len1y
                    end
                  end
                  --[[if mode == 1 and submode == 0 then
                    gfx.a = 0.5
                    gfx.rect(xywh1.x,xywh1.y,xywh1.w,xywh1.h,0)
                  end]]

                elseif (ctl.limittext or 0) > 0 then
                  local tflags = ctl.textflags or 5
                  GUI_textCtl2(gui,xywh, Disp_Name,tc,-4 + tsze, alpha, tflags)
                  --[[if mode == 1 and submode == 0 then
                    gfx.a = 0.5
                    gfx.rect(xywh1.x,xywh1.y,xywh1.w,xywh1.h,0)
                  end]]
                else
                  GUI_textCtl(gui,xywh, Disp_Name,tc,-4 + tsze, alpha)
                end
                --GUI_textCtl(gui,xywh, tostring(Disp_Name),tc,-4+tsze)
              end
            end
          end
        end

      end

      return maxx+offsetx,maxy+offsety

    end
    gfx.dest = 1


  end

  ------------------------------------------------------------

  function GenGFXDragPreview(gui)

    local strip = tracks[track_select].strip
    local i,j
    local minx, miny, maxx, maxy = nil,nil,nil,nil
    if gfx2_select then
      --for ii = 1, #gfx3_select do
        local i = gfx2_select
        if minx == nil then
          minx = strips[strip][page].graphics[i].x
          miny = strips[strip][page].graphics[i].y
          maxx = strips[strip][page].graphics[i].x + strips[strip][page].graphics[i].stretchw
          maxy = strips[strip][page].graphics[i].y + strips[strip][page].graphics[i].stretchh
        else
          minx = math.min(minx, strips[strip][page].graphics[i].x)
          miny = math.min(miny, strips[strip][page].graphics[i].y)
          maxx = math.max(maxx, strips[strip][page].graphics[i].x + strips[strip][page].graphics[i].stretchw)
          maxy = math.max(maxy, strips[strip][page].graphics[i].y + strips[strip][page].graphics[i].stretchh)
        end
      --end
    end

    offsetx = -minx
    offsety = -miny

    gfx.dest = 1022
    --gfx.setimgdim(1022,-1,-1)
    Img_SetDim(1022,maxx+offsetx,maxy+offsety)

    --draw gfx
    if gfx2_select then

      local i = gfx2_select
      local gfxx = strips[strip][page].graphics[i]
      if (strips[strip][page].graphics[i].gfxtype or lvar.gfxtype.img) == lvar.gfxtype.img then

        local x = gfxx.x+offsetx
        local y = gfxx.y+offsety
        local w = gfxx.w
        local h = gfxx.h
        local sw = gfxx.stretchw
        local sh = gfxx.stretchh
        local imageidx = gfxx.imageidx

        --gfx.a = 0.8
        --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)

        if (gfxx.bright and gfxx.bright ~= 0.5) or (gfxx.contr and gfxx.contr ~= 0.5)
                 or (gfxx.rmult and gfxx.rmult ~= 0.5) or (gfxx.gmult and gfxx.gmult ~= 0.5) or (gfxx.bmult and gfxx.bmult ~= 0.5)
                 or (gfxx.alpha and gfxx.alpha ~= 1) then
          iidx = 899
          local ba = -F_limit((0.5-gfxx.bright)*2,-1,1)
          local bc = gfxx.contr
          if bc > 0.5 then
            bc = 1+(bc-0.5)*10
          else
            bc = bc*2
          end

          local mr = gfxx.rmult
          local mg = gfxx.gmult
          local mb = gfxx.bmult
          if mr > 0.5 then
            mr = 1+(mr-0.5)*10
          else
            mr = mr*2
          end
          if mg > 0.5 then
            mg = 1+(mg-0.5)*10
          else
            mg = mg*2
          end
          if mb > 0.5 then
            mb = 1+(mb-0.5)*10
          else
            mb = mb*2
          end

          local ma = gfxx.alpha

          --gfx.setimgdim(iidx, -1, -1)
          Img_SetDim(iidx, sw, sh)
          gfx.dest = iidx
          gfx.a = 1
          --gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
          if gfxx.stretchmode == 1 then
            gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
          else
            local edge = gfxx.edgesz
            --corners
            gfx.blit(imageidx,1,0, 0, 0, edge, edge, 0, 0)
            gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, sw-edge, 0)
            gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, sw-edge, sh-edge)
            gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, 0, sh-edge)
            --sides
            gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, edge, 0, sw-edge-edge, edge)
            gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, sw-edge, edge, edge, sh-edge-edge)
            gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, edge, sh-edge, sw-edge-edge, edge)
            gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, 0, edge, edge, sh-edge-edge)
            --middle
            gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, edge, edge, sw-edge-edge, sh-edge-edge)
          end

          gfx.muladdrect(0,0,sw,sh,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)
          gfx.dest = 1022
          gfx.a = 0.8*ma
          gfx.blit(iidx,1,0, 0, 0, sw, sh, x, y)
        else
          gfx.a = 0.8
          --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
          if gfxx.stretchmode == 1 then
            gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
          else
            local edge = gfxx.edgesz
            --cornersh
            gfx.blit(imageidx,1,0, 0, 0, edge, edge, x+0, y+0)
            gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, x+sw-edge, y+0)
            gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, x+sw-edge, y+sh-edge)
            gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, x+0, y+sh-edge)
            --sides
            gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, x+edge, y+0, sw-edge-edge, edge)
            gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, x+sw-edge, y+edge, edge, sh-edge-edge)
            gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, x+edge, y+sh-edge, sw-edge-edge, edge)
            gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, x+0, y+edge, edge, sh-edge-edge)
            --middle
            gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, x+edge, y+edge, sw-edge-edge, sh-edge-edge)
          end
        end

      elseif gfxx.gfxtype == lvar.gfxtype.txt then

        local x = gfxx.x+offsetx
        local y = gfxx.y+offsety

        local text = gfxx.text
        local textcol = gfxx.text_col

        local flagb,flagi,flagu,flagv = 0,0,0,0
        if gfxx.font.bold then flagb = 98 end
        if gfxx.font.italics then flagi = 105 end
        if gfxx.font.underline then flagu = 117 end
        if gfxx.font.vertical then flagv = 122 end
        local flags = flagb + (flagi*256) + (flagu*(256^2)) + (flagv*(256^3))
        gfx.setfont(1,gfxx.font.name,
                      gfxx.font.size,flags)
        if gfxx.font.shadow then

          local shadx = gfxx.font.shadow_x or 1
          local shady = gfxx.font.shadow_y or 1

          f_Get_SSV(gui.color.black)
          gfx.a = 0.4
          gfx.x, gfx.y = x+shadx,y+shady
          gfx.drawstr(text)
        end

        gfx.a = 0.8
        gfx.x, gfx.y = x,y
        f_Get_SSV(textcol)

        gfx.drawstr(text)

      end

    end


  end

  function GenGFX4DragPreview(gui)

    local strip = tracks[track_select].strip
    local i,j
    local minx, miny, maxx, maxy = nil,nil,nil,nil
    if gfx4_select and #gfx4_select > 0 then
      for ii = 1, #gfx4_select do
        local i = gfx4_select[ii]
        if (strips[strip][page].graphics[i].gfxtype or lvar.gfxtype.img) == lvar.gfxtype.img then
          if minx == nil then
            minx = strips[strip][page].graphics[i].x
            miny = strips[strip][page].graphics[i].y
            maxx = strips[strip][page].graphics[i].x + strips[strip][page].graphics[i].stretchw
            maxy = strips[strip][page].graphics[i].y + strips[strip][page].graphics[i].stretchh
          else
            minx = math.min(minx, strips[strip][page].graphics[i].x)
            miny = math.min(miny, strips[strip][page].graphics[i].y)
            maxx = math.max(maxx, strips[strip][page].graphics[i].x + strips[strip][page].graphics[i].stretchw)
            maxy = math.max(maxy, strips[strip][page].graphics[i].y + strips[strip][page].graphics[i].stretchh)
          end
        else
          local flagb,flagi,flagu,flagv = 0,0,0,0
          local gfxx = strips[strip][page].graphics[i]
          if gfxx.font.bold then flagb = 98 end
          if gfxx.font.italics then flagi = 105 end
          if gfxx.font.underline then flagu = 117 end
          if gfxx.font.vertical then flagv = 122 end
          local flags = flagb + (flagi*256) + (flagu*(256^2))
          gfx.setfont(1,gfxx.font.name,
                        gfxx.font.size,flags)
          local w, h = gfx.measurestr(gfxx.text)
          if gfxx.font.vertical then
            w, h = h, w
            flags = flags + (flagv*(256^3))
            gfx.setfont(1,gfxx.font.name,
                          gfxx.font.size,flags)
            --[[local ww, hh = gfx.measurestr(gfxx.text)
            DBG(ww..'  '..hh) ]]             
          end
          
          if minx == nil then
            minx = strips[strip][page].graphics[i].x
            miny = strips[strip][page].graphics[i].y
            maxx = strips[strip][page].graphics[i].x + w
            maxy = strips[strip][page].graphics[i].y + h
          else
            minx = math.min(minx, strips[strip][page].graphics[i].x)
            miny = math.min(miny, strips[strip][page].graphics[i].y)
            maxx = math.max(maxx, strips[strip][page].graphics[i].x + w)
            maxy = math.max(maxy, strips[strip][page].graphics[i].y + h)
          end
        end
      end
    end

    if minx and miny then
      offsetx = -minx
      offsety = -miny

      gfx.dest = 1022
      --gfx.setimgdim(1022,-1,-1)
      Img_SetDim(1022,maxx+offsetx,maxy+offsety)

      --draw gfx
      if gfx4_select and #gfx4_select > 0 then

        for ii = 1, #gfx4_select do

          local i = gfx4_select[ii]
          local gfxx = strips[strip][page].graphics[i]
          if (strips[strip][page].graphics[i].gfxtype or lvar.gfxtype.img) == lvar.gfxtype.img then

            local x = gfxx.x+offsetx
            local y = gfxx.y+offsety
            local w = gfxx.w
            local h = gfxx.h
            local sw = gfxx.stretchw
            local sh = gfxx.stretchh
            local imageidx = gfxx.imageidx

            --gfx.a = 0.8
            --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)

            if (gfxx.bright and gfxx.bright ~= 0.5) or (gfxx.contr and gfxx.contr ~= 0.5)
                     or (gfxx.rmult and gfxx.rmult ~= 0.5) or (gfxx.gmult and gfxx.gmult ~= 0.5) or (gfxx.bmult and gfxx.bmult ~= 0.5)
                     or (gfxx.alpha and gfxx.alpha ~= 1) then
              iidx = 899
              local ba = -F_limit((0.5-gfxx.bright)*2,-1,1)
              local bc = gfxx.contr
              if bc > 0.5 then
                bc = 1+(bc-0.5)*10
              else
                bc = bc*2
              end

              local mr = gfxx.rmult
              local mg = gfxx.gmult
              local mb = gfxx.bmult
              if mr > 0.5 then
                mr = 1+(mr-0.5)*10
              else
                mr = mr*2
              end
              if mg > 0.5 then
                mg = 1+(mg-0.5)*10
              else
                mg = mg*2
              end
              if mb > 0.5 then
                mb = 1+(mb-0.5)*10
              else
                mb = mb*2
              end

              local ma = gfxx.alpha

              --gfx.setimgdim(iidx, -1, -1)
              Img_SetDim(iidx, sw, sh)
              gfx.dest = iidx
              gfx.a = 1
              --gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
              if gfxx.stretchmode == 1 then
                gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
              else
                local edge = gfxx.edgesz
                --corners
                gfx.blit(imageidx,1,0, 0, 0, edge, edge, 0, 0)
                gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, sw-edge, 0)
                gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, sw-edge, sh-edge)
                gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, 0, sh-edge)
                --sides
                gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, edge, 0, sw-edge-edge, edge)
                gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, sw-edge, edge, edge, sh-edge-edge)
                gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, edge, sh-edge, sw-edge-edge, edge)
                gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, 0, edge, edge, sh-edge-edge)
                --middle
                gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, edge, edge, sw-edge-edge, sh-edge-edge)
              end

              gfx.muladdrect(0,0,sw,sh,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)
              gfx.dest = 1022
              gfx.a = 0.8*ma
              gfx.blit(iidx,1,0, 0, 0, sw, sh, x, y)
            else
              gfx.a = 0.8
              --gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
              if gfxx.stretchmode == 1 then
                gfx.blit(imageidx,1,0, 0, 0, w, h, x, y, sw, sh)
              else
                local edge = gfxx.edgesz
                --cornersh
                gfx.blit(imageidx,1,0, 0, 0, edge, edge, x+0, y+0)
                gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, x+sw-edge, y+0)
                gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, x+sw-edge, y+sh-edge)
                gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, x+0, y+sh-edge)
                --sides
                gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, x+edge, y+0, sw-edge-edge, edge)
                gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, x+sw-edge, y+edge, edge, sh-edge-edge)
                gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, x+edge, y+sh-edge, sw-edge-edge, edge)
                gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, x+0, y+edge, edge, sh-edge-edge)
                --middle
                gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, x+edge, y+edge, sw-edge-edge, sh-edge-edge)
              end
            end

          elseif gfxx.gfxtype == lvar.gfxtype.txt then

            local x = gfxx.x+offsetx
            local y = gfxx.y+offsety

            local text = gfxx.text
            local textcol = gfxx.text_col

            local flagb,flagi,flagu,flagv = 0,0,0,0
            if gfxx.font.bold then flagb = 98 end
            if gfxx.font.italics then flagi = 105 end
            if gfxx.font.underline then flagu = 117 end
            if gfxx.font.vertical then flagv = 122 end
            local flags = flagb + (flagi*256) + (flagu*(256^2)) + (flagv*(256^3))
            gfx.setfont(1,gfxx.font.name,
                          gfxx.font.size,flags)
            if gfxx.font.shadow then

              local shadx = gfxx.font.shadow_x or 1
              local shady = gfxx.font.shadow_y or 1

              f_Get_SSV(gui.color.black)
              gfx.a = 0.4
              gfx.x, gfx.y = x+shadx,y+shady
              gfx.drawstr(text)
            end

            gfx.a = 0.8
            gfx.x, gfx.y = x,y
            f_Get_SSV(textcol)

            gfx.drawstr(text)

          end
        end
      end

    end
  end

  ------------------------------------------------------------

  function GenCtlDragPreview(gui, fixalpha)

    local strip = tracks[track_select].strip
    local i,j
    local minx, miny, maxx, maxy = nil,nil,nil,nil
    if gfx3_select and #gfx3_select > 0 then
      for ii = 1, #gfx3_select do
        local i = gfx3_select[ii].ctl
        local gfxx = strips[strip][page].graphics[i]
        if minx == nil then
          minx = gfxx.x
          miny = gfxx.y
          maxx = gfxx.x + gfxx.stretchw
          maxy = gfxx.y + gfxx.stretchh
        else
          minx = math.min(minx, gfxx.x)
          miny = math.min(miny, gfxx.y)
          maxx = math.max(maxx, gfxx.x + gfxx.stretchw)
          maxy = math.max(maxy, gfxx.y + gfxx.stretchh)
        end
      end
    end
    if ctl_select and #ctl_select > 0 then
      for ii = 1, #ctl_select do
        local i = ctl_select[ii].ctl
        local ctl = strips[strip][page].controls[i]
       
        if minx == nil then
          
          minx = ctl.x
          miny = ctl.y
          maxx = ctl.x + ctl.w
          maxy = ctl.y + ctl.ctl_info.cellh
          
        else
          
          minx = math.min(minx, ctl.x)
          miny = math.min(miny, ctl.y)
          maxx = math.max(maxx, ctl.x + ctl.w)
          maxy = math.max(maxy, ctl.y + ctl.ctl_info.cellh)
          
        end
      end
    end
    offsetx = -minx
    offsety = -miny

    gfx.a = 1
    gfx.dest = 1022
    --gfx.setimgdim(1022,-1,-1)
    Img_SetDim(1022,maxx+offsetx+b_sz*2,maxy+offsety+b_sz*2)

      --draw gfx
      if gfx3_select and #gfx3_select > 0 then

        for ii = 1, #gfx3_select do
          local i = gfx3_select[ii].ctl
          local gfxx = strips[strip][page].graphics[i]
          local hidden = Switcher_CtlsHidden(gfxx.switcher, gfxx.grpid)
          if hidden == false then
            if nz(gfxx.gfxtype, lvar.gfxtype.img) == lvar.gfxtype.img then

              local x = gfxx.x+offsetx
              local y = gfxx.y+offsety
              local w = gfxx.w
              local h = gfxx.h
              local sw = gfxx.stretchw
              local sh = gfxx.stretchh
              local imageidx = gfxx.imageidx

              --gfx.a = 0.3
              --gfx.blit(imageidx,1,0, 0, 0, w, h, x+b_sz, y+b_sz, sw, sh)

              if (gfxx.bright and gfxx.bright ~= 0.5) or (gfxx.contr and gfxx.contr ~= 0.5)
                 or (gfxx.rmult and gfxx.rmult ~= 0.5) or (gfxx.gmult and gfxx.gmult ~= 0.5) or (gfxx.bmult and gfxx.bmult ~= 0.5)
                 or (gfxx.alpha and gfxx.alpha ~= 1) then

                iidx = 899
                local ba = -F_limit((0.5-gfxx.bright)*2,-1,1)
                local bc = gfxx.contr
                if bc > 0.5 then
                  bc = 1+(bc-0.5)*10
                else
                  bc = bc*2
                end

                local mr = gfxx.rmult
                local mg = gfxx.gmult
                local mb = gfxx.bmult
                if mr > 0.5 then
                  mr = 1+(mr-0.5)*10
                else
                  mr = mr*2
                end
                if mg > 0.5 then
                  mg = 1+(mg-0.5)*10
                else
                  mg = mg*2
                end
                if mb > 0.5 then
                  mb = 1+(mb-0.5)*10
                else
                  mb = mb*2
                end

                local ma = gfxx.alpha

                --gfx.setimgdim(iidx, -1, -1)
                Img_SetDim(iidx, sw, sh)
                gfx.dest = iidx
                gfx.a = 1
                --gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
                if gfxx.stretchmode == 1 then
                  gfx.blit(imageidx,1,0, 0, 0, w, h, 0, 0, sw, sh)
                else
                  local edge = gfxx.edgesz
                  --corners
                  gfx.blit(imageidx,1,0, 0, 0, edge, edge, 0, 0)
                  gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, sw-edge, 0)
                  gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, sw-edge, sh-edge)
                  gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, 0, sh-edge)
                  --sides
                  gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, edge, 0, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, sw-edge, edge, edge, sh-edge-edge)
                  gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, edge, sh-edge, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, 0, edge, edge, sh-edge-edge)
                  --middle
                  gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, edge, edge, sw-edge-edge, sh-edge-edge)
                end

                gfx.muladdrect(0,0,sw,sh,bc*mr,bc*mg,bc*mb,1,ba,ba,ba)
                gfx.dest = 1022
                gfx.a = (fixalpha or 0.3)*ma
                gfx.blit(iidx,1,0, 0, 0, sw, sh, x+b_sz, y+b_sz)
              else
                gfx.a = (fixalpha or 0.3)
                --gfx.blit(imageidx,1,0, 0, 0, w, h, x+b_sz, y+b_sz, sw, sh)
                if gfxx.stretchmode == 1 then
                  gfx.blit(imageidx,1,0, 0, 0, w, h, x+b_sz, y+b_sz, sw, sh)
                else
                  local edge = gfxx.edgesz
                  --corners
                  x=x+b_sz
                  y=y+b_sz
                  gfx.blit(imageidx,1,0, 0, 0, edge, edge, x, y+0)
                  gfx.blit(imageidx,1,0, w-edge, 0, edge, edge, x+sw-edge, y+0)
                  gfx.blit(imageidx,1,0, w-edge, h-edge, edge, edge, x+sw-edge, y+sh-edge)
                  gfx.blit(imageidx,1,0, 0, h-edge, edge, edge, x+0, y+sh-edge)
                  --sides
                  gfx.blit(imageidx,1,0, edge, 0, w-edge-edge, edge, x+edge, y+0, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, w-edge, edge, edge, h-edge-edge, x+sw-edge, y+edge, edge, sh-edge-edge)
                  gfx.blit(imageidx,1,0, edge, h-edge, w-edge-edge, edge, x+edge, y+sh-edge, sw-edge-edge, edge)
                  gfx.blit(imageidx,1,0, 0, edge, edge, h-edge-edge, x+0, y+edge, edge, sh-edge-edge)
                  --middle
                  gfx.blit(imageidx,1,0, edge, edge, w-edge-edge, h-edge-edge, x+edge, y+edge, sw-edge-edge, sh-edge-edge)
                end
              end

            elseif gfxx.gfxtype == lvar.gfxtype.txt then

              local x = gfxx.x+offsetx
              local y = gfxx.y+offsety

              local text = gfxx.text
              local textcol = gfxx.text_col

              local flagb,flagi,flagu,flagv = 0,0,0,0
              if gfxx.font.bold then flagb = 98 end
              if gfxx.font.italics then flagi = 105 end
              if gfxx.font.underline then flagu = 117 end
              if gfxx.font.vertical then flagv = 122 end
              local flags = flagb + (flagi*256) + (flagu*(256^2)) + (flagv*(256^3))
              gfx.setfont(1,gfxx.font.name,
                            gfxx.font.size,flags)
              if gfxx.font.shadow then

                local shadx = nz(gfxx.font.shadow_x,1)
                local shady = nz(gfxx.font.shadow_y,1)

                f_Get_SSV(gui.color.black)
                gfx.a = 0.15
                gfx.x, gfx.y = x+shadx+b_sz,y+shady+b_sz
                gfx.drawstr(text)
              end

              gfx.a = (fixalpha or 0.3)
              gfx.x, gfx.y = x+b_sz,y+b_sz
              f_Get_SSV(textcol)

              gfx.drawstr(text)

            end
          end
        end
      end

    --draw controls
    if ctl_select and #strips[strip][page].controls > 0 then

      local tr = GetTrack(tracks[track_select].tracknum)

      for ii = 1, #ctl_select do
        local i = ctl_select[ii].ctl
        local ctl = strips[strip][page].controls[i]
        local hidden = Switcher_CtlsHidden(ctl.switcher, ctl.grpid)
        if hidden == false and (ctl.hidden ~= true or mode ~= 0) then
          local scale = ctl.scale
          local x = ctl.x+offsetx
          local y = ctl.y+offsety
          local w = ctl.w
          local h = ctl.ctl_info.cellh
          local gh = h
          local val = math.floor(100*(ctl.val or 0))
          local fxnum = ctl.fxnum or -1
          local param = ctl.param
          local iidx = ctl.ctl_info.imageidx
          local spn = ctl.show_paramname
          local spv = ctl.show_paramval
          local ctlnmov = ctl.ctlname_override or ''
          local tc = ctl.textcol
          local tc2 = ctl.textcolv
          local toff = math.floor(ctl.textoff)
          local toffv = math.floor(ctl.textoffval)
          local toffx = math.floor(ctl.textoffx)
          local toffvx = math.floor(ctl.textoffvalx)

          local tsze = ctl.textsize or 0
          local tsz2 = ctl.textsizev or 0
          local frames = ctl.ctl_info.frames
          local ctltype = ctl.ctltype
          local found = ctl.fxfound
          local font = ctl.font
          local ctlcat = ctl.ctlcat

          --local Disp_ParamV
          --local Disp_Name
          local v2, val2 = 0, 0

          local track = tr
          if ctl.tracknum and ctl.tracknum ~= tracks[track_select].tracknum then
            track = GetTrack(ctl.tracknum)
          end

          if track then
            if ctlcat == ctlcats.fxparam or ctlcat == ctlcats.trackparam or ctlcat == ctlcats.tracksend or ctlcat == ctlcats.pkmeter then
              v2 = nz(frameScale(ctl.framemode, GetParamValue2(ctlcat,track,fxnum,param,i)),0)
              val2 = F_limit(round(frames*v2),0,frames-1)
            elseif ctlcat == ctlcats.fxoffline or ctlcat == ctlcats.macro or ctlcat == ctlcats.midictl then
              v2 = ctl.val
              val2 = F_limit(round(frames*v2),0,frames-1)
            elseif ctlcat == ctlcats.rs5k then
              if ctl.rsdata.samples and #ctl.rsdata.samples > 0 then
                v2 = math.floor(ctl.val * lvar.maxsamples) / (#ctl.rsdata.samples -1)
                val2 = F_limit(round(frames*v2),0,frames-1)
              end
            elseif ctlcat == ctlcats.takeswitcher then
              if ctl.iteminfo then
                v2 = (math.floor(ctl.val*takeswitch_max)/(ctl.iteminfo.numtakes-1))
                val2 = F_limit(round(frames*v2),0,frames-1)
              end
            end

            gfx.a = 1

            if ctltype == 3 then
              --invert button
              val2 = 1-val2
            end

            gfx.setfont(1, font, gui.fontsz_knob +tsze-4)
            local _, th_a = gfx.measurestr('|')
            local to = th_a

            --[[if ctl.gauge then
              local gx = math.floor(ctl.xsc + offsetx + ctl.wsc/2)
              local gy = math.floor(ctl.ysc + offsety + ctl.hsc/2)
              GUI_DrawGauge2(ctl.gauge,gx,gy,ctl)
            end]]

            --load image
            gfx.blit(iidx,scale,0, 0, (val2)*gh, w, h, x + w/2-w*scale/2 +b_sz, y + h/2-h*scale/2 +b_sz)

            --xywh = {x = x+b_sz, y = math.floor(y+(h/2)-toff-1)+b_sz, w = w, h = th_a}
            if w > ctl.w/2 then
              local Disp_ParamV
              local Disp_Name
              if ctlnmov == '' and ctl.ctlcat ~= ctlcats.tracksend then
                Disp_Name = ctl.param_info.paramname
              else
                Disp_Name = ctlnmov
              end
              Disp_ParamV = ctl.display_value or ctl.val or '-'

              --local mid = x+(w/2)
              local text_len1x, text_len1y = gfx.measurestr(Disp_Name)
              gfx.setfont(1, font, gui.fontsz_knob +tsz2-4)
              local text_len2x, text_len2y = gfx.measurestr(Disp_ParamV)
              --local xywh1 = {x = math.floor(mid-(text_len1x/2))+b_sz, y = math.floor(y+(h/2)-toff-1)+b_sz, w = text_len1x, h = 1}
              local mid = x+(w/2)
              local xywh1 = {x = math.floor(mid-(text_len1x/2))-toffx+b_sz, y = math.floor(y+(h/2)-toff-1)+b_sz, w = text_len1x, h = 1}
              local xywh2 = {x = math.floor(mid-(text_len2x/2))+toffx+toffvx+b_sz, y = math.floor(y+(h/2)+toff+toffv-1)+b_sz, w = text_len2x, h = 1}

              local wwdata, wwc
              if (ctl.wwtext or 0) > 0 then

                if lupd.update_gfx or ctl.wwdata == nil then
                  wwdata = GetWWData(Disp_Name, ctl.wwtext)
                  ctl.wwdata = wwdata
                end
                wwdata = ctl.wwdata
                wwc = #wwdata

                xywh1.w = ctl.wwtext
                xywh1.x = math.floor(mid-(xywh1.w/2)-toffx+b_sz)
                xywh1.h = text_len1y*(ctl.owwcnt or #wwdata)
                xywh1.y = xywh1.y-math.floor((text_len1y*wwc)/2)
                --t1y = xywh1.y-math.ceil(text_len1y/2)
                
                if (ctl.limittext or 0) > 8 then
                  if ctl.ctlcat ~= ctlcats.sk2ctl then
                    xywh2.w = ctl.limittext
                    xywh2.x = math.floor(mid-(xywh2.w/2)+toffx+toffvx)
                  end
                  --t2y = xywh2.y-math.ceil(th2/2)
                  xywh2.y = xywh2.y-math.floor(text_len2y/2)
                  xywh2.h = text_len2y
                end
                
              elseif (ctl.limittext or 0) > 8 then
                xywh1.w = ctl.limittext
                xywh1.x = math.floor(mid-(xywh1.w/2)-toffx+b_sz)
                --t1y = xywh1.y-math.ceil(text_len1y/2)
                xywh1.y = xywh1.y-math.floor(text_len1y/2)
                xywh1.h = text_len1y
                
                xywh2.w = ctl.limittext
                xywh2.x = math.floor(mid-(xywh2.w/2)+toffx+toffvx)
                --t2y = xywh2.y-math.ceil(th2/2)
                xywh2.y = xywh2.y-math.floor(text_len2y/2)
                xywh2.h = text_len2y
              end
              if spn then
                gfx.setfont(1, font, gui.fontsz_knob +tsze-4)
                if (ctl.wwtext or 0) > 0 and ctl.wwdata then
                  local tflags = ctl.textflags or 5
                  local wwdata = ctl.wwdata
                  local box = {x = xywh1.x, y = xywh1.y, w = xywh1.w, h = text_len1y}
                  for wwt = 1, #wwdata do
                    if wwdata[wwt].t then
                      GUI_textCtl2(gui, box, wwdata[wwt].t , tc,-4 + tsze, alpha, tflags)
                      box.y = box.y + text_len1y
                    end
                  end
                  if mode == 1 and submode == 0 then
                    gfx.a = 0.5
                    gfx.rect(xywh1.x,xywh1.y,xywh1.w,xywh1.h,0)
                  end

                elseif (ctl.limittext or 0) > 8 then
                  local tflags = ctl.textflags or 5
                  GUI_textCtl2(gui,xywh1, Disp_Name,tc,-4 + tsze, alpha, tflags)
                  if mode == 1 and submode == 0 then
                    gfx.a = 0.5
                    gfx.rect(xywh1.x,xywh1.y,xywh1.w,xywh1.h,0)
                  end
                else
                  GUI_textCtl(gui,xywh1, Disp_Name,tc,-4 + tsze, alpha)
                end
                --GUI_textCtl(gui,xywh1, tostring(Disp_Name),tc,-4+tsze)
              end
              if spv then
                gfx.setfont(1, font, gui.fontsz_knob +tsz2-4)
                if (ctl.limittext or 0) > 8 and ctl.ctlcats ~= ctlcats.sk2ctl then
                  local tflags = ctl.textflags or 5
                  if tflags == -1 then
                    tflags = 5
                    if text_len2x > xywh2.w then
                      tflags = 4
                    end
                  end
                  GUI_textCtl2(gui,xywh2, Disp_ParamV,tc2,-4 + tsz2, alpha, tflags)
                  --[[if mode == 1 and submode == 0 then
                    gfx.a = 0.5
                    gfx.rect(xywh2.x,xywh2.y,xywh2.w,xywh2.h,0)
                  end]]
                else
                  GUI_textCtl(gui,xywh2, Disp_ParamV,tc2,-4 + tsz2, alpha)
                end
              end
            end
          end
        end
      end

    end

    gfx.dest = 1

  end

  ------------------------------------------------------------

  function CheckRandom(strip, page, sst)

    if strips and strips[strip] and strips[strip][page] and #strips[strip][page].controls > 0 then

      for c = 1, #strips[strip][page].controls do
        local random = strips[strip][page].controls[c].random
        if random then
          if not sst or random.sst == sst then
            RandomOpts_RefreshCtlNos(strip, page, random)
          end
        end
      end

    end

  end

  ------------------------------------------------------------

  function CheckStripControls(strip)
    --DBG('CheckStripControls '..tostring(strip))
    if strip == nil then
      if tracks[track_select] then
        strip = tracks[track_select].strip
      else
        return
      end
    end

    if strips and strips[strip] then
      local tr_found = false

      --Check track guid - none for master
      --if strips[strip].track.tracknum == -1 then return end

      if strips[strip].track.tracknum ~= -1 then
        tr_found = CheckTrack(strips[strip].track, strip)
      end

      if (tr_found or strips[strip].track.tracknum == -1) and strips and strips[strip] then
        local tr = GetTrack(strips[strip].track.tracknum)


        local fxoffline = {}
        for fxn = 0, reaper.TrackFX_GetCount(tr)-1 do
          local pn = reaper.TrackFX_GetNumParams(tr,fxn)
          if pn == lvar.offline_paramcnt then
            fxoffline[fxn] = true
          end
        end

        for p = 1, lvar.maxpage do

          if #strips[strip][p].controls > 0 then

            for c = 1, #strips[strip][p].controls do

              local ctl = strips[strip][p].controls[c]
              ctl.offline = nil

              if ctl.tracknum ~= -3 then
                local tr2 = tr
                if ctl.tracknum ~= nil then
                  tr_found = CheckTrack(tracks[ctl.tracknum],
                                        strip, p, c)
                  if tr_found then
                    tr2 = GetTrack(ctl.tracknum)

                    if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.fxname or ctl.ctlcat == ctlcats.fxoffline or ctl.ctlcat == ctlcats.fxmulti or ctl.ctlcat == ctlcats.gr_meter
                       or ctl.ctlcat == ctlcats.fxgui or ctl.ctlcat == ctlcats.rs5k or (ctl.ctlcat == ctlcats.rcm_switch and ctl.fxnum ~= nil)
                       or (ctl.ctlcat == ctlcats.switcher and switchers[ctl.switcherid] and switchers[ctl.switcherid].switchmode == 1 and ctl.fxnum) then

                      if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr2, nz(ctl.fxnum,-1)) then
                        --fx found
                        ctl.fxfound = true
                      else
                        --find fx by guid
                        local fx_found = false
                        for f = 0, reaper.TrackFX_GetCount(tr2) do
                          if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr2, f) then
                            fx_found = true
                            ctl.fxnum = f
                            break
                          end
                        end

                        if not fx_found then
                          --find on other track?
                          for t = -1, reaper.CountTracks(0)-1 do
                            local tr3 = GetTrack(t)
                            for f = 0, reaper.TrackFX_GetCount(tr3) do
                              if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr3, f) then
                                fx_found = true
                                local ctl = ctl
                                ctl.fxnum = f
                                if t == tracks[track_select].tracknum then
                                  ctl.tracknum = nil
                                  ctl.trackguid = nil
                                else
                                  ctl.tracknum = t
                                  ctl.trackguid = tracks[t].guid
                                end
                                break
                              end
                            end
                          end
                        end

                        if tracks[track_select] and tracks[track_select].strip == strip then
                          PopulateTrackFX()
                          lupd.update_gfx = true
                        end

                        if fx_found then
                          ctl.fxfound = true
                        else
                          --FX not found
                          ctl.fxfound = false
                        end
                      end

                      local pn = reaper.TrackFX_GetNumParams(tr2,ctl.fxnum)
                      if pn == lvar.offline_paramcnt then
                        ctl.offline = true
                      end

                    else
                      --other control type
                      --DBG(ctl.ctlcat..'  '..c..'  '..ctl.fxname..'  '..tostring(ctl.fxnum))
                    end

                  else
                    --track not found
                    ctl.fxfound = false
                  end
                else
                  if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.fxname or ctl.ctlcat == ctlcats.fxoffline or ctl.ctlcat == ctlcats.fxmulti or ctl.ctlcat == ctlcats.gr_meter
                     or ctl.ctlcat == ctlcats.fxgui or ctl.ctlcat == ctlcats.rs5k or (ctl.ctlcat == ctlcats.rcm_switch and ctl.fxnum ~= nil)
                     or (ctl.ctlcat == ctlcats.switcher and switchers[ctl.switcherid] and switchers[ctl.switcherid].switchmode == 1) then
                    if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr2, nz(ctl.fxnum,-1)) then
                      --fx found
                      ctl.fxfound = true
                    else
                      --find fx by guid
                      local fx_found = false
                      for f = 0, reaper.TrackFX_GetCount(tr2) do
                        if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr2, f) then
                          fx_found = true
                          ctl.fxnum = f
                          break
                        end
                      end

                      if not fx_found then
                        --find on other track?
                        for t = -1, reaper.CountTracks(0)-1 do
                          local tr3 = GetTrack(t)
                          for f = 0, reaper.TrackFX_GetCount(tr3) do
                            if ctl.fxguid == reaper.TrackFX_GetFXGUID(tr3, f) then
                              fx_found = true
                              --local ctl = strips[strip][p].controls[c]
                              ctl.fxnum = f
                              if t == tracks[track_select].tracknum then
                                ctl.tracknum = nil
                                ctl.trackguid = nil
                              else
                                ctl.tracknum = t
                                ctl.trackguid = tracks[t].guid
                              end
                              break
                            end
                          end
                        end
                      end

                      if tracks[track_select] and tracks[track_select].strip == strip then
                        PopulateTrackFX()
                        lupd.update_gfx = true
                      end

                      if fx_found then
                        ctl.fxfound = true
                      else
                        --FX not found
                        ctl.fxfound = false
                      end
                    end

                    if fxoffline[ctl.fxnum] then
                      ctl.offline = true
                    end
                  else
                    --other control type

                  end
                end
              end

            end
          end
        end

      else
        --Track not found
        --DBG('TNF')
      end
    end
    --DBG('CheckStripControls EXIT')
  end

  function CheckTrack(track, strip, p, c)

    --if track == nil then PopulateTracks() end
    --master channel

    if livemode == 2 or (track and track.tracknum == -1) then return true end
    if c == nil then
      local found = false
      local trx = GetTrack(track.tracknum)
      if trx then
        if track.guid == GetTrackGUID(trx) then
          return true
        else
          --Find track and update tracknum
          for i = 0, reaper.CountTracks(0) do
            local tr = GetTrack(i)
            if tr ~= nil then
              if strips[strip].track.guid == GetTrackGUID(tr) then
                --found
                found = true
                strips[strip].track.tracknum = i
                lupd.update_gfx = true
                break
              end
            end
          end
          PopulateTracks()
        end
      else
        for i = 0, reaper.CountTracks(0) do
          local tr = GetTrack(i)
          if tr ~= nil then
            if strips[strip].track.guid == GetTrackGUID(tr) then
              --found
              found = true
              strips[strip].track.tracknum = i
              lupd.update_gfx = true
              break
            end
          end
        end
        PopulateTracks()
      end
      return found
    else
      --external track ctl
      if strip and strips[strip] and strips[strip][p] and strips[strip][p].controls[c] then --temp
        local found = false
        local trx = GetTrack(nz(strips[strip][p].controls[c].tracknum,-2))
        if trx then
          if strips[strip][p].controls[c].trackguid == GetTrackGUID(trx) then
            return true
          else
            --Find track and update tracknum
            for i = 0, reaper.CountTracks(0) do
              local tr = GetTrack(i)
              if tr ~= nil then
                if strips[strip][p].controls[c].trackguid == GetTrackGUID(tr) then
                  --found
                  found = true
                  strips[strip][p].controls[c].tracknum = i
                  lupd.update_gfx = true
                  break
                end
              end
            end
            PopulateTracks()
          end
        else
          for i = 0, reaper.CountTracks(0) do
            local tr = GetTrack(i)
            if tr ~= nil then
              if strips[strip][p].controls[c].trackguid == GetTrackGUID(tr) then
                --found
                found = true
                strips[strip][p].controls[c].tracknum = i
                lupd.update_gfx = true
                break
              end
            end
          end
          PopulateTracks()
        end
        return found
      else
        return true --temp
      end
    end

  end

  ------------------------------------------------------------

  function testchunk(tr)
    _, statechunk = reaper.GetTrackStateChunk(tr,'',false)
    reaper.ClearConsole()

    local fxidx = 1
    local r, s, e = GetChunkPresetData(statechunk,fxidx)
    local t = string.sub(statechunk,s,e)
  end

  function ReplaceChunkPresetData(trackchunk, fxidx, newdata)

    local ret, s, e = GetChunkPresetData(trackchunk, fxidx)
    local newchunk
    if s ~= nil and e ~= nil then
      newchunk = string.sub(trackchunk,1,s-1)..newdata..string.sub(trackchunk,e+1)
    end
    return newchunk

  end

  ------------------------------------------------------------

  function GetChunkPresetData(chunk, fxidx)
    if chunk == nil then return nil end

    local ret,i,x,xe = _,_,0,1
    _,x1 = string.find(chunk, '<FXCHAIN*\n')
    xe = x1
    for i = 0, fxidx do
      if xe ~= nil then
        local cont = true
        while cont == true do
          xs,x = string.find(string.sub(chunk, xe), '<')
          if x == nil then break end
          --look for JS or VST
          if string.upper(string.sub(chunk,xe+xs,xe+xs+2)) == 'VST' or string.upper(string.sub(chunk,xe+xs,xe+xs+2)) == 'JS ' then
            cont = false
          end
          xe = xe + x
        end
      end
    end
    local s,e = nil, nil
    if x ~= nil and xe ~= nil then
      xe=xe-1
      s, e = string.find(string.sub(chunk,xe), '.->')
      s = s+xe
      e = e+xe-3 --not sure why is required - newline+blank space i guess
      ret = string.sub(chunk,s,e)
    else
      ret = nil
    end
    return ret, s, e

  end

  function GetLeftTopControlSelected()

    local minx,x = lvar.maxdim,lvar.maxdim
    local miny,y = lvar.maxdim,lvar.maxdim
    local lctl = -1
    local tctl = -1

    local ctls = strips[tracks[track_select].strip][page].controls

    for j = 1, #ctl_select do
      local ctl = ctls[ctl_select[j].ctl]
      if ctl then
        local x = math.min(x,ctl.x)
        if x < minx then
          minx = x
          lctl = j
        end
        local y = math.min(y,ctl.y)
        if y < miny then
          miny = y
          tctl = j
        end
      end
    end
    return minx, miny, lctl, tctl

  end

  function CheckSwitcherCtls2(c,switchid)
    local ret = false
    for i = 1, #strips[tracks[track_select].strip][page].controls do
      local ctl = strips[tracks[track_select].strip][page].controls[c]
      if ctl.ctlcat == ctlcats.switcher and ctl.switcher == switchid then
        ret = true
        break
      elseif ctl.ctlcat == ctlcats.switcher and c ~= i then
        local swid = ctl.switcherid
        local swret = CheckSwitcherCtls2(i, swid)
        if swret == true then
          ret = swret
          break
        end
      end
    end
    return ret
  end

  function CheckSwitcherNotChildOfSelected(c)

    local ret = false
    if ctl_select and #ctl_select > 0 then
      local switchid = strips[tracks[track_select].strip][page].controls[c].switcherid
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl.ctlcat == ctlcats.switcher and i ~= c then
          local swret = CheckSwitcherCtls2(i,switchid)
          if swret == true then
            ret = swret
            break
          end
        end
      end
    end
    return ret
  end

  function SwitcherInSwitcher(switchid)
    local ret = false
    for i = 1, #strips[tracks[track_select].strip][page].controls do
      local ctl = strips[tracks[track_select].strip][page].controls[i]
      if ctl.ctlcat == ctlcats.switcher and ctl.switcher == switchid then
        ret = true
      end
    end
    return ret
  end

  function CheckSwitcherCtls(swid, switchid)
    local ret = false
    for i = 1, #strips[tracks[track_select].strip][page].controls do
      local ctl = strips[tracks[track_select].strip][page].controls[i]
      if ctl.ctlcat == ctlcats.switcher and ctl.switcher == swid then
        ret = true
        break
      elseif ctl.ctlcat == ctlcats.switcher and ctl.switcher == switchid then
        ret = CheckSwitcherCtls(swid, ctl.switcherid)
      end
    end
    return ret
  end

  function SwitcherInSelected(swid)

    local ret = false
    if ctl_select and #ctl_select > 0 then
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl.ctlcat == ctlcats.switcher and swid == ctl.switcherid then
          ret = true
          break
        elseif ctl.ctlcat == ctlcats.switcher then
          --check switcher contains no switcher
          ret = SwitcherInSwitcher(ctl.switcherid)
          --ret = CheckSwitcherCtls(swid, ctl.switcherid)
        end
      end
    end
    return ret

  end

  function PopOut_GetBounds()
    local strip = tracks[track_select].strip
    if strip and strips[strip] and lvar.stripdim then
      local pops = strips[strip][page].pop 
      if not obj or (pops == nil or #pops == 0) then return end
      local swids = {}
      for p = 1, #pops do
        swids[p] = {popidx = p,
                    swid = pops[p].swid,
                    extpos = switchers[pops[p].swid].extendpos}
      end
      swids = table_slowsort_gen(swids,'extpos')
  
      local mingap = 20
      local mingapy = 20
      local maxw = obj.sections[10].w - mingap*2
      local vish = obj.sections[10].h
  
      local y = 0
      local yoff = 0
      local xoff = 0
      local totw = 0
      if lvar.mmov_show then
        if lvar.mixmodedir == 1 then
          yoff = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2))
        else
          xoff = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2))
        end
      end
      vish = vish - yoff
      maxw = maxw - xoff
      
      local stripw, striph
      local switchh = 0
      
      local minx, maxx, miny, maxy = math.huge, -math.huge, math.huge, -math.huge
      
      for i = 1, #swids do
      
        local swdata = lvar.stripdim.swdata[swids[i].swid]
        if swdata then
          local pop = pops[swids[i].popidx]
        
          if switchh == 0 then
            if lvar.popout_autoarrange and lvar.popout_autoarrange_hideswitchers == true then
            else
              switchh = math.floor(((swdata.sb or 0)-(swdata.st or 0))*lvar.zoom)
            end
          end
          stripw = math.floor(math.max(((swdata.stripr or 0)-(swdata.stripl or 0))*lvar.zoom, ((swdata.sr or 0)-(swdata.sl or 0))*lvar.zoom))
          striph = math.floor(math.max(((swdata.stripb or 0)-(swdata.stript or 0))*lvar.zoom, switchh + (lvar.mmgap)*lvar.zoom))
          --striph = math.floor((((swdata.stripb or 0)-(swdata.stript or 0))*lvar.zoom + (switchh + lvar.mmgap)*lvar.zoom))
  
          minx = math.min(minx, pop.x)
          miny = math.min(miny, pop.y)
          maxx = math.max(maxx, pop.x + stripw)
          maxy = math.max(maxy, pop.y + striph)
        end
        
      end
      
      rowswids = {}
      rowswids.vish = vish
      rowswids.visw = maxw
      rowswids.minx = minx
      rowswids.maxx = maxx
      rowswids.miny = miny
      rowswids.maxy = maxy
      rowswids.type = 2
      strips[strip][page].poprows = rowswids
      Pop_SetPos()
      
    end
    
  end

  function PopOut_AutoArrange_ActiveFX()
    if not obj then return end

    local strip = tracks[track_select].strip
    if strip and strips[strip] and lvar.stripdim then
      
      local extid = lvar.stripdim.swdata.extid
      if extid then
        PopOut_DeleteAll(false)
        
        local maxpos = Switcher_Ext_GetMaxPos(extid)
        local fxns, trfxguids
        --local track = GetTrack(tracks[track_select].tracknum)
        for p = 1, maxpos do
          local swid = lvar.stripdim.extposidx[extid][p]
          fxns, trfxguids = Switchers_GetFXNs2(extid, p, trfxguids)
          local active = false
          for f = 1, #fxns do
            local track = GetTrack(fxns[f].trn)
            local enabled = reaper.TrackFX_GetEnabled(track, fxns[f].fxn)
            local offline = reaper.TrackFX_GetOffline(track, fxns[f].fxn)
            if enabled and not offline then
              active = true
              break
            end
          end
          if active then
            PopOut(swid)
          end
        end
        ShowPop(true)
        PopOut_AutoArrange()
      end
    end
  end

  function PopOut_AutoArrange(checkbounds)

    local strip = tracks[track_select].strip
    if strip and strips[strip] and lvar.stripdim then
      local pops = strips[strip][page].pop 
      if not obj or (pops == nil or #pops == 0) then return end
      
      PopOut_Order()
      
      local swids = {}
      for p = 1, #pops do
        if pops[p] and switchers[pops[p].swid] then
          swids[p] = {popidx = p,
                      swid = pops[p].swid,
                      extpos = switchers[pops[p].swid].extendpos}
        end
      end
      swids = table_slowsort_gen(swids,'extpos') or {}
    
      local x = 0
      local y = 0
      local tw = 0
      local mingap = lvar.popout_autoarrange_xgap
      local mingapy = lvar.popout_autoarrange_ygap --*lvar.zoom
      if not lvar.popout_autoarrange_hideswitchers then
        mingapy = math.max(mingapy, 10)
      end
      
      local maxw = obj.sections[10].w - mingap*2
      local vish = obj.sections[10].h
      local rowswids = {}
      local rowidx = 1
      local rowcnt = 0
      local switchh = 0
      local mmgap = lvar.mmgap
      if lvar.popout_autoarrange_hideswitchers then
        mmgap = 0
      end

      local y = 0
      local yoff = 0
      local xoff = 0
      local totw = 0
      if lvar.mmov_show then
        if lvar.mixmodedir == 1 then
          yoff = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2))
        else
          xoff = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2))
        end
      end
      vish = vish - yoff
      maxw = maxw - xoff
    
      for i = 1, #swids do
      
        local swdata = lvar.stripdim.swdata[swids[i].swid]
        if swdata then
          local pop = pops[swids[i].popidx]
          
          if switchh == 0 then
            if lvar.popout_autoarrange and lvar.popout_autoarrange_hideswitchers == true then
            else
              switchh = math.floor(((swdata.sb or 0)-(swdata.st or 0))*lvar.zoom)
            end
          end
          local stripw = math.floor(math.max(((swdata.stripr or 0)-(swdata.stripl or 0))*lvar.zoom, ((swdata.sr or 0)-(swdata.sl or 0))*lvar.zoom))
          swids[i].stripw = stripw
          swids[i].striph = math.floor(math.max(((swdata.stripb or 0)-(swdata.stript or 0))*lvar.zoom + switchh + (mingapy + mmgap)*lvar.zoom))
          tw = tw + stripw
          
          if tw > maxw and (i ~= 1) then
            rowcnt = 1
            rowidx = rowidx + 1
            tw = stripw
          else
            rowcnt = rowcnt + 1
          end
          local rowh
          if rowswids[rowidx] then
            rowh = math.max((rowswids[rowidx].rowh or 0), swids[i].striph)
          else
            rowh = swids[i].striph      
          end
          rowswids[rowidx] = {rowcnt = rowcnt, 
                              rowh = rowh,
                              roww = tw}
          
          tw = tw + mingap
          
          swdata.rownum = rowidx
        end
        
      end

      local mh = 0
      for i = 1, #rowswids do
        mh = mh + rowswids[i].rowh --+ switchh + (mingapy*lvar.zoom)
        totw = math.max(totw, rowswids[i].roww)
      end
      
      rowswids.vish = vish
      rowswids.toth = mh +20
      rowswids.visw = maxw
      rowswids.totw = totw
      
      if mh < vish then
        y = math.floor(vish/2 - mh/2) + yoff
      else  
        y = yoff+20
      end
      
      if totw < maxw then
        x = math.floor(maxw/2 - totw/2) + xoff
      else
        x = xoff+20
      end
      
      local xxgap
      
      local c = 1
      for i = 1, #rowswids do
        xxgap = math.floor((maxw - rowswids[i].roww) / 2) 
        local x = xxgap + mingap + xoff --+ math.floor(xoff/2)
        for s = 1, rowswids[i].rowcnt do
        
          local ny = y + math.floor((rowswids[i].rowh/2) - ((swids[c].striph or 0)/2))
        
          local pop = pops[swids[c].popidx]
          
          pop.x = x
          pop.y = ny
          pop.row = i
        
          x = x + (swids[c].stripw or 0) + mingap --xxgap
          c=c+1
        end
        rowswids[i].ypos = y
        y = y + rowswids[i].rowh --+ mingapy*lvar.zoom
      end
      rowswids.type = 1
      
      strips[strip][page].poprows = rowswids

      --Pop_SetPos() --removed due to losing position when changing pages
      --Replace with bounds check
      if checkbounds then
        local poprows = rowswids
        local offy = 0
        if lvar.mixmodedir == 1 then
          if lvar.mmov_show then
            offy = lvar.mmov_vsize+lvar.mmov_pad*2
          end
        end
        local vh = poprows.vish
        local th = poprows.toth
        if th > vh then
          local min = math.floor((obj.sections[10].h-offy)/2 - poprows[1].rowh/2)
          local max = math.floor((obj.sections[10].h-offy)/2 - poprows[#poprows].rowh/2)
          lvar.pop_yoff = math.floor(F_limit(lvar.pop_yoff or 0, vh-th-max, 0+min))
        else
          lvar.pop_yoff = 0
        end
      end
    end
    
  end

  function PopOut(swid, x, y)

    if not swid then return end

    local strip = tracks[track_select].strip
    if not strips[strip][page].pop then
      strips[strip][page].pop = {}
      strips[strip][page].popidx = {}
    end

    if not strips[strip][page].popidx[swid] then
      local pfnd
      for p = 1, #strips[strip][page].pop do
        if strips[strip][page].pop[p].swid == swid then
          pfnd = true
          break
        end
      end
      if not pfnd then
        local idx = #strips[strip][page].pop+1
        strips[strip][page].pop[idx] = {x = x or 0, y = y or 0, swid = swid}
        strips[strip][page].popidx[swid] = idx
        
      else
        PopOut_ToTop(swid)
      end
    else
      PopOut_ToTop(swid)
    end
  end

  function PopOut_Order()
    local strip = tracks[track_select].strip
    if strips[strip][page].pop then
      local pops = strips[strip][page].pop
      local swidtab = {}
      for p = 1, #pops do
        swidtab[p] = {swid = pops[p].swid, popidx = p, extpos = switchers[pops[p].swid].extendpos}
      end
      swidtab = table_slowsort_gen(swidtab,'extpos')
      local npop = {}
      local npopidx = {}
      for s = 1, #swidtab do
        local idx = swidtab[s].popidx
        npop[s] = pops[swidtab[s].popidx]
        npopidx[swidtab[s].swid] = s
      end
      strips[strip][page].pop = npop
      strips[strip][page].popidx = npopidx
    end
  end

  function PopOut_ToTop(swid)
  
    --if not lvar.popout_autoarrange then
      local strip = tracks[track_select].strip
      local pop = strips[strip][page].pop
      local popidx = strips[strip][page].popidx
      local npop = {}
      local nidx = {}
      local idx = strips[strip][page].popidx[swid]
      for i = 1, #pop do
        if i ~= idx then
          local np = #npop+1
          npop[np] = pop[i]
          nidx[pop[i].swid] = np
        end
      end
      local np = #npop+1
      npop[np] = pop[idx]
      nidx[swid] = np
  
      strips[strip][page].pop = npop
      strips[strip][page].popidx = nidx
    --end
    GUI_DrawCtlBitmap_Mix()
    
  end

  function PopOut_Delete(swid)

    local strip = tracks[track_select].strip
    local pop = strips[strip][page].pop
    local popidx = strips[strip][page].popidx

    if pop and switchers[swid] then
      local idx = popidx[swid]
      if idx then
        switchers[swid].popx = pop[idx].x
        switchers[swid].popy = pop[idx].y
      end
    end

    local npop = {}
    local nidx = {}
    if pop then
      for i = 1, #pop do
        if pop[i].swid ~= swid then
          local np = #npop+1
          npop[np] = pop[i]
          nidx[pop[i].swid] = np
        end
      end
    end
    if #npop == 0 then
      strips[strip][page].pop = nil
      strips[strip][page].popidx = nil
    else
      strips[strip][page].pop = npop
      strips[strip][page].popidx = nidx
    end
    lupd.update_surface = true
    GUI_DrawCtlBitmap_Mix()

  end

  function PopOut_DeleteAll(redrawctlbitmap)

    local strip = tracks[track_select].strip
    local pop = strips[strip][page].pop

    if pop then
      for p = 1, #pop do
        local swid = pop[p].swid
        if switchers[swid] then
          switchers[swid].popx = pop[p].x
          switchers[swid].popy = pop[p].y
        end
      end
    end

    strips[strip][page].pop = nil
    strips[strip][page].popidx = nil

    lupd.update_surface = true
    if redrawctlbitmap then
      GUI_DrawCtlBitmap_Mix()
    end

  end

  function DragSwitcher_Ext(stripid, switchid, all)

    local strip = Strip_INIT()
    local ctls = strips[strip][page].controls

    if stripid then
      if lvar.stripdim then
        switchid = lvar.stripdim.swidx[stripid]
      else
        for i = 1, #ctls do
          if ctls[i].id == stripid then
            switchid = ctls[i].switcher
            break
          end
        end
      end
    end

    if (switchid and switchers[switchid] and switchers[switchid].switchmode == 1 and switchers[switchid].extendmode == true) or all == true then

      --test -touchfx
      if lvar.livemode == 2 and switchers[switchid] and lvar.mmtouch then
        if switchers[switchid].fxguids then
          local fxguid = switchers[switchid].fxguids[1]
          if fxguid then
            local track = GetTrack(lvar.dynamicmode_trn)
            if track then
              local fxn = GetFXNFromGUID(track,fxguid)
              if fxn then
                local trguid = GetTrackGUID(track)
                TouchFX(track, trguid, fxn, fxguid)
              end
            end
          end
        end
      end

      if all == true or (switchers[switchid].switchmode == 1 and switchers[switchid].extendmode == true) then

        local stripids = {}
        local switch_loc = {}
        local extid

        if all ~= true then
          extid = switchers[switchid].extendid
        end

        if lvar.stripdim then
          if all == true then
            switch_loc = lvar.stripdim.swdata
            stripids = lvar.stripdim.swidx
            --DBG('AA')
          else
            --DBG('EXTID: '..extid)
            switch_loc = lvar.stripdim.swdata2[extid]
            stripids = lvar.stripdim.swidx2[extid]
          end
        else
          for i = 1, #ctls do
            local swid = Switcher_GetTopLevelSwitcher(ctls[i].switcher or ctls[i].switcherid)
            if swid and switchers[swid].switchmode == 1 and
               switchers[swid].extendmode == true and (all == true or switchers[swid].extendid == extid) then
              if not switch_loc[swid] then
                switch_loc[swid] = {l = lvar.maxdim, t = lvar.maxdim, r = 0, b = 0}
              end
              switch_loc[swid].l = math.min(switch_loc[swid].l, ctls[i].xsc)
              switch_loc[swid].t = math.min(switch_loc[swid].t, ctls[i].ysc)
              switch_loc[swid].r = math.max(switch_loc[swid].r, ctls[i].xsc+ctls[i].wsc)
              switch_loc[swid].b = math.max(switch_loc[swid].b, ctls[i].ysc+ctls[i].hsc)

              if ctls[i].id and not stripids[ctls[i].id] then
                stripids[ctls[i].id] = ctls[i].switcher
              end
            end
          end

          local gfxx = strips[strip][page].graphics
          for i = 1, #gfxx do
            local swid = gfxx[i].switcher
            if swid and switchers[swid].switchmode == 1 and
               switchers[swid].extendmode == true and (all == true or switchers[swid].extendid == extid) then
              if not switch_loc[swid] then
                switch_loc[swid] = {l = lvar.maxdim, t = lvar.maxdim, r = 0, b = 0}
              end
              switch_loc[swid].l = math.min(switch_loc[swid].l, gfxx[i].x)
              switch_loc[swid].t = math.min(switch_loc[swid].t, gfxx[i].y)
              switch_loc[swid].r = math.max(switch_loc[swid].r, gfxx[i].x+gfxx[i].stretchw)
              switch_loc[swid].b = math.max(switch_loc[swid].b, gfxx[i].y+gfxx[i].stretchh)
            end
          end
        end

        local mx = mouse.mx + surface_offset.x*lvar.zoom - obj.sections[10].x
        local my = mouse.my + surface_offset.y*lvar.zoom - obj.sections[10].y
        local offx, offy = 0,0
        if lvar.livemode == 0 then
          if switchid and switch_loc and switch_loc[switchid] then
            offx = mx - switch_loc[switchid].l*lvar.zoom
            offy = my - switch_loc[switchid].t*lvar.zoom
          end
        else
          if lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[switchid] then
            local idx = strips[strip][page].popidx[switchid]
            offx = mouse.mx - strips[strip][page].pop[idx].x
            offy = mouse.my - strips[strip][page].pop[idx].y
            if lvar.popout_autoarrange then
              offy = offy - lvar.pop_yoff
            end
          else
            if lvar.spos then
              local spos = lvar.spos[switchid]
              if spos then
                offx = mouse.mx - spos.x
                offy = mouse.my - spos.y
              end
            end
          end
        end
        --[[for a,b in pairs(stripids) do
          DBG(a..'  '..b)
        end]]

        return {stripids = stripids, selected = switchid, locs = switch_loc, offx = offx, offy = offy}

      end
    end
  end

  function UnorphanCtls()

    local ctls = strips[tracks[track_select].strip][page].controls
    for c = 1, #ctls do

      if ctls[c].switcher then





      end
    end

  end

  function CtlInSelection(c)

    local ret = false
    if ctl_select and #ctl_select > 0 then
      for i = 1, #ctl_select do
        if c == ctl_select[i].ctl then
          ret = true, i
          break
        end
      end
    end
    return ret

  end

  function GetLTRBControlInGrp(grpid, switchctl)
--  local tt = reaper.time_precise()
    local l,t,r,b = lvar.maxdim,lvar.maxdim,0,0
    local gl,gt,gr,gb = lvar.maxdim,lvar.maxdim,0,0
    local set, gset = false, false
    local ctls = strips[tracks[track_select].strip][page].controls
    local swctl = strips[tracks[track_select].strip][page].controls[switchctl]
    for c = 1, #ctls do

      if ctls[c].hide ~= true then
        if switchctl then
          if grpid == ctls[c].grpid and swctl.switcherid == ctls[c].switcher then
            set = true
            --l = math.min(l, ctls[c].x)
            --t = math.min(t, ctls[c].y)
            --r = math.max(r, ctls[c].x+ctls[c].w)
            --b = math.max(b, ctls[c].y+ctls[c].ctl_info.cellh)

            l = math.min(l, ctls[c].xsc)
            t = math.min(t, ctls[c].ysc)
            r = math.max(r, ctls[c].xsc+ctls[c].wsc)
            b = math.max(b, ctls[c].ysc+ctls[c].hsc)
          end
        else
          if grpid == ctls[c].grpid then
            set = true
            --l = math.min(l, ctls[c].x)
            --t = math.min(t, ctls[c].y)
            --r = math.max(r, ctls[c].x+ctls[c].w)
            --b = math.max(b, ctls[c].y+ctls[c].ctl_info.cellh)

            l = math.min(l, ctls[c].xsc)
            t = math.min(t, ctls[c].ysc)
            r = math.max(r, ctls[c].xsc+ctls[c].wsc)
            b = math.max(b, ctls[c].ysc+ctls[c].hsc)
          end
        end
      end
    end
    local ctls = strips[tracks[track_select].strip][page].graphics
    for c = 1, #ctls do

      if ctls[c].hide ~= true then
        if switchctl then
          if grpid == ctls[c].grpid and swctl.switcherid == ctls[c].switcher then
            gset = true
            gl = math.min(gl, ctls[c].x)
            gt = math.min(gt, ctls[c].y)
            gr = math.max(gr, ctls[c].x+ctls[c].stretchw)
            gb = math.max(gb, ctls[c].y+ctls[c].stretchh)
          end
        else
          if grpid == ctls[c].grpid then
            gset = true
            gl = math.min(gl, ctls[c].x)
            gt = math.min(gt, ctls[c].y)
            gr = math.max(gr, ctls[c].x+ctls[c].stretchw)
            gb = math.max(gb, ctls[c].y+ctls[c].stretchh)
          end
        end
      end
    end
    if set == true and gset == true then
      return math.min(l,gl), math.min(t,gt), math.max(r,gr), math.max(b,gb), l-gl, b-gb
    elseif set == true then
      return l, t, r, b
    elseif gset == true then
      return gl, gt, gr, gb
    else
      --return swctl.x, swctl.y+swctl.ctl_info.cellh, swctl.x+swctl.w, swctl.y+swctl.ctl_info.cellh, 0, 0
      return swctl.xsc, swctl.ysc+swctl.hsc, swctl.xsc+swctl.wsc, swctl.ysc+swctl.hsc, 0, 0
    end
  end

  function GetLTRBControlInSel(switchctl)

    local l,t,r,b = lvar.maxdim,lvar.maxdim,0,0
    local gl,gt,gr,gb = lvar.maxdim,lvar.maxdim,0,0
    local set, gset = false, false
    local ctls = strips[tracks[track_select].strip][page].controls
    local swctl = strips[tracks[track_select].strip][page].controls[switchctl]
    for ctl = 1, #ctl_select do
      c = ctl_select[ctl].ctl
      --if ctls[c].hide ~= true then
        --if switchctl then
          --if grpid == ctls[c].grpid and swctl.switcherid == ctls[c].switcher then
            set = true
            l = math.min(l, ctls[c].x)
            t = math.min(t, ctls[c].y)
            r = math.max(r, ctls[c].x+ctls[c].w)
            b = math.max(b, ctls[c].y+ctls[c].ctl_info.cellh)
          --end
        --[[else
          if grpid == ctls[c].grpid then
            set = true
            l = math.min(l, ctls[c].x)
            t = math.min(t, ctls[c].y)
            r = math.max(r, ctls[c].x+ctls[c].w)
            b = math.max(b, ctls[c].y+ctls[c].ctl_info.cellh)
          end
        end
      end]]
    end
    if gfx3_select and #gfx3_select > 0 then
      local ctls = strips[tracks[track_select].strip][page].graphics
      for ctl = 1, #gfx3_select do
        c = gfx3_select[ctl].ctl

        --if ctls[c].hide ~= true then
          --if switchctl then
            --if grpid == ctls[c].grpid and swctl.switcherid == ctls[c].switcher then
              gset = true
              gl = math.min(gl, ctls[c].x)
              gt = math.min(gt, ctls[c].y)
              gr = math.max(gr, ctls[c].x+ctls[c].stretchw)
              gb = math.max(gb, ctls[c].y+ctls[c].stretchh)
            --end
          --[[else
            if grpid == ctls[c].grpid then
              gset = true
              gl = math.min(gl, ctls[c].x)
              gt = math.min(gt, ctls[c].y)
              gr = math.max(gr, ctls[c].x+ctls[c].stretchw)
              gb = math.max(gb, ctls[c].y+ctls[c].stretchh)
            end
          end
        end]]
      end
    end
    if set == true and gset == true then
      return math.min(l,gl), math.min(t,gt), math.max(r,gr), math.max(b,gb), l-gl, b-gb
    elseif set == true then
      return l, t, r, b
    elseif gset == true then
      return gl, gt, gr, gb
    else
      return swctl.x, swctl.y+swctl.ctl_info.cellh, swctl.x+swctl.w, swctl.y+swctl.ctl_info.cellh, 0, 0
    end
  end

  function GetGFXOffsetInSel()

    if gfx3_select == nil then
      return 0, 0, 0, 0
    else
      local l,t,r,b = lvar.maxdim,lvar.maxdim,0,0
      local gl,gt,gr,gb = lvar.maxdim,lvar.maxdim,0,0
      local ctls = strips[tracks[track_select].strip][page].controls
      for i = 1, #ctl_select do
        local c = ctl_select[i].ctl
        l = math.min(l, ctls[c].x)
        t = math.min(t, ctls[c].y)
        r = math.max(r, ctls[c].x+ctls[c].w)
        b = math.max(b, ctls[c].y+ctls[c].ctl_info.cellh)
      end
      local ctls = strips[tracks[track_select].strip][page].graphics

      for i = 1, #gfx3_select do
        local c = gfx3_select[i].ctl
        gl = math.min(gl, ctls[c].x)
        gt = math.min(gt, ctls[c].y)
        gr = math.max(gr, ctls[c].x+ctls[c].stretchw)
        gb = math.max(gb, ctls[c].y+ctls[c].stretchh)
      end
      return l-gl, t-gt, r-gr, b-gb
    end
  end

  function GetLeftControlInStrip(controls, stripid)

    local minx,x = lvar.maxdim,lvar.maxdim
    local lctl = -1

    for j = 1, #controls do
      if controls[j].id == stripid or stripid == nil then
        local x = math.min(x,controls[j].xsc)
        if x < minx then
          minx = x
          lctl = j
        end
      end
    end
    return lctl

  end

  function GetLeftControlInGroup(controls, grpid)

    local minx,x = lvar.maxdim,lvar.maxdim
    local lctl = -1

    for j = 1, #controls do
      if controls[j].grpid == grpid then -- or grpid == nil then
        local x = math.min(x,controls[j].xsc)
        if x < minx then
          minx = x
          lctl = j
        end
      end
    end
    return lctl

  end

  --with respect to gfx
  function GetLeftControlInStrip2(strip)

    local minx,gminx,miny,gminy,x,y = lvar.maxdim,lvar.maxdim,lvar.maxdim,lvar.maxdim,lvar.maxdim,lvar.maxdim
    for j = 1, #strip.controls do
      local x,y = math.min(x,strip.controls[j].xsc),strip.controls[j].y
      if x < minx then minx = x ly = y end
      if y < miny then miny = y end
    end
    x,y=lvar.maxdim,lvar.maxdim
    if #strip.graphics > 0 then
      for j = 1, #strip.graphics do
        local x,y = math.min(x,strip.graphics[j].x),math.min(y,strip.graphics[j].y)
        if x < gminx then gminx = x end
        if y < miny then miny = y end
      end
    end

    local rx, ry = 0,0
    if gminx < lvar.maxdim then
      rx = math.max(minx - gminx,0)
    end
    if miny < lvar.maxdim then
      ry = ly - miny
    end
    return rx, ry
  end

  --[[function GetLTRBControlInSelection()

    local minx,gminx,miny,gminy,x,y = 2048,2048,2048,2048,2048,2048
    local maxx,gmaxx,maxy,gmaxy = 0,0,0,0
    local ctls = strips[tracks[track_select].strip][page].controls
    local lctl, tctl
    for j = 1, #ctl_select do
      local ctl = ctls[ctl_select[j].ctl]
      local x,y = math.min(x,ctl.x),ctl.y
      if x < minx then minx = x lctl = j ly = y end
      if y < miny then miny = y tctl = j end
      local x,y = math.max(x,ctl.x+ctl.w),ctl.y+ctl.h
      if x > maxx then maxx = x rctl = j ly = y end
      if y > maxy then maxy = y bctl = j end

    end
    x,y=2048,2048
    if gfx3_select and #gfx3_select > 0 then
      for j = 1, #gfx3_select do
        local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[j].ctl]
        local x,y = math.min(x,ctl.x),math.min(y,ctl.y)
        if x < gminx then gminx = x end
        if y < miny then miny = y end
      end
    end

    local rx, ry = 0,0
    if gminx < 2048 then
      rx = math.max(minx - gminx,0)
    end
    if miny < 2048 then
      ry = ly - miny
    end
    return rx, ry, lctl, tctl
  end]]

  function GetXSpaceInGrid()

    local maxx,x = 0,0
    if strips[tracks[track_select].strip] then
      for j = 1, #strips[tracks[track_select].strip][page].controls do
        local x = math.max(x,strips[tracks[track_select].strip][page].controls[j].x+strips[tracks[track_select].strip][page].controls[j].w)
        if x > maxx then
          maxx = x
        end
      end
      if #strips[tracks[track_select].strip][page].graphics > 0 then
        for j = 1, #strips[tracks[track_select].strip][page].graphics do
          local x = math.max(x,strips[tracks[track_select].strip][page].graphics[j].x+strips[tracks[track_select].strip][page].graphics[j].w)
          if x > maxx then
            maxx = x
          end
        end
      end
    end
    return maxx

  end

  function SelectStripElements(stripid)
    --find left most
    local lctl = GetLeftControlInStrip(strips[tracks[track_select].strip][page].controls, stripid)

    if lctl ~= -1 then
      ctl_select = {}
      ctl_select[1] = {}
      ctl_select[1].ctl = lctl

      for j = 1, #strips[tracks[track_select].strip][page].controls do
        if strips[tracks[track_select].strip][page].controls[j].id == stripid and j ~= lctl then
          local cs = #ctl_select+1
          ctl_select[cs] = {}
          ctl_select[cs].ctl = j
          if cs ~= 1 then
            ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[j].x
            ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[j].y
          end
        end
      end
      gfx3_select = {}
      for j = 1, #strips[tracks[track_select].strip][page].graphics do
        if strips[tracks[track_select].strip][page].graphics[j].id == stripid then
          local cs = #gfx3_select+1
          gfx3_select[cs] = {}
          gfx3_select[cs].ctl = j
          gfx3_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[j].x
          gfx3_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[j].y
        end
      end
    else
      lctl = GetLeftControlInStrip(strips[tracks[track_select].strip][page].graphics, stripid)

      if lctl ~= -1 then
        gfx3_select = {}
        gfx3_select[1] = {}
        gfx3_select[1].ctl = lctl

        for j = 1, #strips[tracks[track_select].strip][page].graphics do
          if strips[tracks[track_select].strip][page].graphics[j].id == stripid and j ~= lctl then
            local cs = #gfx3_select+1
            gfx3_select[cs] = {}
            gfx3_select[cs].ctl = j
            gfx3_select[cs].relx = strips[tracks[track_select].strip][page].graphics[gfx3_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[j].x
            gfx3_select[cs].rely = strips[tracks[track_select].strip][page].graphics[gfx3_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[j].y
          end
        end
      end
    end
  end

  function SelectSwitchElements2(swid)

    ctl_select = {}
    gfx3_select = {}

    local grpids = {}
    for i = 1, #switchers[swid].grpids do
      grpids[switchers[swid].grpids[i].id] = true
    end


    local ctls = strips[tracks[track_select].strip][page].controls
    for j = 1, #ctls do
      if ctls[j].switcher == swid or grpids[ctls[j].grpid or -1] == true then
        local cs = #ctl_select+1
        ctl_select[cs] = {}
        ctl_select[cs].ctl = j
        if ctls[j].ctlcat == ctlcats.switcher then
          SelectSwitchElementsRecurse(ctls[j].switcherid)
        end
      end
    end

    local gfxx = strips[tracks[track_select].strip][page].graphics
    for j = 1, #gfxx do
      if gfxx[j].switcher == swid or grpids[gfxx[j].grpid or -1] == true then
        local cs = #gfx3_select+1
        gfx3_select[cs] = {}
        gfx3_select[cs].ctl = j
      end
    end

  end

  function SelectSwitchElements(swid, c)

    ctl_select = {}
    gfx3_select = {}

    if c then
      ctl_select[1] = {}
      ctl_select[1].ctl = c
    end

    --SelectSwitchElementsRecurse(swid)
    local ctls = strips[tracks[track_select].strip][page].controls
    for j = 1, #ctls do
      if ctls[j].switcher == swid then
        local cs = #ctl_select+1
        ctl_select[cs] = {}
        ctl_select[cs].ctl = j
        if cs ~= 1 then
          ctl_select[cs].relx = ctls[ctl_select[1].ctl].x - ctls[j].x
          ctl_select[cs].rely = ctls[ctl_select[1].ctl].y - ctls[j].y
        end
        if ctls[j].ctlcat == ctlcats.switcher then
          SelectSwitchElementsRecurse(ctls[j].switcherid)
        end
      end
    end

    local gfxx = strips[tracks[track_select].strip][page].graphics
    for j = 1, #gfxx do
      if gfxx[j].switcher == swid then
        local cs = #gfx3_select+1
        gfx3_select[cs] = {}
        gfx3_select[cs].ctl = j
        if ctl_select[1] then
          gfx3_select[cs].relx = ctls[ctl_select[1].ctl].x - gfxx[j].x
          gfx3_select[cs].rely = ctls[ctl_select[1].ctl].y - gfxx[j].y
        end
      end
    end

  end

  function SelectSwitchElementsRecurse(swid)

    local ctls = strips[tracks[track_select].strip][page].controls
    for j = 1, #ctls do
      if ctls[j].switcher == swid then
        local cs = #ctl_select+1
        ctl_select[cs] = {}
        ctl_select[cs].ctl = j
        if cs ~= 1 then
          ctl_select[cs].relx = ctls[ctl_select[1].ctl].x - ctls[j].x
          ctl_select[cs].rely = ctls[ctl_select[1].ctl].y - ctls[j].y
        end
        if ctls[j].ctlcat == ctlcats.switcher then
          SelectSwitchElementsRecurse(ctls[j].switcherid)
        end
      end
    end

    local gfxx = strips[tracks[track_select].strip][page].graphics
    for j = 1, #gfxx do
      if gfxx[j].switcher == swid then
        local cs = #gfx3_select+1
        gfx3_select[cs] = {}
        gfx3_select[cs].ctl = j
        gfx3_select[cs].relx = ctls[ctl_select[1].ctl].x - gfxx[j].x
        gfx3_select[cs].rely = ctls[ctl_select[1].ctl].y - gfxx[j].y
      end
    end

  end

  function SelectGroupElements(grpid, ctl_select)
    --find left most
    local lctl = GetLeftControlInGroup(strips[tracks[track_select].strip][page].controls, grpid)

    if lctl ~= -1 then
      if ctl_select == nil then
        ctl_select = {}
        ctl_select[1] = {}
        ctl_select[1].ctl = lctl
      end

      for j = 1, #strips[tracks[track_select].strip][page].controls do
        if strips[tracks[track_select].strip][page].controls[j].grpid == grpid and j ~= lctl then
          local cs = #ctl_select+1
          ctl_select[cs] = {}
          ctl_select[cs].ctl = j
          if cs ~= 1 then
            ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[j].x
            ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[j].y
          end
        end
      end
      gfx3_select = {}
      for j = 1, #strips[tracks[track_select].strip][page].graphics do
        if strips[tracks[track_select].strip][page].graphics[j].grpid == grpid then
          local cs = #gfx3_select+1
          gfx3_select[cs] = {}
          gfx3_select[cs].ctl = j
          gfx3_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[j].x
          gfx3_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[j].y
        end
      end
    end
    return ctl_select

  end

  function AutoCentreCtls()

    if strips and tracks[track_select] and strips[tracks[track_select].strip] then
      local xywh = CalcCtlRect()
      if xywh then

        strips[tracks[track_select].strip][page].surface_x = surface_offset.x
        strips[tracks[track_select].strip][page].surface_y = surface_offset.y
        lupd.update_gfx = true
      end
    end

  end

  function OpenMenu(str)

    local ret = gfx.showmenu(str)
    return ret

  end

  function OpenMsgBox(id, str, butt, str2)

    MS_Open = id
    msgbox = {text1 = str, text2 = str2, b = butt}
    lupd.update_gfx = true

  end

  function GFXMenu()
    local mstr
    local gp = 'Paste'
    if gfx_clip == nil then
      gp = '#'.. gp
    end
    local lb = ''
    if settings_drawbglabelsontop then
      lb = '!'
    end
    if gfx4_select and #gfx4_select > 0 then
      local mm = '#Copy formatting|#Paste formatting'
      local more1 = ''
      if #gfx4_select > 1 then
        more1 = '#'
      end
      if strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].gfxtype == lvar.gfxtype.txt then
        mm = more1..'Copy formatting|Paste formatting'
      end
      local mm2 = 'Lock position'
      if nz(strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].poslock,false) == true then
        mm2 = '!'..mm2
      end
      mstr = more1..'Move up|'..more1..'Move down|Bring to front|Send to back||Insert label||'..lb..'Labels on top||'..mm..'||'..mm2..'||Delete||Copy|'..gp..'||Ungroup'
    else
      mstr = '#Move up|#Move down|#Bring to front|#Send to back||Insert label||'..lb..'Labels on top||#Copy formatting|#Paste formatting||#Lock position||#Delete|#Copy|'..gp..'||#Ungroup'
    end
    mstr = mstr .. '||Gfx Info'
    gfx.x, gfx.y = mouse.mx, mouse.my
    local mx, my = mouse.mx, mouse.my
    res = OpenMenu(mstr)
    if res ~= 0 then
      local gfx2_select
      if gfx4_select then
        gfx2_select = gfx4_select[1]
      end
      if res == 1 then
        if gfx2_select < #strips[tracks[track_select].strip][page].graphics then
          local tbl = {}
          table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx2_select])
          table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx2_select+1])
          strips[tracks[track_select].strip][page].graphics[gfx2_select] = tbl[2]
          strips[tracks[track_select].strip][page].graphics[gfx2_select+1] = tbl[1]
          gfx2_select = gfx2_select +1
          gfx4_select[1] = gfx2_select
        end

      elseif res == 2 then
        if gfx2_select > 1 then
          local tbl = {}
          table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx2_select])
          table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx2_select-1])
          strips[tracks[track_select].strip][page].graphics[gfx2_select] = tbl[2]
          strips[tracks[track_select].strip][page].graphics[gfx2_select-1] = tbl[1]
          gfx2_select = gfx2_select -1
          gfx4_select[1] = gfx2_select
        end

      elseif res == 3 then
        --to front
        if gfx4_select then
          local cnt = #strips[tracks[track_select].strip][page].graphics
          local tbl = {}
          local tbl2 = {}

          table.sort(gfx4_select)
          for i = 1, #gfx4_select do
            table.insert(tbl2, strips[tracks[track_select].strip][page].graphics[gfx4_select[i]])
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]] = nil
          end

          for i = 1, cnt do
            if strips[tracks[track_select].strip][page].graphics[i] ~= nil then
              table.insert(tbl, strips[tracks[track_select].strip][page].graphics[i])
            end
          end

          for i = 1, #tbl2 do
            table.insert(tbl,tbl2[i])
          end
          strips[tracks[track_select].strip][page].graphics = tbl
          local gfxtbl = {}
          local cnt = #gfx4_select
          gfx4_selectidx = {}
          for i = 1, cnt do
            local gidx = #strips[tracks[track_select].strip][page].graphics-(i-1)
            gfx4_select[i] = gidx
            gfx4_selectidx[gidx] = i
          end
        end

      elseif res == 4 then
        --to back
        if gfx4_select then
          local cnt = #strips[tracks[track_select].strip][page].graphics
          local tbl = {}

          table.sort(gfx4_select)
          for i = 1, #gfx4_select do
            table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx4_select[i]])
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]] = nil
          end

          for i = 1, cnt do
            if strips[tracks[track_select].strip][page].graphics[i] ~= nil then
              table.insert(tbl, strips[tracks[track_select].strip][page].graphics[i])
            end
          end
          strips[tracks[track_select].strip][page].graphics = tbl
          gfx4_selectidx = {}
          local cnt = #gfx4_select
          for i = 1, cnt do
            gfx4_select[i] = i
            gfx4_selectidx[i] = i
          end
        end

      elseif res == 5 then

        InsertLabel(mx,my)

      elseif res == 6 then

        settings_drawbglabelsontop = not settings_drawbglabelsontop
        lupd.update_bg = true

      elseif res == 7 then

        local tbl = {}
        table.insert(tbl, strips[tracks[track_select].strip][page].graphics[gfx2_select])
        gfx_lblformat_copy = tbl[1]

      elseif res == 8 then

        if gfx_lblformat_copy then

          for i = 1, #gfx4_select do
            if strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].gfxtype == lvar.gfxtype.txt then
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.name = gfx_lblformat_copy.font.name
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.size = gfx_lblformat_copy.font.size
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.bold = gfx_lblformat_copy.font.bold
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.italics = gfx_lblformat_copy.font.italics
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.underline = gfx_lblformat_copy.font.underline
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.vertical = gfx_lblformat_copy.font.vertical
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow = gfx_lblformat_copy.font.shadow
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_x = gfx_lblformat_copy.font.shadow_x
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_y = gfx_lblformat_copy.font.shadow_y
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_a = gfx_lblformat_copy.font.shadow_a
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].text_col = gfx_lblformat_copy.text_col
            end
          end

        end

      elseif res == 9 then

        Undo_Set({'poslock'})
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].poslock = not strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].poslock
        end
        poslock_select = strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock
        lupd.update_gfx = true

      elseif res == 10 then

        GFX_Delete()

      elseif res == 11 then

        GFX_Copy()

      elseif res == 12 then
        local keep_coords
        if mouse.shift then
          keep_coords = true
        end
        GFX_Paste(keep_coords)

      elseif res == 13 then
        if gfx4_select and #gfx4_select > 0 then
          for c = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[c]].grpid = nil
            strips[tracks[track_select].strip][page].graphics[gfx4_select[c]].switcher = nil
          end
        end
        lupd.update_gfx = true
        lupd.update_bg = true
        
      elseif res == 14 then
        if gfx4_select and #gfx4_select > 0 then
          for c = 1, #gfx4_select do
            GfxInfo(tracks[track_select].strip, page, gfx4_select[c])
          end
        end
      end
    end
    lupd.update_gfx = true
  end

  function GFX_Delete()

    ctl_select = nil
    DeleteSelectedCtls()
    lupd.update_gfx = true

  end

  function GFX_Copy()

    gfx_clip = {}
    if gfx4_select then
      table.sort(gfx4_select)
      for i = 1, #gfx4_select do
        gfx_clip[i] = GetGraphicsTable(tracks[track_select].strip, page, gfx4_select[i])
      end
    end
    
  end

  function GFX_Paste(keep_coords)

    if gfx_clip then
      local rel = {}
      for i = 1, #gfx_clip do
        rel[i] = {}
        if i == 1 then
          rel[i].x = 0
          rel[i].y = 0
        else
          rel[i].x = gfx_clip[1].x - gfx_clip[i].x
          rel[i].y = gfx_clip[1].y - gfx_clip[i].y
        end
      end
      local strip = Strip_INIT()
      for i = 1, #gfx_clip do
        local gfxx = strips[tracks[track_select].strip][page].graphics
        local gcnt = #gfxx+1
        gfxx[gcnt] = GetGraphicsTable(_,_,_, gfx_clip[i])
        gfxx[gcnt].g_id = GenID()
        if not keep_coords then
          gfxx[gcnt].x = (mouse.mx+surface_offset.x-obj.sections[10].x)-rel[i].x
          gfxx[gcnt].y = (mouse.my+surface_offset.y-obj.sections[10].y)-rel[i].y
        end
      end
      lupd.update_gfx = true
    end

  end

  function InsertLabel(x,y)

    label_add = {x = x, y = y}
    --EditLabel(6)
    local strip = Strip_INIT()

    if strips and strips[tracks[track_select].strip] then
      OpenEB(6,'Please enter text for label:')
    end

  end

  function InsertLabel2(txt)

    if txt and txt ~= '' then

      gfx_text_select = txt
      Strip_AddGFX(lvar.gfxtype.txt)
      lupd.update_gfx = true

    end

  end

  function EditLabel2(txt)

    if string.len(txt) > 0 then
      gfx_text_select = txt
      if gfx4_select then
        for i = 1, #gfx4_select do
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]
          if gfxx.gfxtype == lvar.gfxtype.txt then
            gfxx.text = txt
          end
        end
      end
    end

  end

  function EditFont2(font)

    gfx.setfont(1,font)
    local f2,f3 = gfx.getfont()
    gfx_font_select.name = f3
    if gfx4_select then
      for i = 1, #gfx4_select do
        local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]
        if gfxx.gfxtype == lvar.gfxtype.txt then
          gfxx.font.name = f3
        end
      end
    end
  end

  function CheckFont(font)

    gfx.setfont(1,font)
    local f2,f3 = gfx.getfont()
    if f3 == font then
      return f3
    end

  end

  function SortCtlSel_Horiz()

    if ctl_select and #ctl_select > 1 then

      local ctls = strips[tracks[track_select].strip][page].controls
      nctlsel = {}
      for c = 1, #ctl_select do

        if c == 1 then
          table.insert(nctlsel, ctl_select[c])
        else
          local pos = nil
          for nc = 1, #nctlsel do
            if ctls[ctl_select[c].ctl].xsc < ctls[nctlsel[nc].ctl].xsc then
              pos = nc
              break
            end
          end
          if pos then
            --insert at pos
            table.insert(nctlsel, pos, ctl_select[c])
          else
            --insert at end
            table.insert(nctlsel, ctl_select[c])
          end
        end
      end


      ctl_select = nctlsel

    end
  end

  function SortGfxSel_Horiz()

    if gfx4_select and #gfx4_select > 1 then

      local ctls = strips[tracks[track_select].strip][page].graphics
      nctlsel = {}
      for c = 1, #gfx4_select do

        if c == 1 then
          table.insert(nctlsel, gfx4_select[c])
        else
          local pos = nil
          for nc = 1, #nctlsel do
            if ctls[gfx4_select[c]].x < ctls[nctlsel[nc]].x then
              pos = nc
              break
            end
          end
          if pos then
            --insert at pos
            table.insert(nctlsel, pos, gfx4_select[c])
          else
            --insert at end
            table.insert(nctlsel, gfx4_select[c])
          end
        end
      end

      gfx4_select = nctlsel

    end
  end

  function Distribute_Horiz()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then

        Undo_Set({'x','xsc'})

        SortCtlSel_Horiz()

        local ctls = strips[tracks[track_select].strip][page].controls
        local minx = lvar.maxdim
        local minxc = -1
        local maxx = 0
        local maxxc = -1
        for c = 1, #ctl_select do
          if ctls[ctl_select[c].ctl].x < minx then
            minx = math.floor(ctls[ctl_select[c].ctl].x + (ctls[ctl_select[c].ctl].w / 2))
            minxc = c
          end
          if ctls[ctl_select[c].ctl].x > maxx then
            maxx = math.floor(ctls[ctl_select[c].ctl].x + (ctls[ctl_select[c].ctl].w / 2))
            maxxc = c
          end
        end

        local dx = (maxx - minx) / (#ctl_select-1)
        for c = 1, #ctl_select do
          if c ~= 1 and c ~= #ctl_select then
            ctls[ctl_select[c].ctl].x = math.floor(minx+(dx*(c-1)) - ctls[ctl_select[c].ctl].w/2)
            local scale = ctls[ctl_select[c].ctl].scale
            ctls[ctl_select[c].ctl].xsc = ctls[ctl_select[c].ctl].x + math.floor(ctls[ctl_select[c].ctl].w/2
                                                                       - (ctls[ctl_select[c].ctl].w*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil

      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then

        Undo_Set({'x'})

        SortGfxSel_Horiz()

        local ctls = strips[tracks[track_select].strip][page].graphics
        local minx = lvar.maxdim
        local minxc = -1
        local maxx = 0
        local maxxc = -1
        for c = 1, #gfx4_select do
          if ctls[gfx4_select[c]].x < minx then
            minx = math.floor(ctls[gfx4_select[c]].x + (ctls[gfx4_select[c]].stretchw / 2))
            minxc = c
          end
          if ctls[gfx4_select[c]].x > maxx then
            maxx = math.floor(ctls[gfx4_select[c]].x + (ctls[gfx4_select[c]].stretchw / 2))
            maxxc = c
          end
        end

        local dx = (maxx - minx) / (#gfx4_select-1)
        for c = 1, #gfx4_select do
          if c ~= 1 and c ~= #gfx4_select then
            ctls[gfx4_select[c]].x = math.floor(minx+(dx*(c-1)) - (ctls[gfx4_select[c]].stretchw/2))
          end
        end
        --ReselectSelection()
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true

        lupd.update_gfx = true
        movefrom_sc = nil

      end


    end

  end

  function SortCtlSel_Vert()

    if ctl_select and #ctl_select > 1 then

      local ctls = strips[tracks[track_select].strip][page].controls
      nctlsel = {}
      for c = 1, #ctl_select do

        if c == 1 then
          table.insert(nctlsel, ctl_select[c])
        else
          local pos = nil
          for nc = 1, #nctlsel do
            if ctls[ctl_select[c].ctl].ysc < ctls[nctlsel[nc].ctl].ysc then
              pos = nc
              break
            end
          end
          if pos then
            --insert at pos
            table.insert(nctlsel, pos, ctl_select[c])
          else
            --insert at end
            table.insert(nctlsel, ctl_select[c])
          end
        end
      end


      ctl_select = nctlsel

    end
  end

  function SortGfxSel_Vert()

    if gfx4_select and #gfx4_select > 1 then

      local ctls = strips[tracks[track_select].strip][page].graphics
      nctlsel = {}
      for c = 1, #gfx4_select do

        if c == 1 then
          table.insert(nctlsel, gfx4_select[c])
        else
          local pos = nil
          for nc = 1, #nctlsel do
            if ctls[gfx4_select[c]].y < ctls[nctlsel[nc]].y then
              pos = nc
              break
            end
          end
          if pos then
            --insert at pos
            table.insert(nctlsel, pos, gfx4_select[c])
          else
            --insert at end
            table.insert(nctlsel, gfx4_select[c])
          end
        end
      end


      gfx4_select = nctlsel

    end
  end

  function Distribute_Vert()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then

        Undo_Set({'y','ysc'})

        SortCtlSel_Vert()

        local ctls = strips[tracks[track_select].strip][page].controls
        local miny = lvar.maxdim
        local minyc = -1
        local maxy = 0
        local maxyc = -1
        for c = 1, #ctl_select do
          if ctls[ctl_select[c].ctl].y < miny then
            miny = math.floor(ctls[ctl_select[c].ctl].y + (ctls[ctl_select[c].ctl].ctl_info.cellh / 2))
            minyc = c
          end
          if ctls[ctl_select[c].ctl].y > maxy then
            maxy = math.floor(ctls[ctl_select[c].ctl].y + (ctls[ctl_select[c].ctl].ctl_info.cellh / 2))
            maxyc = c
          end
        end

        local dy = (maxy - miny) / (#ctl_select-1)
        for c = 1, #ctl_select do
          if c ~= 1 and c ~= #ctl_select then
            ctls[ctl_select[c].ctl].y = math.floor(miny+(dy*(c-1)) - (ctls[ctl_select[c].ctl].ctl_info.cellh/2))
            local scale = ctls[ctl_select[c].ctl].scale
            ctls[ctl_select[c].ctl].ysc = ctls[ctl_select[c].ctl].y + math.floor(ctls[ctl_select[c].ctl].ctl_info.cellh/2
                                                                       - (ctls[ctl_select[c].ctl].ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil

      end

    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then

        Undo_Set({'y'})

        SortGfxSel_Vert()

        local ctls = strips[tracks[track_select].strip][page].graphics
        local miny = lvar.maxdim
        local minyc = -1
        local maxy = 0
        local maxyc = -1
        for c = 1, #gfx4_select do
          if ctls[gfx4_select[c]].y < miny then
            miny = math.floor(ctls[gfx4_select[c]].y + (ctls[gfx4_select[c]].stretchh / 2))
            minyc = c
          end
          if ctls[gfx4_select[c]].y > maxy then
            maxy = math.floor(ctls[gfx4_select[c]].y + (ctls[gfx4_select[c]].stretchh / 2))
            maxyc = c
          end
        end

        local dy = (maxy - miny) / (#gfx4_select-1)
        for c = 1, #gfx4_select do
          if c ~= 1 and c ~= #gfx4_select then
            ctls[gfx4_select[c]].y = math.floor(miny+(dy*(c-1)) - (ctls[gfx4_select[c]].stretchh/2))
          end
        end
        --ReselectSelection()
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true

        lupd.update_gfx = true
        movefrom_sc = nil

      end


    end

  end

  function Switcher_CtlsHidden(switchid, ctl_grpid)

    if switchid == nil then return false end

    local deleted
    if switchid and switchers[switchid] and switchers[switchid].deleted ~= true then
      if switchers[switchid].current ~= ctl_grpid then
        --DBG(switchers[switchid].current..'  '..ctl_grpid)
        return true, nil, switchid
      else
        if not switchers[switchid].parent or not switchers[switchid].parent.switcherid then
          return false, _, switchid
        else
          local ret, deleted, swid = Switcher_CtlsHidden(switchers[switchid].parent.switcherid, switchers[switchid].parent.grpid)
          return ret, deleted, swid or switchid
        end
      end
    else
      if switchid and switchers[switchid] and switchers[switchid].deleted == true then
        deleted = true
      end
    end
    return false, deleted, switchid
  end

  function Switcher_CtlsDeleted(switchid, ctl_grpid)
    local deleted
    if switchid and switchers[switchid] and switchers[switchid].deleted ~= true then
      if switchers[switchid].parent == nil and switchers[switchid].current ~= ctl_grpid then
        return true
      else
        if switchers[switchid].parent then
          local ret, deleted = Switcher_CtlsHidden(switchers[switchid].parent.switcherid, switchers[switchid].parent.grpid)
          return ret, deleted
        end
      end
    else
      if switchid and switchers[switchid] and switchers[switchid].deleted == true then
        deleted = true
      end
    end
    return false, deleted
  end

  function Switcher_ContentsLocInfo(switchid)

    local l,r,t,b = lvar.maxdim,0,lvar.maxdim,0
    local swl, swr, swt, swb
    local c

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local gfxx = strips[strip][page].graphics
    local gids = Switcher_GetGrpIds(switchid, gids)
    --local gids = Switchers_GetGrpIDs(switchid)
    --for i = 1, #switchers[switchid].grpids do
    --  gids[switchers[switchid].grpids[i].id] = i
    --end

    for i = 1, #ctls do

      local ctl = ctls[i]
      if gids[ctl.grpid] ~= nil then
        l = math.min(l,ctl.xsc)
        r = math.max(r,ctl.xsc+ctl.wsc)
        t = math.min(t,ctl.ysc)
        b = math.max(b,ctl.ysc+ctl.hsc)
      end

      if ctl.switcherid == switchid then
        swl = ctl.x
        swr = ctl.x+ctl.w
        swt = ctl.y
        swb = ctl.y+ctl.ctl_info.cellh
        c = i
      end
    end

    for i = 1, #gfxx do

      local ctl = gfxx[i]
      if gids[ctl.grpid] ~= nil then
        l = math.min(l,ctl.x)
        r = math.max(r,ctl.x+ctl.stretchw)
        t = math.min(t,ctl.y)
        b = math.max(b,ctl.y+ctl.stretchh)
      end

    end

    return c,l,r,t,b,swl,swr,swt,swb
  end

  function Switcher_GetTopLevelSwitcher(switchid)
    if switchid then
      while switchers[switchid] and switchers[switchid].parent and switchers[switchid].parent.switcherid ~= nil and switchers[switchid].parent.switcherid ~= switchid do
        switchid = switchers[switchid].parent.switcherid
      end
      return switchid
    end
  end

  function Switcher_GetStripIDs(switchid, grpid)

    local ids = {}
    local ididx = {}
    local ffxs = -1
    local ctls = strips[tracks[track_select].strip][page].controls
    for c = 1, #ctls do
      if ctls[c].switcher == switchid --[[and ctls[c].grpid == grpid]] and not ididx[ctls[c].id] then
        if ctls[c].id then
          ididx[ctls[c].id] = true
          ids[#ids+1] = ctls[c].id
          if ctls[c].ctlcat == ctlcats.fxparam then
            if ffxs == -1 then
              ffxs = ctls[c].fxnum
            else
              ffxs = math.min(ffsx,ctls[c].fxnum)
            end
          end
        end
      end
    end
    return ids, ffxs

  end

  function Switcher_GetGrpIds(switchid, ext_grpids, ext_swdone)

    if not ext_grpids then
      ext_grpids = {}
    end
    if not ext_swdone then
      ext_swdone = {}
    end
    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    for i = 1, #ctls do
      local ctl = ctls[i]
      if ctl.ctlcat == ctlcats.switcher and ctl.switcherid == switchid then
        ext_swdone[ctl.switcherid] = true
        --local switchid = ctl.switcherid
        local swctl = switchers[switchid]
        for g = 1, #swctl.grpids do
          local grpid = swctl.grpids[g].id
          ext_grpids[grpid] = switchid
        end
      end
    end
    for i = 1, #ctls do
      local ctl = ctls[i]
      if ctl.ctlcat == ctlcats.switcher and ctl.grpid and ext_grpids[ctl.grpid] and not ext_swdone[ctl.switcherid] then
        ext_swdone[ctl.switcherid] = true
        ext_grpids, ext_swdone = Switcher_GetGrpIds(ctl.switcherid, ext_grpids, ext_swdone)
      end
    end
    return ext_grpids, ext_swdone
  end

  function Analyser_FindByName(firsttrack)

    local nm = lvar.analyzer.mod
    local tr = GetTrack(firsttrack)
    if tr then
      local pos = reaper.TrackFX_AddByName(tr, lvar.analyzer.mod, false, 0)
      if pos ~= -1 then
        return firsttrack, pos
      end
    end

    for t = -1, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      local pos = reaper.TrackFX_AddByName(tr, lvar.analyzer.mod, false, 0)
      if pos ~= -1 then
        return t, pos
      end
    end

  end

  --[[function Analyzer_Find(show, otrn, ntrn)

    local dm_trn = otrn or lvar.dynamicmode_trn
    local tr = GetTrack(dm_trn)
    local trn, pos = Analyser_FindByName(dm_trn)
    if not pos then
      pos = reaper.TrackFX_AddByName(tr, lvar.analyzer.mod, false, 1)
    end
    if pos then
      local dm_trn = ntrn or lvar.dynamicmode_trn
      local tr = GetTrack(dm_trn)
      if trn ~= dm_trn then
        local str = GetTrack(trn)
        local spos = pos
        pos = reaper.TrackFX_GetCount(tr)
        reaper.TrackFX_CopyToTrack(str, spos, tr, pos, true)
      end
      lvar.analyzer.guid = reaper.TrackFX_GetFXGUID(tr, pos)
      --DBG(lvar.analyzer.guid)
      lvar.analyzer.pos = pos
      local anwinplug, anwin --= reaper.JS_Window_Find(lvar.analyzer.titleplug, false)
      if not lvar.analyzer.anwinplug or not reaper.ValidatePtr(lvar.analyzer.anwinplug, "HWND") then
        reaper.TrackFX_Show(tr,pos,3)
        anwinplug = reaper.JS_Window_Find(lvar.analyzer.titleplug, false)
        lvar.analyzer.anwinplug = anwinplug
        lvar.analyzer.anwinparent = reaper.JS_Window_GetParent(anwinplug)
      end
      if not lvar.analyzer.anwin or not reaper.ValidatePtr(lvar.analyzer.anwin, "HWND") then
        anwin = reaper.JS_Window_Find(lvar.analyzer.title, true)
        lvar.analyzer.anwin = anwin
      end
      if not lvar.analyzer.lbxwin or not reaper.ValidatePtr(lvar.analyzer.lbxwin, "HWND") then
        lvar.analyzer.lbxwin = reaper.JS_Window_Find('- LBX Stripper -', true)
      end

      anwin = lvar.analyzer.anwin
      anwinplug = lvar.analyzer.anwinplug
      if show then
        if anwin and lvar.analyzer.type == 1 then
          --local lbxwin = reaper.JS_Window_Find('- LBX STRIPPER -', true)
          local style = reaper.JS_Window_GetLong(anwin, 'STYLE')
          if style then
            style = style & (0xFFFFFFFF - 0x00C40000)
            reaper.JS_Window_SetLong(anwin, "STYLE", style)
          end

          local style = reaper.JS_Window_GetLong(anwinplug, 'STYLE')
          if style then
            style = style & (0xFFFFFFFF - 0x00C40000)
            reaper.JS_Window_SetLong(anwinplug, "STYLE", style)
          end
          reaper.JS_Window_SetOpacity(anwinplug, "ALPHA", 0)
          reaper.JS_Window_Show(anwinplug, 'SHOWNOACTIVATE')
          --reaper.JS_Window_SetPosition(anwinplug, 'SHOWNOACTIVATE')
          --reaper.JS_Window_SetZOrder(anwinplug, "BOTTOM")
          --reaper.JS_Window_Show(anwin, 'SHOWNOACTIVATE')
          reaper.JS_Window_SetOpacity(anwin, "ALPHA", 1)
          reaper.JS_Window_SetZOrder(anwin, 'TOPMOST')
          reaper.JS_Window_Show(anwin, 'RESTORE')
        end
      end
      return pos, lvar.analyzer.guid, tr
    end
  end]]


  function Analyzer_SetUp()

    local trackcount = reaper.GetNumTracks()
    reaper.InsertTrackAtIndex(trackcount, false)
    track = GetTrack(trackcount)
    lvar.analyzer.track = trackcount
    lvar.analyzer.trackguid = GetTrackGUID(track)
    reaper.GetSetMediaTrackInfo_String(track, "P_NAME", '__LBX_ANALYZER', true)
    reaper.SetMediaTrackInfo_Value(track,'B_MAINSEND',0)
    reaper.SetMediaTrackInfo_Value(track,'D_VOL',0)
    reaper.SetMediaTrackInfo_Value(track,'B_SHOWINTCP',0)
    reaper.SetMediaTrackInfo_Value(track,'I_PERFFLAGS',2)
    reaper.SetMediaTrackInfo_Value(track,'I_NCHAN',12)

    --DBG(reaper.GetMediaTrackInfo_Value(track,'I_PERFFLAGS'))
    for i = 1, #lvar.analyzer.mod do
      pos = reaper.TrackFX_AddByName(track, lvar.analyzer.mod[i], false, 1)
    end
    return track

  end

  function Analyzer_GetTrack()

    if lvar.analyzer.track then
      local tr = GetTrack(lvar.analyzer.track)
      if GetTrackGUID(track) == lvar.analyzer.trackguid then
        return tr
      end
    end
    return GetTrackByName('__LBX_ANALYZER')

  end

  function Analyzer_Show(idx,show)

    local opos = lvar.analyzer.pos
    local tr = Analyzer_GetTrack()
    if not tr then
      tr = Analyzer_SetUp()
    end
    --DBG(idx)
    lvar.analyzer.pos = idx-1
    local pos = idx-1

    local anwinplug, anwin
    --reaper.TrackFX_Show(tr,pos,3)
    if not lvar.analyzer.anwinplug[idx] or not reaper.ValidatePtr(lvar.analyzer.anwinplug[idx], "HWND") then
      reaper.TrackFX_Show(tr,pos,3)
      anwinplug = reaper.JS_Window_Find(lvar.analyzer.titleplug[idx], false)
      lvar.analyzer.anwinplug[idx] = anwinplug
      lvar.analyzer.anwinparent = reaper.JS_Window_GetParent(anwinplug)
      --DBG('ssss'..tostring(anwinplug))
    end
    if not lvar.analyzer.anwin or opos ~= pos or not reaper.ValidatePtr(lvar.analyzer.anwin, "HWND") then
      anwin = reaper.JS_Window_Find(lvar.analyzer.title[idx], true)
      lvar.analyzer.anwin = anwin
    end
    --DBG('aw'..tostring(anwin))
    if not lvar.analyzer.lbxwin or not reaper.ValidatePtr(lvar.analyzer.lbxwin, "HWND") then
      lvar.analyzer.lbxwin = reaper.JS_Window_Find('- LBX Stripper -', true)
    end

    anwin = lvar.analyzer.anwin
    anwinplug = lvar.analyzer.anwinplug[idx]
    if show then
      if anwin and lvar.analyzer.type == 1 then
        --local lbxwin = reaper.JS_Window_Find('- LBX STRIPPER -', true)
        Analyzer_SetStyle(anwin, anwinplug)
        Analyzer_Link(lvar.dynamicmode_trn,tr)
      end
    end
    lupd.update_trbtns = true

  end

  function Analyzer_SetStyle(hwnd, hwnd2)

    local style = reaper.JS_Window_GetLong(hwnd, 'STYLE')
    if style then
      style = style & (0xFFFFFFFF - 0x00C40000)
      reaper.JS_Window_SetLong(hwnd, "STYLE", style)
    end

    local style = reaper.JS_Window_GetLong(hwnd, 'EXSTYLE')
    if style then
      reaper.JS_Window_SetLong(hwnd, "EXSTYLE", style | 0x80000 | 0x20 )
    end

    local style = reaper.JS_Window_GetLong(hwnd2, 'STYLE')
    if style then
      style = style & (0xFFFFFFFF - 0x00C40000)
      reaper.JS_Window_SetLong(hwnd2, "STYLE", style)
    end
    reaper.JS_Window_SetOpacity(hwnd2, "ALPHA", 0)
    reaper.JS_Window_Show(hwnd2, 'SHOWNOACTIVATE')
    reaper.JS_Window_SetOpacity(hwnd, "ALPHA", 1)
    reaper.JS_Window_SetZOrder(hwnd, 'TOPMOST')
    reaper.JS_Window_Show(hwnd, 'RESTORE')

  end

  function Analyzer_Link(trn,analyzertrack,chan_in)

    for i = 0, lvar.freqcnt do
      lvar.freq[i].name = ''
    end

    chan = chan_in or 0
    local atr = analyzertrack
    if not atr then
      atr = Analyzer_GetTrack()
    end
    local tr = GetTrack(trn)
    local checktab = {}

    if tr ~= atr then

      local scnt = reaper.GetTrackNumSends(atr,-1)
      local fnd
      for i = 0, scnt-1 do
        local ttr = reaper.GetTrackSendInfo_Value(atr,-1,i,'P_SRCTRACK')
        local tch = reaper.GetTrackSendInfo_Value(atr,-1,i,'I_DSTCHAN')

        if ttr and ttr == tr then
          --unmute
          fnd = i

        elseif ttr then
          --mute others
          if tch == 0 then
            reaper.SetTrackSendInfo_Value(atr,-1,i,'B_MUTE',1)
          elseif (chan ~= 0 and tch == chan*2) then
            reaper.SetTrackSendInfo_Value(atr,-1,i,'I_DSTCHAN',0)
            reaper.SetTrackSendInfo_Value(atr,-1,i,'B_MUTE',1)
          --elseif (tch ~= 0 and tch ~= chan*2) then
            --lvar.freq[tch/2].active = true
          end
        end

      end
      if not fnd then
        --add send
        fnd = reaper.CreateTrackSend(tr, atr)
        if chan > 0 then
          reaper.SetTrackSendInfo_Value(atr,-1,fnd,'I_DSTCHAN',chan*2)
          lvar.freq[chan].active = true
          reaper.TrackFX_SetParamNormalized(atr,0,12+chan,1)
        end
      else
        reaper.SetTrackSendInfo_Value(atr,-1,fnd,'B_MUTE',0)
        if chan_in then
          reaper.SetTrackSendInfo_Value(atr,-1,fnd,'I_DSTCHAN',chan*2)
          lvar.freq[chan].active = true
          reaper.TrackFX_SetParamNormalized(atr,0,12+chan,1)
        end
      end

    end

    lupd.update_trmix = true
    lupd.update_analyzertracks = true

  end

  function DM_ShowAnalyzer(show)

    if not lvar.analyzer.script then
      reaper.MB("Please assign the script file 'LBX_AnalyzerWindow' first.","LBX Stripper",0)
      if not AnalyzerScript() then
        return
      end
    end

    --reaper.PreventUIRefresh(1)
    if show then
      lvar.analyzer.active = show
      reaper.SetExtState('LBXANALYZER','ANALYZERNAME',lvar.analyzer.titleplug[lvar.analyzer.pos+1],false)
      lvar.analyzer.anwin = reaper.JS_Window_Find(lvar.analyzer.title[1], true)
      if not lvar.analyzer.anwin or not reaper.ValidatePtr(lvar.analyzer.anwin, "HWND") then
        --start background script
        reaper.Main_OnCommand(reaper.NamedCommandLookup(lvar.analyzer.script),0)
      end
      Analyzer_Show(lvar.analyzer.pos+1,show)
      local atr = Analyzer_GetTrack()
      if atr then
        reaper.SetMediaTrackInfo_Value(atr,'B_MUTE',0)
      end
    else
      lvar.analyzer.active = show
      --reaper.SetExtState('LBXANALYZER','ANALYZERNAME','Idle',false)
      if lvar.analyzer.anwin then
        reaper.JS_Window_SetOpacity(lvar.analyzer.anwin, "ALPHA", 0)
      end
      local atr = Analyzer_GetTrack()
      if atr then
        reaper.SetMediaTrackInfo_Value(atr,'B_MUTE',1)
      end
    end
    --reaper.PreventUIRefresh(-1)

  end

  function DM_AnalyzerMenu(mx,my)

    local plugtab = lvar.analyzer.titleplugdesc
    local anacnt = #plugtab
    mstr = ''
    for i = 1, anacnt do
      local tk = ''
      if lvar.analyzer.pos == i-1 then
        tk = '!'
      end
      mstr = mstr .. tk .. plugtab[i] ..'|'
    end
    local tk = ''
    if lvar.analyzer.script then
      tk = '!'
    end
    mstr = mstr ..'|'..tk..'Assign analyzer window script'
    --[[if lvar.analyzer.pos == 0 then

      mstr = mstr .. '|Normal Slot'
      for i = 1, 4 do

        mstr = mstr .. '|' .. 'Fixed Slot ' .. i

      end

    end]]

    gfx.x = mx
    gfx.y = my
    local res = gfx.showmenu(mstr)
    if res > 0 then

      if res <= anacnt then
        lvar.analyzer.pos = res-1
        DM_ShowAnalyzer(true)
        --reaper.SetExtState('LBXANALYZER','ANALYZERNAME',lvar.analyzer.titleplug[lvar.analyzer.pos+1],false)
      --[[elseif lvar.analyzer.pos == 0 and res-anacnt <= 5 then

        local idx = res-anacnt-1
        Analyzer_Link(lvar.dynamicmode_trn,nil,idx)]]
      elseif res == anacnt+1 then
        AnalyzerScript()
      end

    end

  end

  function AnalyzerScript()
    local r, v = reaper.GetUserInputs("Please enter 'LBX_AnalyzerWindow' script command ID",1,
                  "Command ID:,extrawidth=300",lvar.analyzer.script or '')
    if r then
      if reaper.NamedCommandLookup(v) ~= 0 then
        lvar.analyzer.script = v
        return true
      else
        reaper.MB('Invalid command ID','Analyzer Script',0)
      end
    end

  end

  function ClearPage(p, force)

    local strip = Strip_INIT()
    --local strip = tracks[track_select].strip
    local lmode = strips[strip][p].lmode
    strips[strip][p] = {surface_x = 0,
                         surface_y = 0,
                         controls = {},
                         graphics = {},
                         lmode = lmode}
    if snapshots and snapshots[strip] then
      snapshots[strip][p] = {}
      snapshots[strip][p][1] = {morph_time = 0,
                                morph_sync = false,
                                morph_syncv = 15,
                                morph_scale = 1}
    end
    CleanData()
    --[[if force then
      Switchers_Clean()
      SetCtlBitmapRedraw(true)
    end]]

  end

  function DM_RefreshPage(safe, restore)
    if lvar.dynamicmode_trn then
      local dm_data, cdata
      if safe or not (mouse.ctrl and mouse.shift) then
        --if restore then
          --DM_RestoreStripData()
        --end
        
        local strip = tracks[track_select].strip
        if strip and strips[strip] then
          dm_data = DM_GatherDataForRebuild(GetTrack(lvar.dynamicmode_trn), strips[strip][page].controls, snapshots[strip][page])
        end
      else
        local strip = tracks[track_select].strip
        cdata = DM_GatherSnapCtlDataForRebuild(strips[strip][page].controls, snapshots[strip][page])
      end
      if lvar.stripstore and lvar.stripstore[lvar.dynamicmode_guid] then
        lvar.stripstore[lvar.dynamicmode_guid] = nil
      end
      DM_AddStrips(true, dm_data, cdata)
      DM_Flash_Refresh()
    end

  end

  function DM_GetSaveFN(tmp)

    local save_path=paths.projsave_path..'/'
    if settings_savedatainprojectfolder == true then
      save_path=reaper.GetProjectPath('')..'/'
    end

    local pn = GetProjectName()
    local projname = string.sub(pn,0,string.len(pn)-4) --..'_'..PROJECTID
    if projname == nil or projname == '' then
      projname = 'unnamed_project'
    end
    if save_subfolder and save_subfolder ~= '' then
      local sf = save_subfolder
      if sf == '#' then
        sf = projname
        if projname == 'unnamed_project' then
          projname = projname..'_'..PROJECTID
        end
      end
      projname = sf..'/'..projname
      reaper.RecursiveCreateDirectory(save_path..sf,1)
    end

    local setno = string.sub(lvar.STRIPSET,11)
    local setstr = ''
    if setno ~= '1' then
      setstr = '_SS'..setno
    end

    if tmp then
      fn=projname..setstr..".lbxstripper_dmdata__"
    else
      fn=projname..setstr..".lbxstripper_dmdata"
    end
    local ffn=save_path..fn
    return ffn, save_path, fn

  end

  function DM_SaveData(tmp)

    if not lvar.dm_saveenabled then return end
    if lvar.livemode == 2 then
      DM_StoreStripData()
    end

    if lvar.stripstore and next(lvar.stripstore) ~= nil then
      local SCRIPT = lvar.SCRIPT
      local ffn, save_path, fn = DM_GetSaveFN(tmp)

      local file=io.open(ffn..'.tmp',"w")
      if file == nil then
        DBG('Failed to create DM save file:\n\n'..ffn)
        return nil
      end

      reaper.SetProjExtState(0,SCRIPT,'lbxstripper_datafile_dmdata',fn)
      --DBG(fn)

      file:write('[version]'..tostring(lvar.VERSION)..'\n')

      local guids = {}
      local cnt = 1
      for a, b in pairs(lvar.stripstore) do
        guids[cnt] = a
        cnt = cnt + 1
      end
      file:write('[stripcount]'.. string.format('%i',cnt-1) ..'\n')

      --strip data
      for i = 1, cnt-1 do
        local key = string.format('%i',i)
        file:write('[guid_'..key..']'.. guids[i] ..'\n')
        --Save strip data
        local key = 's'..key..'_'
        GenStripSaveData2(lvar.stripstore[guids[i]],key,file)
      end

      --snapshot data
      for i = 1, cnt-1 do
        local key = string.format('%i',i)
        --Save snapshot data
        local key = 'snap'..key..'_'
        SaveSnapshotDataX(lvar.snapstore[guids[i]],key,file)
      end

      --fader data
      for i = 1, cnt-1 do
        local key = string.format('%i',i)
        --Save fader data
        local key = 'fader'..key..'_'
        SaveFaders(file, key, lvar.faderstore[guids[i]])
      end
      
      if switchers then
        SaveSwitchers(file)
      end

      DM_SaveTrBtns(file)
      
      file:write('[EOF]#EOF\n')
      file:close()
      
      copyfile(ffn..'.tmp',ffn)
      os.remove(ffn..'.tmp')
      
      return fn
    end
  end

  function DM_SaveTrBtns(file)

    if lvar.dm_trackbtns then
      file:write('[DMTRBTNDATA]1\n')

      file:write('[dm_trackbtns_grp_count]'..#lvar.dm_trackbtns..'\n')
      file:write('[dm_tbidx]'..lvar.dm_tbidx..'\n')
      for ii = 0, #lvar.dm_trackbtns do
        if lvar.dm_trackbtns[ii] then
          file:write('[dm_trackbtns_name_'..string.format('%i',ii)..']'..(lvar.dm_trackbtns[ii].name or '')..'\n')
          if #lvar.dm_trackbtns[ii] > 0 then
            file:write('[dm_trackbtns_count_'..string.format('%i',ii)..']'..#lvar.dm_trackbtns[ii]..'\n')
            for i = 1, #lvar.dm_trackbtns[ii] do
              local key = string.format('%i',ii)..'_'..string.format('%i',i)
              file:write('[dm_trackbtns_guid_'..key..']'..(lvar.dm_trackbtns[ii][i].guid or '')..'\n')
              file:write('[dm_trackbtns_trn_'..key..']'..lvar.dm_trackbtns[ii][i].trn..'\n')
            end
          end
        end
      end
    end
    if lvar.dm_backtrack then
      file:write('[dm_backtrack_guid]'..(lvar.dm_backtrack.guid or '')..'\n')
      file:write('[dm_backtrack_trn]'..lvar.dm_backtrack.trn..'\n')
      file:write('[dm_backtrack_page]'..lvar.dm_backtrack.page..'\n')
    end

  end

  function DM_LoadTrBtns(data)

    if tonumber(data['DMTRBTNDATA']) == 1 then

      lvar.dm_tbidx = tonumber(data['dm_tbidx'])
      local trb_gcnt = tonumber(data['dm_trackbtns_grp_count']) or 1
      lvar.dm_trackbtns = {}
      for ii = 0, trb_gcnt do
        local key = string.format('%i',ii)
        local trb_cnt = tonumber(data['dm_trackbtns_count_'..key]) or 0
        lvar.dm_trackbtns[ii] = {}
        lvar.dm_trackbtns[ii].name = zn(data['dm_trackbtns_name_'..key])
        if trb_cnt > 0 then
          for i = 1, trb_cnt do
            local key = string.format('%i',ii)..'_'..string.format('%i',i)
            local guid = zn(data['dm_trackbtns_guid_'..key])
            local trn = data['dm_trackbtns_trn_'..key]
            if tonumber(trn) then
              lvar.dm_trackbtns[ii][i] = {}
              lvar.dm_trackbtns[ii][i].guid = guid
              lvar.dm_trackbtns[ii][i].trn = tonumber(trn)
            end
          end
        else
          lvar.dm_trackbtns[ii] = {}
        end
      end

      lvar.dm_backtrack = nil
      local guid = zn(data['dm_backtrack_guid'])
      if guid then
        lvar.dm_backtrack = {}
        lvar.dm_backtrack.guid = guid
        lvar.dm_backtrack.trn = tonumber(data['dm_backtrack_trn'])
        lvar.dm_backtrack.page = tonumber(data['dm_backtrack_page'])
      end

    else

      local SCRIPT = lvar.SCRIPT
      local ret, trb_idx = reaper.GetProjExtState(0,SCRIPT,'dm_tbidx')
      lvar.dm_tbidx = tonumber(trb_idx) or 1
      local ret, trb_gcnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_grp_count')
      trb_gcnt = tonumber(trb_gcnt)
      local legacy
      if not trb_gcnt then
        trb_gcnt = 1
        legacy = true
      end
      lvar.dm_trackbtns = {}
      for ii = 1, trb_gcnt do
        local ret, trb_cnt
        if not legacy then
          ret, trb_cnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_count_'..string.format('%i',ii))
        else
          ret, trb_cnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_count') --backwards compat
        end
        trb_cnt = tonumber(trb_cnt) or 0
        lvar.dm_trackbtns[ii] = {}
        if not legacy then
          local ret, name = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_name_'..string.format('%i',ii))
          if ret and name ~= '' then
            lvar.dm_trackbtns[ii].name = name
          end
        end
        if trb_cnt > 0 then
          for i = 1, trb_cnt do
            local key = string.format('%i',ii)..'_'..string.format('%i',i)
            if legacy then
              key = string.format('%i',i)
            end
            local ret, guid = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_guid_'..key)
            local ret, trn = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_trn_'..key)
            if tonumber(trn) then
              lvar.dm_trackbtns[ii][i] = {}
              lvar.dm_trackbtns[ii][i].guid = guid
              lvar.dm_trackbtns[ii][i].trn = tonumber(trn)
            end
          end
        else
          lvar.dm_trackbtns[ii] = {}
        end
      end

      lvar.dm_backtrack = nil
      local guid = GPES('dm_backtrack_guid',true)
      if guid then
        lvar.dm_backtrack = {}
        lvar.dm_backtrack.guid = guid
        lvar.dm_backtrack.trn = tonumber(GPES('dm_backtrack_trn',true))
        lvar.dm_backtrack.page = tonumber(GPES('dm_backtrack_page',true))
      end
    end

  end

  function DM_LoadData()

    if not lvar.dm_saveenabled then return end

    local data = {}
    local match = string.match

    local load_path
    local fn = GPES('lbxstripper_datafile_dmdata', true)

    LDF = fn

    if fn == nil then return end

    if settings_savedatainprojectfolder == true then
      load_path=reaper.GetProjectPath('')..'/'
      if reaper.file_exists(load_path..fn) ~= true then
        load_path=paths.projsave_path
      end
    else
      load_path=paths.projsave_path
      if reaper.file_exists(load_path..fn) ~= true then
        load_path=reaper.GetProjectPath('')..'/'
      end
    end

    local ffn=load_path..fn

    DBGOut('LoadData: ffn: '..tostring(ffn))
    if reaper.file_exists(ffn) ~= true then

      if lvar.striploadoverride_active ~= true then
        nfn = FindDataFile(ffn)
        if nfn ~= nil and reaper.file_exists(nfn) == true then
          ffn = nfn
        else
          if nfn then
            ffn = nfn
          end
          DBG('Missing file: '..ffn)
          return 0
        end
      else
        return 0
      end
    end

    local ctr = 0
    datafile = ffn
    local flines = io.lines
    for line in flines(ffn) do
      ctr = ctr + 1
      if ctr % 4000 == 0 then
        GUI_DrawMsgX(obj, gui, 'Reading data file...  (line: '..ctr..')', nil, nil, true)
      end
      local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
      if idx then
        val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
        data[idx] = val
      end
    end

    DBGOut('LoadData: Read lines: '..tostring(ctr))

    local v = tonumber(zn(data['version']))
    local cont = true
    if v and tonumber(v) >= 0.96 then
      if data['EOF'] ~= '#EOF' then
        id = tostring(math.floor(math.random() * 0xFFFFFFFF))
        local rfn = string.match(ffn,'(.+).lbxstripper')..'_'..id..'.lbxincomplete'
        local r = reaper.MB('It appears the DM data file is incomplete:  Continue loading?\n\nA backup of this file will be made to: '..rfn,'Load Data',4)
        if r == 7 then
          cont = false
        end
        copyfile(ffn, rfn)
      end
    elseif v == nil then
      local rfn = string.match(ffn,'(.+).lbxstripper')..'_'..id..'.lbxincomplete'
      local r = reaper.MB('It appears the DM data file is incomplete:  Continue loading?\n\nA backup of this file will be made to: '..rfn,'Load Data',4)
      if r == 7 then
        cont = false
      end
      copyfile(ffn, rfn)
      
    end

    --[[if cont == false then
      reaper.MB('You may wish to locate an alternative or backup data file for this project - use Main Menu->Script Data to search for an alternative data file','Load Aborted',0)
    end]]

    DM_LoadTrBtns(data)

    lvar.stripstore = {}
    lvar.snapstore = {}
    lvar.faderstore = {}

    if cont == true then
      local scnt
      scnt = tonumber(data['stripcount'])
      DBGOut('LoadData: strip count: '..tostring(scnt))

      local guids = {}
      for i = 1, scnt do
        local key = 'guid_'..string.format('%i',i)
        local guid = data[key]
        if lvar.trackguids[guid] then
          guids[i] = guid

          local key = 's'..string.format('%i',i)..'_'
          --DBG('fxcnt '..tostring(zn(data[key..'fxcnt'])))
          --DBG('fxstr '..tostring(zn(data[key..'fxstr'])))
          --DBG(key)

          lvar.stripstore[guid] = LoadStripDataX(key,data)
          --DBG(guid)
          local key = 'snap'..string.format('%i',i)..'_'
          lvar.snapstore[guid] = LoadSnapDataX(key,data)
          
          local key = 'fader'..string.format('%i',i)..'_'
          lvar.faderstore[guid] = LoadFaders(data,key,true)
          --DBG(lvar.snapstore[guid].morph_time)
        end

      end

      LoadSwitchers(data)
      lvar.dm_switchload = true

      --Switchers_Clean()

      if lvar.livemode == 2 then
        lvar.dm_init = true
      end

    end

  end

  --[[function DM_CreateGUIDTRNIdx()
    lvar.dm_trns = {}
    for a, b in pairs(lvar.stripstore) do
      lvar.dm_trns[
    end
  end]]

  function DM_RestoreStripData()

    local track = reaper.GetSelectedTrack2(0,0,true)
    if track then
      local trn
      if lvar.dynamicmode_trn == nil then
        trn = math.max(reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1,-1)
        lvar.dynamicmode_trn = trn
        lvar.dynamicmode_guid = GetTrackGUID(track)
      end
    end
    
    if lvar.dm_fastmode and lvar.stripstore and lvar.stripstore[lvar.dynamicmode_guid] then
    
      fmode = true
      ClearPage(page, force)
      local strip = tracks[track_select].strip
      strips[strip][page] = lvar.stripstore[lvar.dynamicmode_guid]

      snapshots[strip][page] = lvar.snapstore[lvar.dynamicmode_guid]
      surface_offset.mixx = strips[strip][page].mixx
      surface_offset.mixy = strips[strip][page].mixy
  
      StoreSnapshotControlIdxs(strip,page)
      
    end
  end

  function DM_StoreStripData(force, ts, pg, omixx, omixy)
    --DBG('storing ' .. tostring(lvar.dm_fastmode)..'  '..tostring(lvar.dynamicmode_guid)..'  '..tostring(force))
    if not ts then
      ts = track_select
      pg = page
    end
    if not omixx then
      omixx = surface_offset.mixx
      omixy = surface_offset.mixy
    end
    if lvar.dm_fastmode and lvar.dynamicmode_guid and not force then
      if not lvar.stripstore then
        lvar.stripstore = {}
        lvar.snapstore = {}
      end
      local strip = tracks[ts].strip
      if strips and strips[strip] then
        strips[strip][pg].mixx = omixx
        strips[strip][pg].mixy = omixy
        strips[strip][pg].pop_xoff = lvar.pop_xoff or 0
        strips[strip][pg].pop_yoff = lvar.pop_yoff or 0
        
        strips[strip][pg].trn = lvar.dynamicmode_trn

        --DBG(strips[strip][page].mixy)
        --lvar.stripstore[lvar.dynamicmode_guid] = table.deepcopy(strips[strip][pg])
        lvar.stripstore[lvar.dynamicmode_guid] = strips[strip][pg]
        if snapshots[strip] and snapshots[strip][pg][sstype_select] then
          snapshots[strip][pg][sstype_select].selected = ss_select
        end
        --lvar.snapstore[lvar.dynamicmode_guid] = table.deepcopy(snapshots[strip][pg])
        lvar.snapstore[lvar.dynamicmode_guid] = snapshots[strip][pg]
        if not lvar.faderstore then
          lvar.faderstore = {}
        end
        lvar.faderstore[lvar.dynamicmode_guid] = table.deepcopy(faders)

      end
    end

  end

  local function DM_GetCtlData(ctl, idx)

    local ctldata 
    if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.gr_meter then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.trackparam then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.tracksend then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.param_info.paramdestguid),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.snapshot then
      local t = {tostring(ctl.ctlcat),tostring(ctl.param),tostring(ctl.param_info.paramname)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.fxoffline then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.midictl then
      if ctl.midiout then
        local t = {tostring(ctl.ctlcat),tostring(ctl.midiout.msgtype),tostring(ctl.midiout.mchan),tostring(ctl.midiout.msg3),tostring(ctl.midiout.osc), tostring(ctl.midiout.output)}
        ctldata = {idx = idx,
                   id = ctl.c_id,
                   key = table.concat(t)}
      end
    elseif ctl.ctlcat == ctlcats.takeswitcher then

    elseif ctl.ctlcat == ctlcats.rs5k then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.fxmulti then
      local t = {tostring(ctl.ctlcat),tostring(ctl.fxguid),tostring(ctl.param),tostring(ctl.trackguid)}
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t)}

    elseif ctl.ctlcat == ctlcats.macro then
      local macro = ctl.macroctl
      local strip = tracks[track_select].strip
      local ctls = strips[strip][page].controls
      local t = {}
      t[1] = tostring(ctl.ctlcat)
      for m = 1, #macro do
        t[1+(m-1)*3+1] = tostring(ctls[macro[m].ctl].fxguid)
        t[1+(m-1)*3+2] = tostring(ctls[macro[m].ctl].param)
        t[1+(m-1)*3+3] = tostring(ctls[macro[m].ctl].trackguid)
      end
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t),
                 val = ctl.val}

    elseif ctl.ctlcat == ctlcats.rcm_switch then
      local t = {}
      t[1] = tostring(ctl.ctlcat)
      t[2] = tostring(ctl.fxguid)
      for m = 1, #ctl.rcmdata do
        t[2+(m-1)*3+1] = tostring(ctl.rcmdata[m].msb)
        t[2+(m-1)*3+2] = tostring(ctl.rcmdata[m].lsb)
        t[2+(m-1)*3+3] = tostring(ctl.rcmdata[m].prog)
      end
      ctldata = {idx = idx,
                 id = ctl.c_id,
                 key = table.concat(t),
                 val = ctl.val}
    end

    return ctldata

  end
   function DM_GatherSnapCtlDataForRebuild(ctls, snaps)

    local ctldata = {}
    local ctldataidx = {}

    if ctls then
      for c = 1, #ctls do
        local ctl = ctls[c]
        local cd = DM_GetCtlData(ctl, c)
        if cd then
          local idx = #ctldata+1
          ctldata[idx] = cd
          ctldataidx[ctl.c_id] = cd.key
        end
      end
    end

    local cdata = {}
    cdata.ctldata = ctldata
    cdata.ctldataidx = ctldataidx
    cdata.pagesnaps = snaps[1]
    cdata.subsnaps = snaps

    if #ctldata > 0 then
      return cdata
    end

  end

  function DM_GatherDataForRebuild(track, ctls, snaps)

    --if true then return end

    --ensure all switcher fxguids (plugins) are in correct order in track fx list to prevent moving incorrect plugins.
    --only have to move each switchers plugins adjacent to eachother - not entire track list?
    --so single plugin switchers need not change at all
    --for multi ones - find first plugin (fxguid) - move others in sequence after it.

    local fxg_stripid = {}
    
    local swids = {}
    local swidsidx = {}

    local ctldata = {}
    local ctldataidx = {}

    local padx, pady

    if ctls then
      for c = 1, #ctls do
        local ctl = ctls[c]
        if ctl.ctlcat == ctlcats.switcher and ctl.switcherid then
          local sw = switchers[ctl.switcherid]
          if sw and sw.switchmode == 1 and sw.extendmode == true then
            local nswid = #swids+1
            swids[nswid] = {id = ctl.switcherid}
            swidsidx[ctl.switcherid] = nswid
            padx = switchers[ctl.switcherid].padx
            pady = switchers[ctl.switcherid].pady
          end
        end
        local cd = DM_GetCtlData(ctl, c)
        if cd then
          local idx = #ctldata+1
          ctldata[idx] = cd
          ctldataidx[ctl.c_id] = cd.key
          ctldataidx[cd.key] = idx
        end
        if not fxg_stripid[ctl.fxguid] and 
           ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.fxoffline or ctl.ctlcat == ctlcats.gr_meter then
          fxg_stripid[ctl.fxguid] = ctl.id
        end
      end
    end

    if #swids == 0 then return end

    Switchers_SortFXChain2(switchers[swids[1].id].extendid, track, true)

    local fxguids = {}
    --DBG('#swids '..#swids)
    for s = 1, #swids do
      if switchers[swids[s].id] then
        swids[s].fxguids = switchers[swids[s].id].fxguids
        for a, b in pairs(switchers[swids[s].id].grpids) do

          if swids[s].fxguids and #swids[s].fxguids == 1 then
            --[[local sss = PlugDef_GetFromFXGUID(track, swids[s].fxguids[1])
            if sss then
              swids[s].stripfn = paths.strips_path..sss
            else]]
              swids[s].stripfn = b.stripfn
            --end
          else
            --[[local sss = string.match(b.stripfn,'.+[\\/]strips[\\/](.+).strip$')
            if sss then
              sss = string.match(sss,'.-[\\/](.*)')
              if sss and plugdefstrips_idx[sss] then
                local idx = plugdefstrips_idx[sss]
                swids[s].stripfn = paths.strips_path..plugdefstrips[idx].stripfol..'/'..plugdefstrips[idx].stripfile
              else
                swids[s].stripfn = b.stripfn
              end
            else]]
              swids[s].stripfn = b.stripfn
            --end
          end
        end
        if not string.match(swids[s].stripfn or '','dynamic_placeholder.strip$') and swids[s].fxguids then
          for f = 1, #swids[s].fxguids do

            fxguids[swids[s].fxguids[f]] = {id = s}

          end
        end
      end
    end

    local fxinfo = {}
    local fxinfo_guids = {}
    local fcnt = reaper.TrackFX_GetCount(track)
    for f = 0, fcnt-1 do
      local guid = reaper.TrackFX_GetFXGUID(track,f)
      local ret, fxname = reaper.TrackFX_GetFXName(track, f, '')
      if fxguids[guid] then
        --existing
        fxinfo[f] = {oswid = swids[fxguids[guid].id].id,
                     swid = fxguids[guid].id,
                     guid = guid,
                     fxname = fxname,
                     stripid = fxg_stripid[guid]}
        fxinfo_guids[guid] = f
      else
        --new
        fxinfo[f] = {oswid = -1,
                     swid = -1,
                     guid = guid,
                     fxname = fxname,
                     stripid = fxg_stripid[guid]}
        fxinfo_guids[guid] = f
      end
    end
    
    local snapsubsel = {}
    for s = 2, #snaps do
      if snaps[s] and snaps[s].ctls[1] and ctls[snaps[s].ctls[1].ctl] then
        local stripid = ctls[snaps[s].ctls[1].ctl].id
        snaps[s].stripid = stripid
        if snaps[s].subid then
          snapsubsel[stripid..snaps[s].subid] = snaps[s].selected
        end
      end
    end

    local newswitcherdata = {}
    newswitcherdata.ctldata = ctldata
    newswitcherdata.ctldataidx = ctldataidx
    newswitcherdata.pagesnaps = snaps[1]
    newswitcherdata.snaps = snaps
    newswitcherdata.snapsubsel = snapsubsel
    newswitcherdata.padx = padx
    newswitcherdata.pady = pady
    newswitcherdata.showpop = lvar.showpop
    newswitcherdata.mixx = surface_offset.mixx
    newswitcherdata.mixy = surface_offset.mixy

    local strip = tracks[track_select].strip
    if strip then
      newswitcherdata.pop = strips[strip][page].pop
      newswitcherdata.popidx = strips[strip][page].popidx
    end

    local newswitcherdata_idx = {}
    local tfxi = GetTrackFXInfo(nil, lvar.dynamicmode_trn)

    if fcnt > 0 then
      for f = 0, #fxinfo do

        if fxinfo[f].swid == -1 then
          local nsd = #newswitcherdata+1
          local ret, fxname = reaper.TrackFX_GetFXName(track, f, '')
          fxname = string.lower(TrimStr(CropFXName(fxname)))
          local fxident = string.lower(tfxi[f].fxfn)
          local stripfn = ''
          local sfol, sfil
          if fxident and plugdefstrips_idx and (plugdefstrips_idx[fxname] or plugdefstrips_idx[fxident]) then
            local idx = plugdefstrips_idx[fxname] or plugdefstrips_idx[fxident]
            if idx and plugdefstrips[idx] then
              sfol = plugdefstrips[idx].stripfol
              sfil = plugdefstrips[idx].stripfile
              stripfn = paths.strips_path..sfol..'/'..sfil
            end
          end
          newswitcherdata[nsd] = {fxn = f, fxident = fxident,
                                  fxguids = {fxinfo[f].guid},
                                  fxns = {},
                                  stripfn = stripfn,
                                  sfol = sfol, sfil = sfil}
          newswitcherdata[nsd].fxns[fxinfo[f].guid] = {fxn = f,
                                                       fxname = fxinfo[f].fxname}
        else
          if newswitcherdata_idx[fxinfo[f].swid] then
            --already added to list
            --local idx = newswitcherdata_idx[fxinfo[f].swid]
            --newswitcherdata[nsd].fxns[#newswitcherdata[nsd].fxns+1] = guid
          else
            local nsd = #newswitcherdata+1
            local sfol, sfil
            --DBG(swids[fxinfo[f].swid].stripfn)
            if swids[fxinfo[f].swid].stripfn then
              sfol = string.match(swids[fxinfo[f].swid].stripfn, '(.+)%/.*$')
              sfol = string.match(sfol, '.+%/(.*)$')
              sfil = string.match(swids[fxinfo[f].swid].stripfn, '.+%/(.*)$')
            end
            newswitcherdata[nsd] = {fxn = f,
                                    fxguids = swids[fxinfo[f].swid].fxguids,
                                    stripfn = swids[fxinfo[f].swid].stripfn,
                                    stripid = fxinfo[f].stripid,
                                    sfol = sfol, sfil = sfil,
                                    swid = fxinfo[f].oswid,
                                    popx = switchers[fxinfo[f].oswid].popx,
                                    popy = switchers[fxinfo[f].oswid].popy}

            newswitcherdata_idx[fxinfo[f].swid] = nsd
            local fxns = {}
            for g = 1, #newswitcherdata[nsd].fxguids do
              local fxn = fxinfo_guids[newswitcherdata[nsd].fxguids[g]]
              if fxn then
                fxns[newswitcherdata[nsd].fxguids[g]] = {fxn = fxn,
                                                         fxname = fxinfo[fxn].fxname}
              end
            end
            newswitcherdata[nsd].fxns = fxns
          end
        end

      end
    end

    --[[for i = 1, #newswitcherdata do
      DBG('Switcher Loc: '..i.. ' first fx = '..newswitcherdata[i].fxn..'  '..newswitcherdata[i].stripfn)
    end]]
    if #newswitcherdata > 0 then
      return newswitcherdata
    else
      return nil
    end
  end

  function DM_GetCtlTranslateTable(dm_data)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls

    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    local nctldata = {}
    local nctldataidx = {}

    for c = 1, #ctls do
      local ctl = ctls[c]
      local cd = DM_GetCtlData(ctl, c)
      if cd then
        local idx = #nctldata+1
        nctldata[idx] = cd
        nctldataidx[cd.key] = idx
        nctldataidx[ctl.c_id] = idx
      end
    end

    return nctldata, nctldataidx
  end

  function DM_RebuildSnapData(dm_data)
    if dm_data.snapsubsel then
      local strip = tracks[track_select].strip
      local snaps = snapshots[strip][page]
      for s = 2, #snapshots[strip][page] do
        if snapshots[strip][page][s].stripid and snapshots[strip][page][s].subid then
          local key = snapshots[strip][page][s].stripid..snapshots[strip][page][s].subid
          if dm_data.snapsubsel[key] then
            snapshots[strip][page][s].selected = dm_data.snapsubsel[key]
          end
        end
      end
    end
  end

  function DM_RebuildPageSnaps(dm_data, nctldata, nctldataidx)

    --Get new control id/key
    local strip = tracks[track_select].strip
    local snaps = dm_data.pagesnaps
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    if #snaps == 0 then return end

    --Update page snapshots
    for ss = 1, #snaps do
      local ndata = {}
      local nidx = 1
      for d = 1, #snaps[ss].data do
        local data = snaps[ss].data[d]
        if data then
          local key = ctldataidx[data.c_id]
          if key and nctldataidx[key] then
            local nd = nctldata[nctldataidx[key]]
            ndata[nidx] = {c_id = nd.id,
                           ctl = nd.idx,
                           val = data.val,
                           dval = data.dval}
            nidx = nidx + 1
          end
        end
      end
      snaps[ss].data = ndata
    end

    Snapshots_INIT()
    snapshots[strip][page][1] = snaps

  end

  --[[function DM_RebuildSubSnaps(dm_data, nctldata, nctldataidx)

    --update ctls for each subset
    --identify subset to replace

    --Get new control id/key
    local strip = tracks[track_select].strip
    local snaps = dm_data.subsnaps
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    if #snaps == 0 then return end

    --Update page snapshots
    for ss = 1, #snaps do
      local ndata = {}
      local nidx = 1
      for d = 1, #snaps[ss].data do
        local data = snaps[ss].data[d]
        if data then
          local key = ctldataidx[data.c_id]
          if key and nctldataidx[key] then
            local nd = nctldata[nctldataidx[key] ]
            ndata[nidx] = {c_id = nd.id,
                           ctl = nd.idx,
                           val = data.val,
                           dval = data.dval}
            nidx = nidx + 1
          end
        end
      end
      snaps[ss].data = ndata
    end

    Snapshots_INIT()
    snapshots[strip][page][1] = snaps

  end]]

  function DM_RebuildModulators(dm_data, nctldata, nctldataidx)

    local strip = tracks[track_select].strip
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    local mods = modulators
    for m = 1, #mods do
      local targets = mods[m].targets
      if targets then
        for t = 1, #targets do

          if targets[t].dm_guid == lvar.dynamicmode_guid then
            local key = ctldataidx[targets[t].c_id]
            if key and nctldataidx[key] then
              local nd = nctldata[nctldataidx[key]]
              targets[t].c_id = nd.id
              targets[t].ctl = nd.idx
            end

          end

        end
      end
    end

  end

  function DM_RebuildFaders(dm_data, nctldata, nctldataidx)

    local strip = tracks[track_select].strip
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    local fads = faders
    for f = 1, #fads do

      if fads[f].dm_guid == lvar.dynamicmode_guid then
        local key = ctldataidx[fads[f].c_id]
        if key and nctldataidx[key] then
          local nd = nctldata[nctldataidx[key]]
          fads[f].c_id = nd.id
          fads[f].ctl = nd.idx
        end

      end

    end

  end

  function DM_RebuildPop(dm_data)

    local strip = tracks[track_select].strip
    local pop = dm_data.pop
    local popidx = dm_data.popidx

    if pop then

      local swids = {}
      for d = 1, #dm_data do
        if dm_data[d].swid then
          swids[dm_data[d].swid] = dm_data[d].nswid
          if switchers[dm_data[d].nswid] then
            switchers[dm_data[d].nswid].popx = dm_data[d].popx
            switchers[dm_data[d].nswid].popy = dm_data[d].popy
          end

        end
      end

      local npop = {}
      local npopidx = {}
      local idx = 1
      for p = 1, #pop do
        if swids[pop[p].swid] then
          npop[idx] = pop[p]
          npop[idx].swid = swids[pop[p].swid]
          npopidx[npop[idx].swid] = idx
          idx = idx + 1
        end
      end

      if #npop > 0 then
        strips[strip][page].pop = npop
        strips[strip][page].popidx = npopidx
      end
    end

    strips[strip][page].showpop = dm_data.showpop

  end

  function DM_RebuildMacro(dm_data, nctldata, nctldataidx)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    for c = 1, #ctls do

      if ctls[c].ctlcat == ctlcats.macro then
        local nd = nctldata[nctldataidx[ctls[c].c_id]]
        if nd then
          local key = nd.key
          if key and ctldataidx[key] then
            local cd = ctldata[ctldataidx[key]]
            if nd and cd.val then
              ctls[c].val = cd.val
            end
          end
        end
      end

    end

  end

  function DM_RebuildRCM(dm_data, nctldata, nctldataidx)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local ctldata = dm_data.ctldata
    local ctldataidx = dm_data.ctldataidx

    for c = 1, #ctls do

      if ctls[c].ctlcat == ctlcats.rcm_switch then
        local nd = nctldata[nctldataidx[ctls[c].c_id]]
        if nd then
          local key = nd.key
          if key and ctldataidx[key] then
            local cd = ctldata[ctldataidx[key]]
            if nd and cd.val then
              ctls[c].val = cd.val
            end
          end
        end
      end

    end

  end

  function DM_AddStrips(force, dm_data, cdata)

    DM_StoreStripData(force)
    lvar.prsr = nil
    local sfade
    
    local track = reaper.GetSelectedTrack2(0,0,true)
    if track then
      lvar.checkdatatables_active = false

      local switchid
      local trn
      if lvar.dynamicmode_trn == nil or reaper.CountSelectedTracks2(0, true) < 2 then
        trn = math.max(reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1,-1)
        if trn ~= lvar.dynamicmode_trn then
          if lvar.analyzer.active then
            Analyzer_Link(trn)
          end
        end
        if trn~=lvar.dynamicmode_trn then
          sfade = true
        end
        lvar.dynamicmode_trn = trn
        lvar.dynamicmode_guid = GetTrackGUID(track)
        lvar.dm_trname = reaper.GetTrackState(track)
  
        lvar.trmix_sndpnl_offs = 0
  
        if trn == -1 then
          lvar.dm_trname = 'Master track'
        else
          if lvar.dm_trname == '' then
            lvar.dm_trname = 'Untitled track'
          end
          lvar.dm_trname = 'Track '..string.format('%i',trn+1)..' - '..lvar.dm_trname
        end
      else
        --track = GetTrack(lvar.dynamicmode_trn)
        lvar.dm_refresh = nil
        return
      end
      --DBG('Refresh: '..tostring(dm_data))
      local fmode
      if lvar.dm_fastmode and lvar.stripstore and lvar.stripstore[lvar.dynamicmode_guid] then

        fmode = true
        ClearPage(page, force)

        local strip = tracks[track_select].strip
        strips[strip][page] = lvar.stripstore[lvar.dynamicmode_guid]

        snapshots[strip][page] = lvar.snapstore[lvar.dynamicmode_guid]
        surface_offset.mixx = strips[strip][page].mixx
        surface_offset.mixy = strips[strip][page].mixy
        lvar.pop_xoff = strips[strip][page].pop_xoff or 0
        lvar.pop_yoff = strips[strip][page].pop_yoff or 0

        if snapshots[strip][page][sstype_select] then
          ss_select = snapshots[strip][page][sstype_select].selected
        else
          sstype_select = 1
          if snapshots[strip][page][sstype_select] then
            ss_select = snapshots[strip][page][sstype_select].selected
          end
        end

        lvar.showpop = strips[strip][page].showpop or false

        --DBG(surface_offset.mixy)
        --DBG('loading: '..lvar.dynamicmode_guid)
        --DBG(#strips[strip][page].controls)
        SetCtlBitmapRedraw(true)

        if (lvar.mixmodedir == 1 and surface_offset.mixx == nil) or (lvar.mixmodedir == 0 and surface_offset.mixy == nil) then
          local mmlen = MixMode_GetLength()
          if lvar.mixmodedir == 0 then
            surface_offset.mixy = math.min(math.floor((0-obj.sections[10].h/2)+(mmlen/2)),-40)
          else
            surface_offset.mixx = math.min(math.floor((0-obj.sections[10].w/2)+(mmlen/2)),-40)
          end
        end
        
        --SetSurfaceFade()

      else

        ClearPage(page, force)

        if dm_data then

          for d = 1, #dm_data do

            --DBG(dm_data[d].stripfn)
            if dm_data[d].stripfn == '' or string.match(dm_data[d].stripfn,'.*dynamic_placeholder.strip$') then

              --insert dynamic placeholder
              local sfn = paths.resource_path..'dynamic_placeholder.strip'
              loadstrip = LoadStripFN(nil, sfn)

              if loadstrip then
                local switchid2
                local strip = tracks[track_select].strip
                local ctls = strips[strip][page].controls
                local ccnt = #ctls
                for i = 1, ccnt do
                  if ctls[i].ctlcat == ctlcats.switcher then
                    local swid = ctls[i].switcherid
                    if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                      switchid = swid
                      break
                    end
                  end
                end

                local extid
                local maxpos = 0
                if switchid then
                  extid = switchers[switchid].extendid
                  maxpos = Switcher_Ext_GetMaxPos(extid)

                  for s = 1, #switchers do
                    if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                       switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                      switchid2 = s
                      break
                    end
                  end

                  if switchid2 --[[and #switchers[switchid2].grpids > 0]] then
                    maxpos = maxpos + 1
                  end
                end
                local c = Switchers_Ext_Insert(switchid, maxpos)
                dm_data[d].nswid = ctls[c].switcherid

                switchers[dm_data[d].nswid].padx = dm_data.padx
                switchers[dm_data[d].nswid].pady = dm_data.pady

                local _, fxname = reaper.TrackFX_GetFXName(track, dm_data[d].fxn, '')
                fxname = TrimStr(CropFXName(fxname))
                local fxident = dm_data[d].fxident

                --DBG(dm_data[d].fxn .. '   '..(fxident or 'nil'))
                local swok, swid = Switcher_AddStrip(nil, c, loadstrip, nil, trn, dm_data[d].fxn+1, fxname or fxident, nil, dm_data[d])

              end

            else

              local sfol = dm_data[d].sfol
              local sfil = dm_data[d].sfil

              loadstrip = LoadStrip(nil, sfol, sfil, true)

              if loadstrip then

                lupd.update_gfx = true

                local switchid2
                local strip = tracks[track_select].strip
                local ctls = strips[strip][page].controls
                for i = 1, #ctls do
                  if ctls[i].ctlcat == ctlcats.switcher then
                    local swid = ctls[i].switcherid
                    if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                      switchid = swid
                      break
                    end
                  end
                end

                local extid
                local maxpos = 0
                if switchid then
                  extid = switchers[switchid].extendid
                  maxpos = Switcher_Ext_GetMaxPos(extid)

                  for s = 1, #switchers do
                    if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                       switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                      switchid2 = s
                      break
                    end
                  end
                  if switchid2 --[[and #switchers[switchid2].grpids > 0]] then
                    maxpos = maxpos + 1
                  end
                end

                local c = Switchers_Ext_Insert(switchid, maxpos)
                dm_data[d].nswid = ctls[c].switcherid

                switchers[dm_data[d].nswid].padx = dm_data.padx
                switchers[dm_data[d].nswid].pady = dm_data.pady

                --DBG('B')
                --DBG(dm_data[d].fxn .. '   '..(fxident or 'nil')..'  '..dm_data[d].stripfn)

                local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, dm_data[d].fxn+1, nil, nil, dm_data[d], nil, dm_data[d].stripid)

                --if swok ~= true then
                --  Switcher_DeleteExt(ctls[c].switcherid)
                --end

                loadstrip = nil

              end
            end

          end

          local nctldata, nctldataidx = DM_GetCtlTranslateTable(dm_data)
          DM_RebuildRCM(dm_data, nctldata, nctldataidx)
          DM_RebuildMacro(dm_data, nctldata, nctldataidx)
          DM_RebuildPageSnaps(dm_data, nctldata, nctldataidx)
          DM_RebuildModulators(dm_data, nctldata, nctldataidx)
          DM_RebuildFaders(dm_data, nctldata, nctldataidx)
          DM_RebuildPop(dm_data)

          --DM_RebuildSnapData(dm_data)

          surface_offset.mixx = dm_data.mixx
          surface_offset.mixy = dm_data.mixy

        else

          local tfxi = GetTrackFXInfo(nil, trn)
          --local fxchunks = GetFXChunks(trn)
          for fx = 1, reaper.TrackFX_GetCount(track) do
            local ret, fxname = reaper.TrackFX_GetFXName(track, fx-1, '')
            fxname = string.lower(string.match(CropFXName(fxname), "^%s*(.-)%s*$"))
            --local fxident = GetPlugIdentifierFromChunk(fxchunks[fx].chunk)
            local fxident = string.lower(tfxi[fx-1].fxfn)
            if fxident and fxident ~= '' and plugdefstrips_idx and (plugdefstrips_idx[fxname] or plugdefstrips_idx[fxident]) then
              local idx = plugdefstrips_idx[fxname] or plugdefstrips_idx[fxident]
              if idx and plugdefstrips[idx] then
                local sfol = plugdefstrips[idx].stripfol
                local sfil = plugdefstrips[idx].stripfile
                loadstrip = LoadStrip(nil, sfol, sfil, true)
                if loadstrip then

                  lupd.update_gfx = true

                  local switchid2
                  local strip = tracks[track_select].strip
                  local ctls = strips[strip][page].controls
                  for i = 1, #ctls do
                    if ctls[i].ctlcat == ctlcats.switcher then
                      local swid = ctls[i].switcherid
                      if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                        switchid = swid
                        break
                      end
                    end
                  end

                  local extid
                  local maxpos = 0
                  if switchid then
                    extid = switchers[switchid].extendid
                    maxpos = Switcher_Ext_GetMaxPos(extid)

                    for s = 1, #switchers do
                      if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                         switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                        switchid2 = s
                        break
                      end
                    end
                    if switchid2 --[[and #switchers[switchid2].grpids > 0]] then
                      maxpos = maxpos + 1
                    end
                  end

                  local c = Switchers_Ext_Insert(switchid, maxpos)
                  local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, nil, nil, dm_data)
                  --if swok ~= true then
                  --  Switcher_DeleteExt(ctls[c].switcherid)
                  --end

                  loadstrip = nil

                end
              end
            else
              --add placeholder switcher
              local sfn = paths.resource_path..'dynamic_placeholder.strip'
              loadstrip = LoadStripFN(nil, sfn)

              if loadstrip then
                local switchid2
                local strip = tracks[track_select].strip
                local ctls = strips[strip][page].controls
                local ccnt = #ctls
                for i = 1, ccnt do
                  if ctls[i].ctlcat == ctlcats.switcher then
                    local swid = ctls[i].switcherid
                    if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                      switchid = swid
                      break
                    end
                  end
                end

                local extid
                local maxpos = 0
                if switchid then
                  extid = switchers[switchid].extendid
                  maxpos = Switcher_Ext_GetMaxPos(extid)

                  for s = 1, #switchers do
                    if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                       switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                      switchid2 = s
                      break
                    end
                  end
                  if switchid2 --[[and #switchers[switchid2].grpids > 0]] then
                    maxpos = maxpos + 1
                  end
                end

                local c = Switchers_Ext_Insert(switchid, maxpos)
                local _, fxname = reaper.TrackFX_GetFXName(track, fx-1, '')
                fxname = CropFXName(fxname)
                local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, fxname or fxident)
              end

            end
          end
          if cdata then
            local nctldata, nctldataidx = DM_GetCtlTranslateTable(cdata)
            DM_RebuildPageSnaps(cdata, nctldata, nctldataidx)
            DM_RebuildModulators(cdata, nctldata, nctldataidx)
            DM_RebuildFaders(cdata, nctldata, nctldataidx)
            DM_RebuildMacro(cdata, nctldata, nctldataidx)            
          end
        end


        if switchid then
          local extid = switchers[switchid].extendid
          Strip_ReposSwitcher_Ext(extid, 1)
        end

        local strip = tracks[track_select].strip
        local fxstr = ''
        local fxcnt = reaper.TrackFX_GetCount(track)
        strips[strip][page].fxcnt = fxcnt

        local fxguid = {}
        for fx = 0, fxcnt-1 do
          local guid = reaper.TrackFX_GetFXGUID(track,fx)
          --if guid ~= lvar.analyzer.guid then
            fxguid[#fxguid+1] = guid
          --end
        end
        strips[strip][page].fxstr = table.concat(fxguid,'')

        --surface_offset.mixx = -40
        --surface_offset.mixy = -40

        SetCtlBitmapRedraw(true)

        local mmlen = MixMode_GetLength()
        --[[if lvar.mixmodedir == 0 then
          surface_offset.mixy = math.min(math.floor((0-obj.sections[10].h/2)+(mmlen/2)),-40)
        else
          surface_offset.mixx = math.min(math.floor((0-obj.sections[10].w/2)+(mmlen/2)),-40)
        end]]
        --DBG(mmlen..'  '..surface_offset.mixy..'  '..math.floor((0-obj.sections[10].h/2)+(mmlen/2)))
        --MixMode_Swipe(1,1,true)
        DM_StoreStripData()--force)

      end

      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()

      lvar.checkdatatables_active = true
      CheckDataTables(nil, true)

      if not fmode then
        UpdateControlValues3(nil, ctls_upd, ctls_orr)
      end
      
      --if not dm_data then
        RefreshSnapshotControls(tracks[track_select].strip, page)
      --end

    else
      lvar.dynamicmode_trn = nil
      lvar.dynamicmode_guid = nil
      lvar.dm_trname = ''
      SetCtlBitmapRedraw(true)
    end
    
    RecallFaders(true)
    
    if settings_trackchangemidi == true then
      TrackChangeMidi()
    end
    lvar.dm_refresh = nil

    local refresh
    if lvar.dm_refreshtrack_active and not lvar.dm_refreshtrack[lvar.dynamicmode_guid] then
      refresh = true
      lvar.dm_refreshtrack[lvar.dynamicmode_guid] = true
      DM_RefreshPage(true)
    end
    
    if lvar.popout_autoarrange and lvar.showpoponly and lvar.autoarrange_activefx then
      PopOut_AutoArrange_ActiveFX()
    end
    
    if sfade then
      SetSurfaceFade()
    end
  end

  function DM_RefreshFX()
    lvar.dm_refreshfx = true
  end

  function Switcher_AddStrip(fn, switcher, loadstrip, fxdata, trn, fx, overridename, dm_create, dm_data, swipe, stripid)

    loadstrip = loadstrip or LoadStripFN(fn)

    if loadstrip then

      --[[if lvar.livemode == 2 then
        if #loadstrip.fx ~= 1 then
          loadstrip = nil
          return
        end
      end]]

      reaper.PreventUIRefresh(1)

      GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
      --image_count = image_count_add

      local swok = true
      local nc, ng = 1,1

      local ctls = strips[tracks[track_select].strip][page].controls
      local gfxx = strips[tracks[track_select].strip][page].graphics
      local switchid = ctls[switcher].switcherid
      local ctl_sw = ctls[switcher]
      local oswcnt = #switchers

      local x,y = ctl_sw.x - surface_offset.x, ctl_sw.y - surface_offset.y
      y = y + ctl_sw.ctl_info.cellh

      local grpid, ngrpid, sw_cur
      if (switchers[switchid].switchmode or 0) == 0 then

        nc, ng = #ctls+1, #gfxx+1
        stripid, _, grpid, fxguids = Strip_AddStrip(loadstrip,x,y,true, nil, nil, 0, nil, fxdata)
        sw_cur = #switchers[switchid].grpids+1
        switchers[switchid].grpids[sw_cur] = {}
        switchers[switchid].grpids[sw_cur].id = grpid
        switchers[switchid].grpids[sw_cur].name = string.match(fn,'.+/(.-).strip')

        if ctl_sw then
          ctl_sw.param_info.paramname = string.format('%i',sw_cur)..': '..switchers[switchid].grpids[sw_cur].name
        end
        switchers[switchid].current = grpid
        if fxguids and #fxguids > 0 then
          switchers[switchid].fxguids = fxguids
        end

      elseif switchers[switchid].switchmode == 1 then

        --set strip folder
        local sss = string.match(loadstrip.fn,'.+[\\/]strips[\\/](.+).strip$')
        if sss then
          local sss2 = string.match(sss,'(.-)[\\/].*')
          if sss2 then
            switchers[switchid].stripfolder = sss2
          end
        else
          local sss2 = string.match(loadstrip.fn,'(.-)[\\/].*')
          local dph = string.match(loadstrip.fn,'.+[\\/](.*)')
          if dph == 'dynamic_placeholder.strip' then
            switchers[switchid].stripfolder = '__LBXFAVS'
          elseif sss2 then
            switchers[switchid].stripfolder = sss2
          end

        end

        if switchers[switchid].dropx and switchers[switchid].dropy then
          x = switchers[switchid].dropx + ctl_sw.x - surface_offset.x
          y = switchers[switchid].dropy + ctl_sw.y - surface_offset.y
        end

        local stripids, firstfxslot = Switcher_GetStripIDs(switchid, grpid)

        --ctl_sw.id = nil --prevent deletion of switcher ctl

        --reaper.PreventUIRefresh(1)
        if fxdata and lvar.livemode == 2 and lvar.show_addstripdialog then
          --DeleteSwitcherStrip(switchid, true, true, fxdata)
          local checkguid = {}
          local delswids = {}
          for i = 1, #fxdata do
            if fxdata[i].fxguid then
              checkguid[fxdata[i].fxguid] = i
            end
          end
          local stripdim = lvar.stripdim
          local extid = switchers[switchid].extendid
          local extmax = Switcher_Ext_GetMaxPos(extid)
          for pos = 1, extmax do
            local swid = stripdim.extposidx[extid][pos]
            local fxguids = switchers[swid].fxguids
            local del, nodel
            if fxguids then
              for f = 1, #fxguids do
                if checkguid[fxguids[f]] then
                  del = true
                else
                  nodel = true
                end
              end
            end
            if del then
              if not nodel then
                delswids[pos] = swid
              end
            end
          end

          for d = extmax,1,-1  do
            if delswids[d] then
              if delswids[d] == switchid then
                DeleteSwitcherStrip(delswids[d], false, true, fxdata)
              else
                Switcher_DeleteExt(delswids[d], true, fxdata)
              end
            end
          end

        elseif fxdata then
          DeleteSwitcherStrip(switchid, true, true, fxdata)
        else
          DeleteSwitcherStrip(switchid, true, true)
        end

        --Reload ctls and gfxx as tables have changed

        ctls = strips[tracks[track_select].strip][page].controls
        gfxx = strips[tracks[track_select].strip][page].graphics
        switchid = ctl_sw.switcherid --get new switcherid as everything is reordered
        if insertstrip then
          insertstrip.target = switchid
        end             
        local cn = Switchers_FindCtl(switchid)
        ctl_sw = ctls[cn]

        nc, ng = #ctls+1, #gfxx+1

        --relocate target pos
        local trg, fxn
        if lvar.livemode ~= 2 then
          trn, trg, fxn = FindInsertFX(ctl_sw.fxguid, ctl_sw.tracknum, ctl_sw.fxnum)
          if not fxn then return end
        else
          local tr = GetTrack(trn)
          trg = GetTrackGUID(tr)
          fxn = fx-1
        end
        --pins

        local pinmaps
        if lvar.livemode ~= 2 then
          if switchers[switchid].copypinmap == true then
            local tr = GetTrack(ctl_sw.tracknum or strips[tracks[track_select].strip].track.tracknum)
            if tr and ctl_sw.fxnum then
              local pm_inLo, pm_inHi, pm_outLo, pm_outHi = GetPinMap(tr, ctl_sw.fxnum)
              pinmaps = {inLo = pm_inLo, inHi = pm_inHi, outLo = pm_outLo, outHi = pm_outHi}
            end
          end
        end

        --reaper.PreventUIRefresh(1)
        --local oksi = lvar.addstrip_keepseparateids
        --lvar.addstrip_keepseparateids = true
        --DBG('fx1:'..tostring(fxdata))
        if loadstrip.version == nil then
          loadstrip.plugpos = fxn
        end

        if fxdata then
          local alllink = true
          for i = 1, #loadstrip.fx do
            --DBG('dd'..tostring(fxdata[i].fxnum))
            if not fxdata[i].fxnum then
              alllink = false
            end
          end
          if alllink then
            dm_create = false
          end
        end
        stripid, _, ngrpid, fxguids = Strip_AddStrip(loadstrip,x,y,true,trn,trg,fxn+1,pinmaps,fxdata, dm_create, nil, dm_data, stripid)

        --lvar.addstrip_keepseparateids = oksi

        --ctl_sw.id = stripid
        --reaper.PreventUIRefresh(-1)
        grpid = ngrpid

        local pfx = ''
        if ctl_sw.fxnum then
          local track = GetTrack(ctl_sw.tracknum or strips[tracks[track_select].strip].track.tracknum)
          if track then

            local _, fxname = reaper.TrackFX_GetFXName(track, ctl_sw.fxnum, '')
            if fxname then
              pfx = CropFXName(fxname)
            end

          end
        end

        sw_cur = 1
        switchers[switchid].grpids[sw_cur] = {}
        switchers[switchid].grpids[sw_cur].id = grpid
        --switchers[switchid].grpids[sw_cur].name = pfx..': '..string.match(fn or loadstrip.fn,'.+/(.-).strip')
        if overridename then
          switchers[switchid].grpids[sw_cur].name = overridename
        else
          switchers[switchid].grpids[sw_cur].name = string.match(fn or loadstrip.fn,'.+/(.-).strip')
        end
        if ctl_sw then
          ctl_sw.param_info.paramname = switchers[switchid].grpids[sw_cur].name
        end
        switchers[switchid].current = grpid
        if fxguids and #fxguids > 0 then
          switchers[switchid].fxguids = fxguids
        end
        if string.match(loadstrip.fn, '%/LBXCS_resources%/') then
          switchers[switchid].grpids[sw_cur].stripfn = loadstrip.fn
        else
          switchers[switchid].grpids[sw_cur].stripfn = paths.strips_path..'/'..loadstrip.fn
        end
      end

      local stripids = {}
      if #switchers > oswcnt then

        local extid = switchers[switchid].extendid
        local inspos = switchers[switchid].extendpos
        local extmax = Switcher_Ext_GetMaxPos(extid)
        local poscnt = extmax + 1
        local nextcnt = 0
        for s = oswcnt+1, #switchers do
          if switchers[s].switchmode == 1 and switchers[s].extendmode == true then
            switchers[s].extendid = extid
            if switchers[switchid].posfirstswitcher then
              switchers[s].posfirstswitcher = {x = switchers[switchid].posfirstswitcher.x,
                                               y = switchers[switchid].posfirstswitcher.y}
            end
            if switchers[switchid].padx then
              switchers[s].padx = switchers[switchid].padx
            end
            if switchers[switchid].pady then
              switchers[s].pady = switchers[switchid].pady
            end

            nextcnt = nextcnt + 1
            swok = false
          end
        end
        if nextcnt > 0 then
          for s = 1, oswcnt do
            if switchers[s].switchmode == 1 and switchers[s].extendmode == true and switchers[s].extendid == extid then
              if switchers[s].extendpos >= inspos then
                switchers[s].extendpos = switchers[s].extendpos + nextcnt
              end
            end
          end
        end
        for s = oswcnt+1, #switchers do

          if switchers[s].switchmode == 1 and switchers[s].extendmode == true then
            switchers[s].extendpos = inspos + switchers[s].extendpos -1 --poscnt-1 + switchers[s].extendpos
            switchers[s].parent = nil
            local c = Switchers_FindCtl(s)
            local ctl = strips[tracks[track_select].strip][page].controls[c]
            ctl.grpid = nil

            stripids[s] = GenID()

            --poscnt = poscnt + 1
            --swok = false
          end
        end
      end

      --local ctls = strips[tracks[track_select].strip][page].controls
      --local gfxx = strips[tracks[track_select].strip][page].graphics
      local dph, track
      if loadstrip and lvar.livemode == 2 then
        if string.match(loadstrip.fn,'.+[\\/](.*)') == 'dynamic_placeholder.strip' then
          dph = true
          track = GetTrack(lvar.dynamicmode_trn)
        end
      end

      for c = nc, #ctls do
        if ctls[c].id == stripid then
          if swok == true or (ctls[c].switcher == nil) then

            if ctls[c].ctlcat == ctlcats.switcher then
              if switchers[ctls[c].switcherid].switchmode == 1 and switchers[ctls[c].switcherid].extendmode == true then
                --switchers[ctls[c].switcherid].extendid = switchers[switchid].extendid
              elseif switchers[ctls[c].switcherid].parent == nil or switchers[ctls[c].switcherid].parent.switcherid == nil then
                --add parent info --hmmm - what about loaded nested switchers
                local sid = ctls[c].switcherid
                switchers[sid].parent = {switcherid = switchid,
                                         grpid = grpid}
              else
                --DBG(c..' parent '..switchers[ctls[c].switcherid].parent.switcherid)
                --DBG('grpid '..switchers[ctls[c].switcherid].parent.grpid)
                --DBG(switchers[switchers[ctls[c].switcherid].parent.switcherid])
              end
            end
            --DBG(tostring(swok)..'  '..c..'  '..ctls[c].param_info.paramname..'  '..tostring(ctls[c].switcher)..'  '..tostring(ctls[c].grpid)..'  '..switchid)
            if swok == true and ctls[c].switcher == nil then
              ctls[c].switcher = switchid
              ctls[c].grpid = grpid
            end

          elseif swok ~= true then

            --if ctls[c].ctlcat == ctlcats.switcher then
              --if switchers[ctls[c].switcherid].switchmode == 1 and switchers[ctls[c].switcherid].extendmode == true then
                --switchers[ctls[c].switcherid].extendid = switchers[switchid].extendid


          end

        end

        if swok ~= true and ctls[c].switcher and ctls[c].switcher > oswcnt then
          local sid = Switcher_GetTopLevelSwitcher(ctls[c].switcher)
          if stripids[sid] == nil then
            stripids[sid] = GenID()
          end
          ctls[c].id = stripids[sid]
        end

        if ctls[c].switcherid then
          local swid = ctls[c].switcherid
          if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
            ctls[c].id = nil
            ctls[c].grpid = nil
          end
        end

        if lvar.livemode == 2 and dph then
          if ctls[c].ctlcat == ctlcats.fxparam then
            if ctls[c].param == 0 then
              ctls[c].param = reaper.TrackFX_GetNumParams(track, ctls[c].fxnum)-2
            end
          end
        end
      end

      for c = ng, #gfxx do
        if gfxx[c].id == stripid then
          if swok == true and (gfxx[c].switcher == nil) then
            --if gfxx[c].grpid == nil then
            gfxx[c].grpid = grpid
            --end
            gfxx[c].switcher = switchid
          end
        end

        if swok ~= true and gfxx[c].switcher and gfxx[c].switcher > oswcnt then
          local sid = Switcher_GetTopLevelSwitcher(gfxx[c].switcher)
          if stripids[sid] == nil then
            stripids[sid] = GenID()
          end
          gfxx[c].id = stripids[sid]
          --  DBG('id'..gfxx[c].id)
        end
      end

      if swok == true and lvar.livemode ~= 2 then
        if (switchers[switchid].switchmode or 0) == 1 and switchers[switchid].extendmode == true then

          local extid = switchers[switchid].extendid
          local extpos = Switcher_Ext_GetMaxPos(extid)

          if switchers[switchid].extendpos == extpos then

            --Add new switcher underneath
            local _,l,r,t,b,swl,swt = Switcher_ContentsLocInfo(switchid)

            local pady = 20
            Strip_AddSwitcher_Ext(swl,b+pady,ctl_sw.knob_select,switchid,extpos+1,true)

            --Reposition subsequent switchers
            Switchers_Ext_MovePos(extid,1,1,true,true,true)

            --Strip_ReposSwitcher_Ext(extid, 1)
          else
            --Reposition subsequent switchers

            Switchers_Ext_MovePos(extid,1,1,true,true,true)
            --Strip_ReposSwitcher_Ext(extid, 1)
          end

        end
      --elseif swok == true then

        --local extid = switchers[switchid].extendid
        --Strip_ReposSwitcher_Ext(extid, 1)

      elseif lvar.livemode ~= 2 then
        --Reposition subsequent switchers

        local extid = switchers[switchid].extendid
        Switchers_Ext_MovePos(extid,1,1,true,true,true)
        --Strip_ReposSwitcher_Ext(extid, 1)
      end

      if lvar.livemode == 2 then
        if lvar.popout_autoarrange and lvar.showpoponly and lvar.autoarrange_activefx then
          PopOut_AutoArrange_ActiveFX()
        end
      end

      lupd.update_gfx = true
      lupd.update_bg = true
      SetCtlBitmapRedraw()
      reaper.MarkProjectDirty(0)


      if lvar.livemode == 2 and lvar.dm_addstrip_autoswipe and swipe then
      
        --scroll to new switcher
        local inspos = switchers[switchid].extendpos
        --MixMode_Swipe((lvar.centrepos or 0), inspos)
        lvar.autoswipe = {ip = inspos, swid = switchid}      
      
      end

      reaper.PreventUIRefresh(-1)

      return swok
    end

  end

  function Switcher_Ext_Drag(switchid, c)



  end

  function Switchers_Ext_GetTop(extid)
    local topx, topy
    for i = 1, #switchers do
      if switchers[i].switchmode == 1 and switchers[i].extendmode == true then
        if switchers[i].extendid == extid then
          if switchers[i].extendpos == 1 then
            local c = Switchers_FindCtl(i)
            local strip = tracks[track_select].strip
            local ctl = strips[strip][page].controls[c]
            if ctl then
              topx = ctl.x
              topy = ctl.y
            end
            break
          end
        end
      end
    end
    return topx, topy
  end

  function Switchers_Ext_MovePos(extid, oldpos, newpos, before, movefx, force, nomove)

    --reaper.PreventUIRefresh(1)

    if oldpos < newpos and before == true then
      newpos = newpos - 1
    elseif oldpos > newpos and before ~= true then
      newpos = newpos + 1
    end

    local extmax = Switcher_Ext_GetMaxPos(extid)
    if newpos < 1 or newpos > extmax then return end

    if oldpos ~= newpos or force then

      if lvar.livemode == 2 then
        nomove = true
      end

      if not nomove then
        local src_c, src_c1, dst_c, dts_c1
        local topx, topy
        local ctls = strips[tracks[track_select].strip][page].controls
  
        for i = 1, #switchers do
          if switchers[i].switchmode == 1 and switchers[i].extendmode == true then
            if switchers[i].extendid == extid then
              if switchers[i].extendpos == oldpos then
                src_c = Switchers_FindCtl(i)
              --elseif switchers[i].extendpos == oldpos+1 then
              --  src_c1 = Switchers_FindCtl(i)
              end
              if switchers[i].extendpos == newpos then
                dst_c = Switchers_FindCtl(i)
              elseif switchers[i].extendpos == newpos+1 then
                dst_c1 = Switchers_FindCtl(i)
              end
              if src_c and dst_c and dst_c1 then
                break
              end
            end
          end
        end
      end
      
      if nomove or (src_c and dst_c) then

        if not nomove then
          local srcctl_sw = ctls[src_c]
          local dstctl_sw = ctls[dst_c]
          local dstctl_sw1
          if dst_c1 then
            dstctl_sw1 = ctls[dst_c1]
          end
  
          local dst_trn, dst_trg, dst_fxn
          if lvar.livemode ~= 2 then
            if oldpos < newpos and dstctl_sw1 then
              dst_trn, dst_trg, dst_fxn, dst_fxg = FindInsertFX(dstctl_sw1.fxguid, dstctl_sw1.tracknum, dstctl_sw1.fxnum)
            else
              dst_trn, dst_trg, dst_fxn, dst_fxg = FindInsertFX(dstctl_sw.fxguid, dstctl_sw.tracknum, dstctl_sw.fxnum)
            end
          end
  
          
          local ctl_c
          for i = 1, #switchers do
            if switchers[i].switchmode == 1 and switchers[i].extendmode == true then
              if switchers[i].extendid == extid then
                if switchers[i].extendpos == 1 then
                  for c = 1, #ctls do
                    if ctls[c].switcherid == i then
                      ctl_c = c
                      break
                    end
                  end
                  if ctl_c then
                    topx = ctls[ctl_c].x
                    topy = ctls[ctl_c].y
                    break
                  end
                end
              end
            end
          end
        end

        for i = 1, #switchers do
          if switchers[i].switchmode == 1 and switchers[i].extendmode == true then
            if switchers[i].extendid == extid then
              if oldpos > newpos then
                if switchers[i].extendpos == oldpos then
                  switchers[i].extendpos = newpos
                elseif switchers[i].extendpos >= newpos and switchers[i].extendpos < oldpos then
                  switchers[i].extendpos = switchers[i].extendpos + 1
                end
              else
                if switchers[i].extendpos == oldpos then
                  switchers[i].extendpos = newpos
                elseif switchers[i].extendpos > oldpos and switchers[i].extendpos <= newpos then
                  switchers[i].extendpos = switchers[i].extendpos - 1
                end
              end
            end
          end
        end

        avoidtop = false
        if newpos == 1 then
          avoidtop = true
        end
        
        if nomove then
          
        else
          Strip_ReposSwitcher_Ext(extid, 1, topx, topy, avoidtop)
          lupd.update_gfx = true
          lupd.update_bg = true
        end
        
        --Move FX Here...
        if movefx == true then
          if reaper.APIExists('TrackFX_CopyToTrack') == true then

            --reaper.PreventUIRefresh(1)
            local dsttrack = GetTrack(dst_trn)

            Switchers_SortFXChain(extid, dsttrack)

            --[[local fxns = Switchers_GetFXNs(srcctl_sw.switcherid, srcctl_sw)
            if fxns then
              local srctrack = GetTrack(fxns[0].trn)
              MoveFXByGUID2(srctrack,fxns[0].fxg,dsttrack,dst_fxg,0)
              for f = #fxns, 1, -1 do

                local srctrack = GetTrack(fxns[f].trn)
                local shift = MoveFXByGUID2(srctrack,fxns[f].fxg,dsttrack,dst_fxg,1)
                --dst_fxn = dst_fxn + shift
              end
            end]]

            --local src_trn, src_trg, src_fxn = FindInsertFX(srcctl_sw.fxguid, srcctl_sw.tracknum, srcctl_sw.fxnum)
            --local srctrack = GetTrack(src_trn)
            --reaper.TrackFX_CopyToTrack(srctrack,src_fxn,dsttrack,dst_fxn,true)
            --MoveFXByGUID(srctrack,srcctl_sw.fxguid,dsttrack,dst_fxn,srcctl_sw)

            --reaper.PreventUIRefresh(-1)
          end
        end

        if nomove then
          SetCtlBitmapRedraw(true)
          lupd.update_surface = true
        else
          SetCtlBitmapRedraw()
        end
        reaper.MarkProjectDirty(0)
      end

    end
    --reaper.PreventUIRefresh(-1)

  end

  function MoveFXByGUID(srctr, srcguid, dsttr, dstfxn)

    local fxn = GetFXNFromGUID(srctr,srcguid)
    if fxn == nil then return end
    if fxn ~= dstfxn then
      reaper.TrackFX_CopyToTrack(srctr,fxn,dsttr,dstfxn,true)
    end
    return true

  end

  function MoveFXByGUID2(srctr, srcguid, dsttr, dstfxg, offs)
    local dfxn = GetFXNFromGUID(dsttr,dstfxg) -- + offs
    local fxn = GetFXNFromGUID(srctr,srcguid)
    if fxn and dfxn then
      reaper.TrackFX_CopyToTrack(srctr,fxn,dsttr,dfxn,true)
    end
  end

  function GetFXNFromGUID(tr, guid, searchtracks)
    if tr then
      for i = 0, reaper.TrackFX_GetCount(tr)-1 do
        if reaper.TrackFX_GetFXGUID(tr,i) == guid then
          return i, tr
        end
      end
    end
    if searchtracks then
      for t = -1, reaper.CountTracks(0)-1 do
        local tr = GetTrack(t)
        if tr then
          for i = 0, reaper.TrackFX_GetCount(tr)-1 do
            if reaper.TrackFX_GetFXGUID(tr,i) == guid then
              return i, tr
            end
          end
        end
      end
    end
  end

  function Switchers_GetTopInsertFXPos(extid)
    local fxnum
    for i = 1, #switchers do
      if switchers[i].switchmode == 1 and switchers[i].extendmode == true and switchers[i].extendid == extid then
        local c = Switchers_FindCtl(i)
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[c]
        if ctl then
          if ctl.fxnum then
            fxnum = math.min(ctl.fxnum, fxnum or ctl.fxnum)
          end
        end
      end
    end
    return fxnum
  end

  function Switchers_SortFXChain2(extid, dtr, nosort)
    --This function sorts fx so each switchers fx are next to each other in original order
    local track = GetTrack(lvar.dynamicmode_trn)
    if track then

      --local pos = 0
      local extmax = Switcher_Ext_GetMaxPos(extid)

      reaper.PreventUIRefresh(1)

      for i = 1, extmax do

        local fxguids = Switchers_GetFXGUIDs(extid, i)
        if fxguids then

          if #fxguids > 1 then
            local pos, ps
            for p = 1, #fxguids do
              local pp = GetFXNFromGUID(track, fxguids[p])
              if pp then
                pos = math.min((pos or 9999),pp)
                --ps = p+1
                --pos = pp+1
                --break
              end
            end
            if pos then
              for fg = 1, #fxguids do

                if MoveFXByGUID(track, fxguids[fg], track, pos) == true then
                  pos = pos + 1
                end

              end
            end
            --[[for p = 1, #fxguids do
              local pp = GetFXNFromGUID(track, fxguids[p])
              if pp then
                if MoveFXByGUID(track, fxguids[fg], track, pos) == true then
                  pos = pos + 1
                end

              end
            end]]
          end
        end

      end
      if not nosort then
        UpdateControlValues3(nil, ctls_upd, ctls_orr)
      end
      DM_RefreshFX()

      reaper.PreventUIRefresh(-1)

    end

  end

  function Switchers_SortFXChain(extid, dtr, nosort)
    --Sorts entire ext switcher chain


    if lvar.livemode == 2 --[[and oldpos and newpos]] then

      --Switchers_SortFXChain2(extid, dtr, nosort)
      local track = GetTrack(lvar.dynamicmode_trn)
      if track then

        local pos = 0
        local extmax = Switcher_Ext_GetMaxPos(extid)

        for i = 1, extmax do

          local fxguids = Switchers_GetFXGUIDs(extid, i)
          if fxguids then

            for fg = 1, #fxguids do

              if MoveFXByGUID(track, fxguids[fg], track, pos) == true then
                pos = pos + 1
              end

            end

          end

        end
        if not nosort then
          UpdateControlValues3(nil, ctls_upd, ctls_orr)
        end
        DM_RefreshFX()

      end

    elseif lvar.livemode ~= 2 then

      local extmax = Switcher_Ext_GetMaxPos(extid)
      local fxnum = Switchers_GetTopInsertFXPos(extid)
      if fxnum then
        local fxc = fxnum or 0
        local trfxguids
        --DBG('extmax '..extmax..'  '..extid)
        for i = 1, extmax do
          local fxns
          fxns, trfxguids = Switchers_GetFXNs2(extid, i, trfxguids)
          for f = 0, #fxns do
            local str = GetTrack(fxns[f].trn)
            if MoveFXByGUID(str, fxns[f].fxg, dtr, fxc) == true then
              fxc = fxc + 1
            end
          end
        end
      else
        --use dynamic mode sort?

      end
    end

  end

  function Switchers_GetFXGUIDs(extid, extpos)

    local switchid
    for i = 1, #switchers do
      if switchers[i].switchmode == 1 and switchers[i].extendmode == true and switchers[i].extendid == extid then
        --DBG('extid '..extid)
        if switchers[i].extendpos == extpos then
          switchid = i
          break
        end
      end
    end
    if switchid then
      return switchers[switchid].fxguids
    end
  end

  function Switchers_GetFXNs2(extid, extpos, trfxguids)

    local switchid
    for i = 1, #switchers do
      if switchers[i].switchmode == 1 and switchers[i].extendmode == true and switchers[i].extendid == extid then
        --DBG('extid '..extid)
        if switchers[i].extendpos == extpos then
          switchid = i
          break
        end
      end
    end
    local fxns, trfxguids = Switchers_GetFXNs_alt(switchid, nil, trfxguids)
    return fxns, trfxguids

  end

  function Switchers_GetFXNs_alt(switchid, ctlsw, trfxguids)

    local fxns = {}
    local fxidx = {}

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls

    if not ctlsw then
      --DBG(switchid)
      --DBG(Switchers_FindCtl(switchid))
      ctlsw = ctls[Switchers_FindCtl(switchid)]
    end

    if ctlsw then
      if switchers[switchid] then
        local fxguids = switchers[switchid].fxguids
        if fxguids and #fxguids > 0 then
  
          if not trfxguids then
            trfxguids = GetTrackFXGUIDs(tracks[track_select].tracknum)
          end
  
          local alltrackguidsread = false
  
          for f = 1, #fxguids do
  
            local tfg = trfxguids[fxguids[f]]
            if not tfg and alltrackguidsread == false then
              alltrackguidsread = true
              trfxguids = GetAllTrackFXGUIDs()
              tfg = trfxguids[fxguids[f]]
            end
  
            if tfg then
              local fxnum = tfg.fxn
              if fxnum then
  
                fxns[#fxns+1] = {trn = tfg.trn, fxn = fxnum, fxg = fxguids[f]}
                fxidx[fxnum] = true
  
              end
            end
          end
        end
  
  
        fxns = table_slowsort_gen(fxns,'fxn')
        local src_trn, src_trg, src_fxn, src_fxg = FindInsertFX(ctlsw.fxguid, ctlsw.tracknum, ctlsw.fxnum)
        if not fxns then
          fxns = {}
        end
        fxns[0] = {trn = src_trn, fxn = src_fxn, fxg = ctlsw.fxguid}
      end
    end
    
    return fxns, trfxguids

  end

  function Switchers_GetFXNs(switchid, ctlsw)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local gids = Switchers_GetGrpIDs(switchid)
    local fxns = {}
    local fxidx = {}

    if not ctlsw then
      ctlsw = ctls[Switchers_FindCtl(switchid)]
    end

    for i = 1, #ctls do
      local ctl = ctls[i]
      if gids[ctl.grpid] == true then
        if ctl.fxnum and not fxidx[ctl.fxnum] then
          local trn = ctl.tracknum or tracks[track_select].tracknum
          fxns[#fxns+1] = {trn = trn, fxn = ctl.fxnum, fxg = ctl.fxguid}
          fxidx[ctl.fxnum] = true
        end
      end
    end

    fxns = table_slowsort_gen(fxns,'fxn')
    local src_trn, src_trg, src_fxn, src_fxg = FindInsertFX(ctlsw.fxguid, ctlsw.tracknum, ctlsw.fxnum)
    if not fxns then
      fxns = {}
    end
    fxns[0] = {trn = src_trn, fxn = src_fxn, fxg = ctlsw.fxguid}
    return fxns

  end

  function Switchers_GetGrpIDs(switchid, gids, swdone)

    if swdone == nil then
      swdone = {}
    end
    swdone[switchid] = true
    if gids == nil then
      gids = {}
    end
    for i = 1, #switchers[switchid].grpids do
      gids[switchers[switchid].grpids[i].id] = true
    end
    local ctls = strips[tracks[track_select].strip][page].controls
    for i = 1, #ctls do
      if ctls[i].ctlcat == ctlcats.switcher and not swdone[ctls[i].switcherid] and ctls[i].grpid and gids[ctls[i].grpid] then
        gids, swdone = Switchers_GetGrpIDs(ctls[i].switcherid, gids, swdone)
      end
    end
    return gids, swdone

  end

  function Switchers_Ext_Insert(switchid, extpos, s, dm_create)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local c

    if switchid then
      local extid = switchers[switchid].extendid

      local topx, topy = 0, 0
      if extpos == 1 then
        local ctl_c
        for i = 1, #switchers do
          if switchers[i].switchmode == 1 and switchers[i].extendmode == true then
            if switchers[i].extendid == extid then
              if switchers[i].extendpos == 1 then
                for c = 1, #ctls do
                  if ctls[c].switcherid == i then
                    ctl_c = c
                    break
                  end
                end

                if ctl_c then
                  topx = ctls[ctl_c].x
                  topy = ctls[ctl_c].y
                  break
                end
              end
            end
          end
        end

      end

      local swc = Switchers_FindCtl(switchid)
      local ctl_sw = ctls[swc]
      local trn, trg, fxn
      if lvar.livemode ~= 2 then
        trn, trg, fxn = FindInsertFX(ctl_sw.fxguid, ctl_sw.tracknum, ctl_sw.fxnum)
        Switchers_Ext_Shift(extid, extpos, 1)
        c = Strip_AddSwitcher_Ext(topx,topy,ctl_sw.knob_select,switchid,extpos,true,fxn)

        Strip_ReposSwitcher_Ext(extid, 1)
      else
        Switchers_Ext_Shift(extid, extpos, 1)
        c = Strip_AddSwitcher_Ext(topx,topy,ctl_sw.knob_select,switchid,extpos,false,fxn)

        Strip_ReposSwitcher_Ext(extid, 1)

      end
    else

      if lvar.livemode ~= 2 then
        c, switchid = Strip_AddSwitcher_Ext(0,0,nil,nil,1,true,0)
      else
        c, switchid = Strip_AddSwitcher_Ext(0,0,nil,nil,1,false,0)
      end
      --local swid = ctls[c].switcherid

      --Strip_ReposSwitcher_Ext(extid, 1)

    end

    lupd.update_gfx = true
    lupd.update_bg = true
    SetCtlBitmapRedraw()
    reaper.MarkProjectDirty(0)

    return c, switchid

  end

  function Switchers_FindCtl(switchid)

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls

    for i = 1, #ctls do
      local ctl = ctls[i]
      if ctl.ctlcat == ctlcats.switcher then
        if ctl.switcherid == switchid then
          return i
        end
      end
    end
  end

  function Switchers_Ext_Shift(extid, extpos, s)
    for i = 1, #switchers do

      if switchers[i].switchmode == 1 then
        if switchers[i].extendid == extid then

          if switchers[i].extendpos >= extpos then

            switchers[i].extendpos = switchers[i].extendpos + s

          end

        end
      end
    end
  end

  function Switchers_AddInsertFX(switchid, strip, page, c, fxloc)

    if lvar.livemode ~= 2 then
      local ctl = strips[strip][page].controls[c]
      local trn = strips[strip].track.tracknum
      local track = GetTrack(trn)
      --[[if trn == -3 then
        trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')-1
      end]]

      if track then

        local chunk = GetTrackChunk(track,true)
        local insfxchunk = lvar.lbxinsfx_chunk
        local nchunk, nguid = Chunk_InsertFXChunkAtEndOfFXChain(trn,chunk,insfxchunk)

        --Move
        --if fxloc > 1 then
        --  nchunk = MoveFXChunk2(nchunk, trn, fxcnt, 1, fxcnt)
        --end

        if nchunk then
          SetTrackChunk(track, nchunk, false)
        end

        local fxcnt = reaper.TrackFX_GetCount(track)

        if fxloc then
          if reaper.APIExists('TrackFX_CopyToTrack') == true then
            reaper.TrackFX_CopyToTrack(track,fxcnt-1,track,fxloc,true)
          else
            fxloc = fxcnt
          end
        end

        ctl.fxnum = fxloc or fxcnt
        ctl.fxguid = nguid

      end
    end

  end

  function Strip_ReposSwitcher_Ext(extid, extpos, topx, topy, avoidtop)

    local dir = 0
    if lvar.livemode >= 1 then
      dir = lvar.mixmodedir or 0
    end

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local ext_switchers = {}
    local extmax = 0
    local ext_grpids = {}
    for i = 1, #ctls do
      local ctl = ctls[i]
      if ctl.ctlcat == ctlcats.switcher then
        local switchid = ctl.switcherid
        if switchid then
          local swctl = switchers[switchid]
          if swctl then
            if swctl.extendmode == true and swctl.extendid == extid then
              extmax = math.max(extmax, swctl.extendpos)
              ext_switchers[swctl.extendpos] = {c = i,
                                                switchid = switchid}
              ext_grpids = Switcher_GetGrpIds(switchid, ext_grpids)
            end
          end
        end
      end
    end

    if #ext_switchers > 0 then

      local padx = math.max(lvar.dm_padx, lvar.shadowmax_p)
      local pady = math.max(lvar.dm_pady, lvar.shadowmax_p)

      local l,r,t,b,sl,sr,st,sb, extctls, extgfx = Switcher_ContentsLocInfo_all2(extid)

      if topy == nil and extctls[1] then
        topy = extctls[1].ctl_sw.y
      else
        topy = 0
      end
      if topx == nil and extctls[1] then
        topx = extctls[1].ctl_sw.x
      else
        topx = 0
      end

      local dx = 0
      local ny = topy --b[1]
      --local dy = st[extpos+1]-ny
      local xx = 0
      local testx = 1
      if avoidtop then
        testx = 2
      end
      if sr[testx] then
        xx = math.max(sr[testx], (r[testx] or 0))
      end
      local nx = topx
      if not nx and extctls[1] then
        nx = extctls[1].ctl_sw.x
      else
        nx = 0
      end

      if switchers[extctls[1].ctl_sw.switcherid].posfirstswitcher then
        topx = switchers[extctls[1].ctl_sw.switcherid].posfirstswitcher.x
        topy = switchers[extctls[1].ctl_sw.switcherid].posfirstswitcher.y
        nx = topx
        ny = topy
      end

      local gfxpage = 0

      for i = 1, extmax do

        --check fit
        if extctls and extctls[i] then
          local ctl_sw = extctls[i].ctl_sw

          local ext_h = (b[i] or 0) - (t[i] or 0)
          local ext_w = (r[i] or 0) - (l[i] or 0)
          if ext_w == -lvar.maxdim then
            ext_w = sr[i] - sl[i]
          end
          if ext_h == -lvar.maxdim then
            ext_h = sb[i] - st[i]
          end

          if dir == 0 then
            if ny + pady + ctl_sw.hsc + ext_h + lvar.shadowmax_p > surface_size.h then
              nx = xx + padx
              ny = topy-pady
            end

            if (nx + ext_w + lvar.shadowmax_p > surface_size.w) then
              gfxpage = gfxpage + 1
              nx = 0
              ny = 0
            end
          else
            if (nx + ext_w + lvar.shadowmax_p > surface_size.w) then
              nx = topx-padx
              ny = xx + pady
            end

            if ny + pady + ctl_sw.hsc + ext_h + lvar.shadowmax_p > surface_size.h then
              gfxpage = gfxpage + 1
              nx = 0 --xx + padx
              ny = 0 --topy-pady
            end
          end

          local scale = ctl_sw.scale
          if dir == 0 then
            if nx then
              ctl_sw.x = nx
              ctl_sw.xsc = ctl_sw.x + math.floor(ctl_sw.w/2 - (ctl_sw.w*scale)/2)
            end
            if i == 1 then
              ctl_sw.y = ny
            else
              ctl_sw.y = ny + pady
            end
            ctl_sw.ysc = ctl_sw.y + math.floor(ctl_sw.ctl_info.cellh/2 - (ctl_sw.ctl_info.cellh*scale)/2)
            ctl_sw.gfxpage = gfxpage

            ny = extctls[i].ctl_sw.ysc + extctls[i].ctl_sw.hsc
          else
            if ny then
              ctl_sw.y = ny
              ctl_sw.ysc = ctl_sw.y + math.floor(ctl_sw.ctl_info.cellh/2 - (ctl_sw.ctl_info.cellh*scale)/2)
            end
            if i == 1 then
              ctl_sw.x = nx
            else
              ctl_sw.x = nx + padx
            end
            ctl_sw.xsc = ctl_sw.x + math.floor(ctl_sw.w/2 - (ctl_sw.w*scale)/2)
            ctl_sw.gfxpage = gfxpage

            nx = extctls[i].ctl_sw.xsc + extctls[i].ctl_sw.wsc
          end
          if extctls[i] then
            for c = 1, #extctls[i] do
              local ctl = extctls[i][c]
              local scale = ctl.scale
              ctl.gfxpage = gfxpage
              ctl.x = extctls[i].ctl_sw.x + ctl.ext_dx
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
              ctl.y = extctls[i].ctl_sw.y + ctl.ext_dy
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              if dir == 0 then
                ny = math.max(ny, ctl.y+ctl.ctl_info.cellh)
                xx = math.max(xx, ctl.x+ctl.w)
              else
                nx = math.max(nx, ctl.x+ctl.w)
                xx = math.max(xx, ctl.y+ctl.ctl_info.cellh)
              end
            end
          end
          if extgfx[i] then
            for c = 1, #extgfx[i] do
              local ctl = extgfx[i][c]
              ctl.gfxpage = gfxpage
              ctl.x = extctls[i].ctl_sw.x + ctl.ext_dx
              ctl.y = extctls[i].ctl_sw.y + ctl.ext_dy
              if dir == 0 then
                ny = math.max(ny, ctl.y+ctl.stretchh)
                xx = math.max(xx, ctl.x+ctl.stretchw)
              else
                nx = math.max(nx, ctl.x+ctl.stretchw)
                xx = math.max(xx, ctl.y+ctl.stretchh)
              end
            end
          end
        end
      end

      lvar.gfxpages = gfxpage
      if lvar.livemode >= 1 then
        SetSurfaceSize()
        GUI_DrawCtlBitmap()
      end

    end
  end

  function Switcher_ContentsLocInfo_all2(extid)

    local l,r,t,b = {},{},{},{}
    local extctls = {}
    local extgfx = {}
    local swl, swr, swt, swb = {},{},{},{}

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local gfxx = strips[strip][page].graphics

    local gids = {}
    local sids = {}
    for ii = 1, #ctls do
      local ctl = ctls[ii]
      if ctl.ctlcat == ctlcats.switcher then
        local switchid = ctl.switcherid
        if switchid then
          local swctl = switchers[switchid]
          if swctl and swctl.extendmode == true and swctl.extendid == extid then

            local extpos = swctl.extendpos
            l[extpos],r[extpos],t[extpos],b[extpos] = lvar.maxdim,0,lvar.maxdim,0

            if not extctls[extpos] then
              extctls[extpos] = {}
            end
            extctls[extpos].ctl_sw = ctl
            gids = Switcher_GetGrpIds(switchid, gids)
            --[[for i = 1, #switchers[switchid].grpids do
              gids[switchers[switchid].grpids[i].id] = switchid
            end]]
          end
        end
      end
    end

    for i = 1, #ctls do

      local extpos
      local ctl = ctls[i]
      local sid = gids[ctl.grpid]
      if sid then

        if not switchers[sid].extendpos then
          sid = Switcher_GetTopLevelSwitcher(sid)
        end

        if sid then
          extpos = switchers[sid].extendpos
          l[extpos] = math.min(l[extpos], ctl.xsc)
          r[extpos] = math.max(r[extpos], ctl.xsc+ctl.wsc)
          t[extpos] = math.min(t[extpos], ctl.ysc)
          b[extpos] = math.max(b[extpos], ctl.ysc+ctl.hsc)
          extctls[extpos][#extctls[extpos]+1] = ctl
          ctl.ext_dx = ctl.x-extctls[extpos].ctl_sw.x
          ctl.ext_dy = ctl.y-extctls[extpos].ctl_sw.y
        end
      end

      if ctl.switcherid and switchers[ctl.switcherid] then
        local extpos = switchers[ctl.switcherid].extendpos
        if switchers[ctl.switcherid].switchmode == 1 and switchers[ctl.switcherid].extendmode == true then
          swl[extpos] = ctl.x
          swr[extpos] = ctl.x+ctl.w
          swt[extpos] = ctl.y
          swb[extpos] = ctl.y+ctl.ctl_info.cellh
        end
      end
    end

    for i = 1, #gfxx do

      local ctl = gfxx[i]
      local sid = gids[ctl.grpid]
      if sid and switchers[sid] then
        if not switchers[sid].extendpos then
          sid = Switcher_GetTopLevelSwitcher(sid)
        end
        if sid then
          local extpos = switchers[sid].extendpos
          l[extpos] = math.min(l[extpos],ctl.x)
          r[extpos] = math.max(r[extpos],ctl.x+ctl.stretchw)
          t[extpos] = math.min(t[extpos],ctl.y)
          b[extpos] = math.max(b[extpos],ctl.y+ctl.stretchh)
          if not extgfx[extpos] then
            extgfx[extpos] = {}
          end
          extgfx[extpos][#extgfx[extpos]+1] = ctl
          ctl.ext_dx = ctl.x-extctls[extpos].ctl_sw.x
          ctl.ext_dy = ctl.y-extctls[extpos].ctl_sw.y
        end
      end
    end

    return l,r,t,b,swl,swr,swt,swb, extctls, extgfx
  end

  function Switcher_ContentsLocInfo_all(extid)

    local l,r,t,b = {},{},{},{}
    local swl, swr, swt, swb = {},{},{},{}

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local gfxx = strips[strip][page].graphics

    local gids = {}
    for i = 1, #ctls do
      if ctl.ctlcat == ctlcats.switcher and ctl.extendmode == true and (extid == nil or ctl.extendid == extid) then
        for i = 1, #switchers[switchid].grpids do
          gids[switchers[switchid].grpids[i].id] = i
          l[i],r[i],t[i],b[i] = lvar.maxdim,0,lvar.maxdim,0
        end
      end
    end

    for i = 1, #ctls do

      local ctl = ctls[i]
      local sid = gids[ctl.grpid]
      if sid then
        l[sid] = math.min(l[sid], ctl.xsc)
        r[sid] = math.max(r[sid], ctl.xsc+ctl.wsc)
        t[sid] = math.min(t[sid], ctl.ysc)
        b[sid] = math.max(b[sid], ctl.ysc+ctl.hsc)
      end

      if ctl.switcherid == switchid then
        swl[switchid] = ctl.x
        swr[switchid] = ctl.x+ctl.w
        swt[switchid] = ctl.y
        swb[switchid] = ctl.y+ctl.ctl_info.cellh
      end
    end

    for i = 1, #gfxx do

      local ctl = gfxx[i]
      local sid = gids[ctl.grpid]
      if sid then
        l[sid] = math.min(l[sid],ctl.x)
        r[sid] = math.max(r[sid],ctl.x+ctl.stretchw)
        t[sid] = math.min(t[sid],ctl.y)
        b[sid] = math.max(b[sid],ctl.y+ctl.stretchh)
      end

    end

    return l,r,t,b,swl,swr,swt,swb
  end

  function Switcher_Ext_GetMaxPos(extid)

    local pos = 0
    for i = 1, #switchers do
      if switchers[i].switchmode == 1 and switchers[i].extendmode == true and switchers[i].extendid == extid then
        pos = math.max(switchers[i].extendpos or 0, pos)
      end

    end
    return pos

    --[[local strip = tracks[track_select].strip
    local ctls = strip[strip][page].controls
    for i = 1, #ctls do

      local ctl = ctls[i]
      if ctl.


    end]]

  end

  function Switcher_CreatePageButtons(switcher)

    local ctls = strips[tracks[track_select].strip][page].controls
    local switchid = ctls[switcher].switcherid

    if switchid then
      local x = ctls[switcher].xsc
      local y = ctls[switcher].ysc
      local h = ctls[switcher].hsc
      scale_select = ctls[switcher].scale
      knob_select = ctls[switcher].knob_select

      local grpids = switchers[switchid].grpids
      if #grpids > 0 then
        local bc = 0
        for g = 1, #grpids do

          if not SwitcherPage_CheckExists(switchid, grpids[g].id) then
            y = y + h + 1

            Switcher_AddPageButton(switcher, switchid,g,x,y)
          end
        end
        SetCtlBitmapRedraw()
        lupd.update_gfx = true

      end
    end
  end

  function SwitcherPage_CheckExists(switchid, grpid)

    local ctls = strips[tracks[track_select].strip][page].controls
    for i = 1, #ctls do
      if ctls[i].ctlcat == ctlcats.switcher_pagesel then
        if ctls[i].param == grpid then
          return true
        end
      end
    end

  end

  function Switcher_AddPageButton(switcher, switchid,grpididx, x, y)

      local sctl = strips[tracks[track_select].strip][page].controls[switcher]
      local grpids = switchers[switchid].grpids
      local strip = tracks[track_select].strip
      local ctlnum = #strips[strip][page].controls + 1
      local w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
      strips[strip][page].controls[ctlnum] = {c_id = GenID(),
                                              ctlcat = ctlcats.switcher_pagesel,
                                              switcher = sctl.switcher,
                                              fxname='Strip Switcher Page Button',
                                              fxguid=nil,
                                              fxnum=nil,
                                              fxfound = true,
                                              param = grpids[grpididx].id,
                                              param_info = {paramname = grpids[grpididx].name,
                                                            paramidx = grpididx},
                                              ctltype = 2,
                                              knob_select = knob_select,
                                              ctl_info = {fn = ctl_files[knob_select].fn,
                                                          frames = ctl_files[knob_select].frames,
                                                          imageidx = ctl_files[knob_select].imageidx,
                                                          cellh = ctl_files[knob_select].cellh},
                                              x = x,
                                              y = y,
                                              w = w,
                                              poslock = false,
                                              scale = scale_select,
                                              xsc = x + math.floor(w/2 - (w*scale_select)/2),
                                              ysc = y + math.floor(ctl_files[knob_select].cellh/2 - (ctl_files[knob_select].cellh*scale_select)/2),
                                              wsc = w*scale_select,
                                              hsc = ctl_files[knob_select].cellh*scale_select,
                                              show_paramname = show_paramname,
                                              show_paramval = false,
                                              ctlname_override = '',
                                              textcol = textcol_select,
                                              textoff = 1,
                                              textoffval = textoffval_select,
                                              textoffx = textoff_selectx,
                                              textoffvalx = textoffval_selectx,
                                              textsize = textsize_select,
                                              textsizev = textsizev_select,
                                              textcolv = textcolv_select,
                                              enabledefval = enabledefval_select,
                                              val = 0,
                                              defval = 0,
                                              maxdp = maxdp_select,
                                              cycledata = {statecnt = 0,val = 0,mapptof = false,draggable = false,spread = false, {}},
                                              xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5},
                                              membtn = {state = false,
                                                        mem = nil},
                                              switcherid = switchid,
                                              id = nil,
                                              grpid = sctl.grpid,
                                              tracknum = nil,
                                              trackguid = nil,
                                              scalemode = 8,
                                              framemode = 1,
                                              horiz = horiz_select,
                                              poslock = false,
                                              bypassbg_c = bypass_bgdraw_c_select,
                                              bypassbg_n = bypass_bgdraw_n_select,
                                              bypassbg_v = bypass_bgdraw_v_select,
                                              knobsens = table.copy(settings_defknobsens),
                                              clickthrough = clickthrough_select,
                                              eqgraph = def_graph
                                             }

  end

  function Switcher_AddPage(switcher)

    local grpid = GenID()
    local ctls = strips[tracks[track_select].strip][page].controls
    local switchid = ctls[switcher].switcherid
    local sw_cur = #switchers[switchid].grpids+1
    switchers[switchid].grpids[sw_cur] = {}
    switchers[switchid].grpids[sw_cur].id = grpid
    switchers[switchid].grpids[sw_cur].name = 'Page '..sw_cur

    switchers[switchid].current = grpid

    local ctl = ctls[switcher]
    if ctl then
      ctl.param_info.paramname = string.format('%i',sw_cur)..': '..switchers[switchid].grpids[sw_cur].name
    end

    lupd.update_gfx = true
    lupd.update_bg = true
    SetCtlBitmapRedraw()

    return grpid
  end

  function Switcher_Check2(strip)
    DBGOut('*** Switcher_Check2 ***')
    if strips then

      local ctlselbkp
      if ctl_select then
        ctlselbkp = table.copy(ctl_select)
      end
      for s = 1, #strips do
        if not strip or strip == s then
          for p = 1, lvar.maxpage do
            if strips[s] and strips[s][p] then
              if strips[s][p].controls and #strips[s][p].controls > 0 then

                gfx2_select = nil
                gfx3_select = nil
                gfx4_select = nil
                gfx4_selectidx = nil
                ctl_select = {}

                for c = 1, #strips[s][p].controls do
                  local ctl = strips[s][p].controls[c]
                  if ctl.ctlcat == ctlcats.switcher then

                    if ctl.switcherid == nil then

                      local cc = #ctl_select+1
                      ctl_select[cc] = {ctl = c}
                      DBGOut('Deleting switcher control '..c)

                    end

                  end
                end

                if #ctl_select > 0 then
                  DeleteSelectedCtls(false,true,strips[s].track.tracknum)
                  ctl_select = {}
                end
              end
            end
          end
        end
      end
      if ctlselbkp then
        ctl_select = table.copy(ctlselbkp)
      else
        ctl_select = nil
      end
    end
    DBGOut('*** Exit Switcher_Check2 ***')

  end

  function Switcher_Check()

    local swidtab = {}
    local nstab = {}
    local scnt = #switchers
    local nscnt
    local dflag = false
    for s = 1, scnt do
      if switchers[s].deleted ~= true then
        nscnt = #nstab+1
        nstab[nscnt] = switchers[s]
        swidtab[s] = nscnt
      else
        dflag = true
      end
    end
    if dflag == true then

      switchers = nstab

      for s = 1, #switchers do
        if switchers[s].parent then
          local swid = switchers[s].parent.switcherid
          switchers[s].parent.switcherid = swidtab[swid]
        end
      end
      if strips then
        for s = 1, #strips do
          for p = 1, lvar.maxpage do
            if strips[s] and strips[s][p] then
              if strips[s][p].controls and #strips[s][p].controls > 0 then
                for c = 1, #strips[s][p].controls do
                  local ctl = strips[s][p].controls[c]
                  if ctl.switcher then
                    ctl.switcher = swidtab[ctl.switcher]
                  end
                  if ctl.switcherid then
                    ctl.switcherid = swidtab[ctl.switcherid]
                  end
                  
                  if ctl.ctltype == 4 then
                    local cd = ctl.cycledata
                    if #cd > 0 then
                      for cdidx = 1, #cd do
                        if cd[cdidx].tsp then
                          if swidtab[cd[cdidx].tsp.swid] then
                            cd[cdidx].tsp.swid = swidtab[cd[cdidx].tsp.swid]
                          else
                            cd[cdidx].tsp = nil
                          end
                        end
                      end
                    end
                  end
                end
              end
              if strips[s][p].graphics and #strips[s][p].graphics > 0 then
                for c = 1, #strips[s][p].graphics do
                  local ctl = strips[s][p].graphics[c]
                  if ctl.switcher then
                    ctl.switcher = swidtab[ctl.switcher]
                  end
                end
              end
            end
          end
        end
      end
    end

    Switcher_Check2()
  end

  function Switcher_CheckExt(extid, extpos)

    for s = 1, #switchers do
      if switchers[s].switchmode == 1 and switchers[s].extendmode == true then
        if switchers[s].extendid == extid then
          if switchers[s].extendpos > extpos then
            switchers[s].extendpos = switchers[s].extendpos -1
          end
        end
      end
    end

  end

  function Switchers_Clean()

    local newswitchtab = {}
    local newswitchtab_idx = {}
    local swtab = {}
    for s = 1, #strips do
      for p = 1, lvar.maxpage do
        if strips[s][p] then
          local ctls = strips[s][p].controls
          for c = 1, #ctls do
            swtab[ctls[c].switcherid or -1] = true
            swtab[ctls[c].switcher or -1] = true
          end
          local gfxx = strips[s][p].graphics
          for g = 1, #gfxx do
            swtab[gfxx[g].switcher or -1] = true
          end
        end
      end
    end
    if lvar.stripstore then
      for a, b in pairs(lvar.stripstore) do
        local ctls = b.controls
        for c = 1, #b.controls do
          swtab[ctls[c].switcherid or -1] = true
          swtab[ctls[c].switcher or -1] = true
        end
        local gfxx = b.graphics
        for g = 1, #gfxx do
          swtab[gfxx[g].switcher or -1] = true
        end
      end
    end

    local delcnt = 0
    local nstcnt = 1
    for s = 1, #switchers do
      if swtab[s] then
        newswitchtab[nstcnt] = switchers[s]
        newswitchtab_idx[s] = nstcnt
        nstcnt = nstcnt + 1
      else
        delcnt = delcnt + 1
      end
    end

    for s = 1, #newswitchtab do
      if newswitchtab[s].parent and newswitchtab[s].parent.switcherid then
        newswitchtab[s].parent.switcherid = newswitchtab_idx[newswitchtab[s].parent.switcherid]
      end
    end

    for s = 1, #strips do
      for p = 1, lvar.maxpage do

        if strips[s][p] then
          local ctls = strips[s][p].controls
          for c = 1, #ctls do
            local ctl = ctls[c]
            if ctl.switcherid then
              ctl.switcherid = newswitchtab_idx[ctl.switcherid]
            end
            if ctl.switcher then
              ctl.switcher = newswitchtab_idx[ctl.switcher]
            end
            
            if ctl.ctltype == 4 then
              local cd = ctl.cycledata
              if #cd > 0 then
                for cdidx = 1, #cd do
                  if cd[cdidx].tsp then
                    if newswitchtab_idx[cd[cdidx].tsp.swid] then
                      cd[cdidx].tsp.swid = newswitchtab_idx[cd[cdidx].tsp.swid]
                    else
                      cd[cdidx].tsp = nil
                    end
                  end
                end
              end
            end
          end
          local gfxx = strips[s][p].graphics
          for g = 1, #gfxx do
            if gfxx[g].switcher then
              gfxx[g].switcher = newswitchtab_idx[gfxx[g].switcher]
            end
          end
          local pop = strips[s][p].pop
  
          if pop then
            local popidx = {}
            for i = 1, #pop do
              pop[i].swid = newswitchtab_idx[pop[i].swid]
              if pop[i].swid then
                popidx[pop[i].swid] = i
              end
            end
            strips[s][p].popidx = popidx
          end
        end
      end
    end
    if lvar.stripstore then
      for a, b in pairs(lvar.stripstore) do
        local ctls = b.controls
        for c = 1, #b.controls do
          local ctl = ctls[c]
          if ctl.switcherid then
            ctl.switcherid = newswitchtab_idx[ctl.switcherid]
          end
          if ctl.switcher then
            ctl.switcher = newswitchtab_idx[ctl.switcher]
          end

          if ctl.ctltype == 4 then
            local cd = ctl.cycledata
            if #cd > 0 then
              for cdidx = 1, #cd do
                if cd[cdidx].tsp then
                  if newswitchtab_idx[cd[cdidx].tsp.swid] then
                    cd[cdidx].tsp.swid = newswitchtab_idx[cd[cdidx].tsp.swid]
                  else
                    cd[cdidx].tsp = nil
                  end
                end
              end
            end
          end
        end
        local gfxx = b.graphics
        for g = 1, #gfxx do
          if gfxx[g].switcher then
            gfxx[g].switcher = newswitchtab_idx[gfxx[g].switcher]
          end
        end
        local pop = b.pop
        if pop then
          local popidx = {}
          for i = 1, #pop do
            pop[i].swid = newswitchtab_idx[pop[i].swid]
            if pop[i].swid then
              popidx[pop[i].swid] = i
            end
          end
          b.popidx = popidx
        end
      end
    end

    --DBG('Old: '..#switchers..'  New:'..#newswitchtab)
    switchers = newswitchtab

    --ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
    SetCtlBitmapRedraw(true)
  end

  function DeleteFXByGUID(track, guid)

    if reaper.APIExists('TrackFX_Delete') == true then
      local cnt = reaper.TrackFX_GetCount(track)
      for f = 0, cnt-1 do
        if reaper.TrackFX_GetFXGUID(track, f) == guid then
          reaper.TrackFX_Delete(track,f)
          break
        end
      end
    end
  end

  function Switcher_DeleteExt(switchid, preservefx, fxdata)

    if not switchers[switchid] then return end

    local stripids, firstfxslot = Switcher_GetStripIDs(switchid)
    for i = 1, #stripids do
      if preservefx then
        DeleteStrip(stripids[i],false,true)
      else
        DeleteStrip(stripids[i],true,true)
      end
    end

    local extid = switchers[switchid].extendid

    local tx, ty = Switchers_Ext_GetTop(extid)

    local c = Switchers_FindCtl(switchid)
    local ctl = strips[tracks[track_select].strip][page].controls[c]
    local extpos = switchers[switchid].extendpos

    if lvar.livemode == 2 then
      if not preservefx then
        local fxguids = Switchers_GetFXGUIDs(extid, extpos)

        local track = GetTrack(lvar.dynamicmode_trn)
        if track and fxguids then
          for f = 1, #fxguids do
            DeleteFXByGUID(track, fxguids[f])
          end
        end
      end
    else
      if ctl.fxnum then
        local rtrn, rtrguid, rfxnum, rfxguid = FindInsertFX(ctl.fxguid, ctl.tracknum or tracks[track_select].tracknum, ctl.fxnum)
        if reaper.APIExists('TrackFX_Delete') == true and rfxnum then
          local tr = GetTrack(rtrn)
          reaper.TrackFX_Delete(tr,rfxnum)
        end
      end
    end

    local pop = strips[tracks[track_select].strip][page].pop
    if pop then
      local npop = {}
      local ncnt = 1
      local npopidx = {}
      for p = 1, #pop do
        local swid = pop[p].swid
        if swid ~= switchid then

          if swid > switchid then
            npop[ncnt] = pop[p]
            npop[ncnt].swid = swid-1
            npopidx[swid-1] = ncnt
            ncnt = ncnt + 1
          else
            npop[ncnt] = pop[p]
            npopidx[swid] = ncnt
            ncnt = ncnt + 1
          end
        end

      end
      strips[tracks[track_select].strip][page].pop = npop
      strips[tracks[track_select].strip][page].popidx = npopidx
    end

    ctl_select = {}
    ctl_select[1] = {}
    ctl_select[1].ctl = c
    gfx2_select = nil
    gfx3_select = nil
    gfx4_select = nil

    local delflag = true
    if lvar.livemode == 2 then
      delflag = nil
    end
    DeleteSelectedCtls(delflag, true)
    Strip_ReposSwitcher_Ext(extid, 1, tx, ty, true)

    lupd.update_gfx = true
    lupd.update_bg = true
    SetCtlBitmapRedraw(true)
    reaper.MarkProjectDirty(0)

  end

  function Switcher_Delete(switcher, removenils, ccnt, gcnt)

    local ctls = strips[tracks[track_select].strip][page].controls
    local gctls = strips[tracks[track_select].strip][page].graphics
    local switchid = ctls[switcher].switcherid
    if switchid then
      if ccnt == nil then
        ccnt = #ctls
      end
      if gcnt == nil then
        gcnt = #gctls
      end
      for c = 1, ccnt do
        local ctl = ctls[c]
        if ctl and ctl.switcher == switchid then
          if ctl.ctlcat == ctlcats.switcher and c ~= switcher then
            Switcher_Delete(c, false, ccnt, gcnt)
          end
          ctls[c] = nil
        elseif ctl and ctl.ctlcat == ctlcats.switcher_pagesel and ctl.switcherid == switchid then
          ctls[c] = nil
        end
      end
      for c = 1, gcnt do
        local ctl = gctls[c]
        if ctl and ctl.switcher == switchid then
          gctls[c] = nil
        end
      end

      local extid, extpos, repos
      if switchers[switchid].switchmode == 1 and switchers[switchid].extendmode == true then
        extid = switchers[switchid].extendid
        extpos = switchers[switchid].extendpos
        Switcher_CheckExt(extid, extpos)
        repos = true
      end

      switchers[switchid].grpids = {}
      switchers[switchid].current = -1
      switchers[switchid].parent = nil
      switchers[switchid].deleted = true

      if removenils == true then
        local tbl = {}
        for i = 1, ccnt do
          if ctls[i] ~= nil then
            table.insert(tbl, ctls[i])
          end
        end
        strips[tracks[track_select].strip][page].controls = tbl

        local tbl = {}
        for i = 1, gcnt do
          if gctls[i] ~= nil then
            table.insert(tbl, gctls[i])
          end
        end
        strips[tracks[track_select].strip][page].graphics = tbl
        CheckDataTables(nil, true)

        if repos == true then
          Strip_ReposSwitcher_Ext(extid, 1)
        end

        ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      end

    end

  end

  function Switcher_DeletePage(switchid)
    local ctls = strips[tracks[track_select].strip][page].controls
    --local switchid = ctls[switcher].switcherid
    if switchid then
      local grpid = switchers[switchid].current
      switchers[switchid].current = -1
      local gidcnt = #switchers[switchid].grpids
      if gidcnt > 0 then
        local tbl = {}
        for g = 1, gidcnt do
          if switchers[switchid].grpids[g].id ~= grpid then
            table.insert(tbl, switchers[switchid].grpids[g])
          end
        end
        switchers[switchid].grpids = tbl
      end

      local ctls = strips[tracks[track_select].strip][page].controls
      local gctls = strips[tracks[track_select].strip][page].graphics
      local cnt = #ctls
      local gcnt = #gctls
      for c = 1, cnt do
        if ctls[c] and ctls[c].switcher == switchid and ctls[c].grpid == grpid then
          if ctls[c].ctlcat == ctlcats.switcher then
            Switcher_Delete(c,false,cnt,gcnt)
          end
          ctls[c] = nil
        elseif ctls[c] and ctls[c].ctlcat == ctlcats.switcher_pagesel and ctls[c].switcherid == switchid and ctls[c].param == grpid then
          ctls[c] = nil
        end
      end
      for c = 1, gcnt do
        if gctls[c] and gctls[c].switcher == switchid and gctls[c].grpid == grpid then
          gctls[c] = nil
        end
      end

      local tbl = {}
      for i = 1, cnt do
        if ctls[i] ~= nil then
          table.insert(tbl, ctls[i])
        end
      end
      strips[tracks[track_select].strip][page].controls = tbl
      local tbl = {}
      for i = 1, gcnt do
        if gctls[i] ~= nil then
          table.insert(tbl, gctls[i])
        end
      end
      strips[tracks[track_select].strip][page].graphics = tbl

      if switchers[switchid].grpids and #switchers[switchid].grpids > 0 then
        switchers[switchid].current = switchers[switchid].grpids[1].id
        local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
        if ctl then
          ctl.param_info.paramname = string.format('%i',1)..': '..switchers[switchid].grpids[1].name
        end
      else
        switchers[switchid].current = -1
        local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
        if ctl then
          ctl.param_info.paramname = 'No pages'
        end
      end

      CheckDataTables(nil, true)
      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()

    end
  end

  function RCM_AddProgram()

    local retval, retcsv = reaper.GetUserInputs('Add RCM Program',4,'Program Name,Bank MSB,Bank LSB,Program Change,extrawidth=60',',0,0,0')
    if retval == true then

      local vals = split2(retcsv,',')
      if vals[1] and vals[1] ~= '' and tonumber(vals[2]) and tonumber(vals[3]) and tonumber(vals[4]) then
        local msb = F_limit(tonumber(vals[2]),0,127)
        local lsb = F_limit(tonumber(vals[3]),0,127)
        local prog = F_limit(tonumber(vals[4]),0,127)

        local rctl = strips[tracks[track_select].strip][page].controls[rcm_select]
        if rctl.rcmdata == nil then
          rctl.rcmdata = {}
        end
        rctl.rcmdata[#rctl.rcmdata+1] = {name = vals[1],
                                         msb = msb,
                                         lsb = lsb,
                                         prog = prog}

      else
        OpenMsgBox(1,'Invalid value.',1)
      end
    end

  end

  function RCM_AddProgramNeb()

    local retval, retcsv = reaper.GetUserInputs('Add RCM Program',2,'Program Name,Program ID,extrawidth=60',',0')
    if retval == true then

      local vals = split2(retcsv,',')
      if vals[1] and vals[1] ~= '' and tonumber(vals[2]) then
        local msb = F_limit(tonumber(math.floor(math.floor(vals[2]/100) / 128)),0,127)
        local lsb = F_limit(tonumber(math.floor(vals[2]/100) % 128),0,127)
        local prog = F_limit(tonumber(vals[2] % 100),0,127)

        local rctl = strips[tracks[track_select].strip][page].controls[rcm_select]
        if rctl.rcmdata == nil then
          rctl.rcmdata = {}
        end
        local datacnt = #rctl.rcmdata+1
        rctl.rcmdata[datacnt] = {name = vals[1],
                                         msb = msb,
                                         lsb = lsb,
                                         prog = prog}
        if neb_scanboot_tab then
          rctl.rcmdata[datacnt].nebfn = neb_scanboot_tab[tonumber(vals[2])]
        end
      else
        OpenMsgBox(1,'Invalid value.',1)
      end
    end

  end

  function RCM_EditProgram(pn)

    local rctl = strips[tracks[track_select].strip][page].controls[rcm_select]
    if rctl and rctl.rcmdata and rctl.rcmdata[pn] then
      local defvals = rctl.rcmdata[pn].name ..','.. rctl.rcmdata[pn].msb ..','..rctl.rcmdata[pn].lsb ..','.. rctl.rcmdata[pn].prog
      local retval, retcsv = reaper.GetUserInputs('Edit RCM Program',4,'Program Name,Bank MSB,Bank LSB,Program Change,extrawidth=60',defvals)
      if retval == true then

        local vals = split2(retcsv,',')
        if vals[1] and vals[1] ~= '' and tonumber(vals[2]) and tonumber(vals[3]) and tonumber(vals[4]) then
          local msb = F_limit(tonumber(vals[2]),0,127)
          local lsb = F_limit(tonumber(vals[3]),0,127)
          local prog = F_limit(tonumber(vals[4]),0,127)

          rctl.rcmdata[pn] = {name = vals[1],
                               msb = msb,
                               lsb = lsb,
                               prog = prog}

        else
          OpenMsgBox(1,'Invalid value.',1)
        end
      end
    end
  end

  function RCM_EditProgramNeb(pn)

    local rctl = strips[tracks[track_select].strip][page].controls[rcm_select]
    if rctl and rctl.rcmdata and rctl.rcmdata[pn] then
      local defvals = rctl.rcmdata[pn].name ..','.. rctl.rcmdata[pn].msb * (128*100) + rctl.rcmdata[pn].lsb*100 + rctl.rcmdata[pn].prog
      local retval, retcsv = reaper.GetUserInputs('Edit RCM Program',2,'Program Name,Program ID,extrawidth=60',defvals)
      if retval == true then

        local vals = split2(retcsv,',')
        if vals[1] and vals[1] ~= '' and tonumber(vals[2]) then
          local msb = F_limit(tonumber(math.floor(math.floor(vals[2]/100) / 128)),0,127)
          local lsb = F_limit(tonumber(math.floor(vals[2]/100) % 128),0,127)
          local prog = F_limit(tonumber(vals[2] % 100),0,127)

          rctl.rcmdata[pn] = {name = vals[1],
                               msb = msb,
                               lsb = lsb,
                               prog = prog}
          if neb_scanboot_tab then
            rctl.rcmdata[pn].nebfn = neb_scanboot_tab[tonumber(vals[2])]
          end

        else
          OpenMsgBox(1,'Invalid value.',1)
        end
      end
    end
  end

  function RCM_Set(rcm_select, v)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[rcm_select]
    if ctl and ctl.rcmdata and ctl.rcmdata[v] then

      if ctl.fxfound == true then

        local track
        if ctl.tracknum == nil then
          track = GetTrack(strips[strip].track.tracknum)
        else
          track = GetTrack(ctl.tracknum)
        end
        if track then
          local fxnum = ctl.fxnum
          if fxnum == nil then return end
          local pcnt = reaper.TrackFX_GetNumParams(track, fxnum)
          local p_byp = pcnt-2
          local p_msb = 0
          local p_lsb = 1
          local p_prog = 2
          local p_bken = 13

          --bypass
          --reaper.TrackFX_SetParam(track, fxnum, p_byp, 1)
          reaper.TrackFX_SetParam(track, fxnum, p_bken, 1)
          reaper.TrackFX_SetParam(track, fxnum, p_msb, ctl.rcmdata[v].msb/127)
          reaper.TrackFX_SetParam(track, fxnum, p_lsb, ctl.rcmdata[v].lsb/127)
          reaper.TrackFX_SetParam(track, fxnum, p_prog, ctl.rcmdata[v].prog/127)
          os.sleep(0.1)
          reaper.TrackFX_SetParam(track, fxnum, p_bken, 0)
          --reaper.TrackFX_SetParam(track, fxnum, p_byp, 1)

          ctl.val = v
          ctl.dirty = true
          SetCtlDirty(rcm_select)
          lupd.update_ctls = true

          if ctl.rcmrefresh and ctl.rcmrefresh.guid then
            if rcmrefreshtimer == nil then
              rcmrefreshtimer = {}
            end
            local rcmrtcnt = #rcmrefreshtimer+1
            rcmrefreshtimer[rcmrtcnt] = {time = reaper.time_precise() + (ctl.rcmrefresh.delay),
                                                   guid = ctl.rcmrefresh.guid,
                                                   tracknum = tracks[track_select].tracknum,
                                                   setvals = ctl.rcmrefresh.setvals}
            rcmrefreshtimercount = rcmrefreshtimercount + 1
            if ctl.rcmrefresh.setvals then
              local guid = ctl.rcmrefresh.guid
              for i = 1, #strips[strip][page].controls do
                local sctl = strips[strip][page].controls[i]
                if sctl.fxguid == guid then

                  if sctl.ctlcat == ctlcats.fxparam then

                    if rcmrefreshtimer[rcmrtcnt].ctlvals == nil then
                      rcmrefreshtimer[rcmrtcnt].ctlvals = {}
                    end
                    rcmrefreshtimer[rcmrtcnt].ctlvals[#rcmrefreshtimer[rcmrtcnt].ctlvals+1] = {val = sctl.val,
                                                                                               strip = strip,
                                                                                               page = page,
                                                                                               ctl = i}
                  end
                end
              end

            end
          end
        end
      end
    end

  end

  function RCMMenu_RB()

    local ctl = strips[tracks[track_select].strip][page].controls[rcm_select]

    if ctl then
      if mode == 0 then

        if ctl.rcmdata and #ctl.rcmdata > 0 then

          if not ddlist then
            local ddtab = {idx = 1, x = mouse.mx, y = mouse.my, w = 100, h = 100, items = {}, wpad = 40}

            local mstr = ''
            for i = 1, #ctl.rcmdata do
              ddtab.items[i] = ctl.rcmdata[i].name
            end

            OpenDropDown(1, ddtab, true)
          end
        end

      elseif mode == 1 then

        local mstr = 'Add Program'

        if ctl.rcmdata and #ctl.rcmdata > 0 then

          mstr = mstr .. '|>Edit Program'
          for i = 1, #ctl.rcmdata do

            if i < #ctl.rcmdata then
              mstr = mstr..'|'..ctl.rcmdata[i].name
            else
              mstr = mstr..'|<'..ctl.rcmdata[i].name
            end
          end
        end

        mstr = mstr ..'||Add Program (Nebula)'

        if ctl.rcmdata and #ctl.rcmdata > 0 then
          mstr = mstr .. '|>Edit Program (Nebula)'
          for i = 1, #ctl.rcmdata do

            if i < #ctl.rcmdata then
              mstr = mstr..'|'..ctl.rcmdata[i].name
            else
              mstr = mstr..'|<'..ctl.rcmdata[i].name
            end
          end
          if neb_scanboot_fn then
            mstr = mstr .. '|Update all program IDs (Nebula)'
          else
            mstr = mstr .. '|#Update all program IDs (Nebula)'
          end
          mstr = mstr .. '||>Remove Program'
          for i = 1, #ctl.rcmdata do

            if i < #ctl.rcmdata then
              mstr = mstr..'|'..ctl.rcmdata[i].name
            else
              mstr = mstr..'|<'..ctl.rcmdata[i].name
            end
          end

        end

        local edprog_off = 1
        local edprogN_off = 2
        local remprog_off = 3

        if ctl.rcmdata then
          edprog_off = 1+#ctl.rcmdata
          edprogN_off = edprog_off+1 + #ctl.rcmdata
          remprog_off = edprogN_off + #ctl.rcmdata + 1
        end

        local delcnt = 10
        if ctl.rcmrefresh and ctl.rcmrefresh.guid then
          mstr = mstr .. '||>!Refresh Plugin|>Delay'
        else
          mstr = mstr .. '||>Refresh Plugin|>Delay'
        end
        for i = 1, delcnt do
          if i == delcnt then
            mstr = mstr .. '|<'
          else
            mstr = mstr .. '|'
          end
          if ctl.rcmrefresh and ctl.rcmrefresh.delay == i then
            mstr = mstr ..'!'..i..' sec'
          else
            mstr = mstr ..i..' sec'
          end
        end
        mstr = mstr..'|>Plugin'
        local track = GetTrack(tracks[track_select].tracknum)
        local fxcnt = reaper.TrackFX_GetCount(track)
        for f = 0, fxcnt-1 do
          local _, fxname = reaper.TrackFX_GetFXName(track,f,'')
          local guid = reaper.TrackFX_GetFXGUID(track,f)
          mstr = mstr .. '|'
          if f == fxcnt-1 then
            mstr = mstr .. '<'
          end
          if ctl.rcmrefresh and ctl.rcmrefresh.guid == guid then
            mstr = mstr .. '!'
          end
          mstr = mstr..fxname
        end
        if ctl.rcmrefresh and ctl.rcmrefresh.setvals == true then
          mstr = mstr .. '|!Retain Values'
        else
          mstr = mstr .. '|Retain Values'
        end
        mstr = mstr .. '||<Clear'

        gfx.x, gfx.y = mouse.mx, mouse.my
        local res = OpenMenu(mstr)

        if res > 0 then
          if res == 1 then
            RCM_AddProgram()

          elseif res > 1 and res <= edprog_off then

            RCM_EditProgram(res-1)

          elseif res == edprog_off+1 then

            RCM_AddProgramNeb()

          elseif res > edprog_off+1 and res <= edprogN_off then

            RCM_EditProgramNeb(res-(edprog_off+1))

          elseif res == edprogN_off+1 then

            --RCM_Neb_UpdateProgIDs(strips[tracks[track_select].strip][page].controls)
            RCM_Neb_UpdateAllProgIDs()

          elseif res > edprogN_off+1 and res <= remprog_off then

            local rcnt = #ctl.rcmdata
            ctl.rcmdata[res-(edprogN_off)] = nil
            ctl.rcmdata = Table_RemoveNils(ctl.rcmdata, rcnt)

          elseif res > remprog_off and res <= remprog_off+delcnt then
            if ctl.rcmrefresh == nil then
              ctl.rcmrefresh = {}
            end
            ctl.rcmrefresh.delay = res-remprog_off

          elseif res > remprog_off+delcnt and res <= remprog_off+delcnt+fxcnt then
            local fxnum = res - (remprog_off+delcnt+1)
            if ctl.rcmrefresh == nil then
              ctl.rcmrefresh = {delay = 1}
            end
            ctl.rcmrefresh.guid = reaper.TrackFX_GetFXGUID(track,fxnum)
          elseif res == remprog_off+delcnt+fxcnt+1 then
            if ctl.rcmrefresh == nil then
              ctl.rcmrefresh = {delay = 1}
            end
            if ctl.rcmrefresh.setvals == nil or ctl.rcmrefresh.setvals == false then
              ctl.rcmrefresh.setvals = true
            else
              ctl.rcmrefresh.setvals = nil
            end
          elseif res == remprog_off+delcnt+fxcnt+2 then
            ctl.rcmrefresh = nil
          end
        end

      end
    end
  end


  function num2note(num)

    local i = (num % 12)+1
    local n = math.floor((num)/12)-1
    return lvar.noteletters_tab[i]..n

  end

  function NoteValueOffsetMenu(f)

    local vo = ''
    for i = 0, 127 do
      vo = vo .. '|'
      if i == f then
        vo = vo .. '!'
      end
      if i == 127 then
        vo = vo .. '<'
      end
      vo = vo.. string.format('%i',i)..'  -  '..num2note(i)
    end
    gfx.x, gfx.y = mouse.mx, mouse.my
    local res = OpenMenu(vo)
    if res > 0 then
      lbx_midilrnoff = res-1
    end

  end

  function SBMenu_RB()
    if lvar.stripbrowser.select then
      if lvar.stripbrowser.favs == true or lvar.stripbrowser.search == true then
        mstr = 'Edit Strip||#Associate All Strips With Plugins||Strip: Enable Quick Load|Strip: Disable Quick Load'
      else
        mstr = 'Edit Strip||Associate All Strips With Plugins||Strip: Enable Quick Load|Strip: Disable Quick Load'
      end
      gfx.x = mouse.mx
      gfx.y = mouse.my
      local res = gfx.showmenu(mstr)
      if res > 0 then
        if res == 1 then
          if (lvar.stripbrowser.search == true and strip_search[lvar.stripbrowser.select+1]) then
            local sfn = paths.strips_path..strip_search[lvar.stripbrowser.select+1]
            if reaper.file_exists(sfn) then
              DM_OpenEditMode(nil, nil, sfn)
            end
          elseif (lvar.stripbrowser.favs == true and strip_favs[lvar.stripbrowser.select+1]) then
            local sfn = paths.strips_path..strip_favs[lvar.stripbrowser.select+1]
            if reaper.file_exists(sfn) then
              DM_OpenEditMode(nil, nil, sfn)
            end
          elseif (lvar.stripbrowser.favs ~= true and strip_files[lvar.stripbrowser.select]) then
            local sfn = paths.strips_path..strip_folders[stripfol_select].fn..'/'..strip_files[lvar.stripbrowser.select].fn
            if reaper.file_exists(sfn) then
              DM_OpenEditMode(nil, nil, sfn)
            end
          end
        elseif res == 2 then
          local sfcnt = #strip_files + 1
          for i = 0, sfcnt-1 do
            Strip_SetPlugDef(i, stripfol_select, true)
            Save_PlugDefs()
          end
        elseif res == 3 then
          if (lvar.stripbrowser.favs == true and strip_favs[lvar.stripbrowser.select+1]) then
            local sfn = strip_favs[lvar.stripbrowser.select+1]
            if SetStripQuickLoadSetting(sfn, true) then
              OpenMsgBox(1,'Quick load enabled.',1)
            end
          elseif (lvar.stripbrowser.favs ~= true and strip_files[lvar.stripbrowser.select]) then
            local sfn = strip_folders[stripfol_select].fn..'/'..strip_files[lvar.stripbrowser.select].fn
            if SetStripQuickLoadSetting(sfn, true) then
              OpenMsgBox(1,'Quick load enabled.',1)
            end
          end
        elseif res == 4 then
          if (lvar.stripbrowser.favs == true and strip_favs[lvar.stripbrowser.select+1]) then
            local sfn = strip_favs[lvar.stripbrowser.select+1]
            if SetStripQuickLoadSetting(sfn, false) then
              OpenMsgBox(1,'Quick load disabled.',1)
            end
          elseif (lvar.stripbrowser.favs ~= true and strip_files[lvar.stripbrowser.select]) then
            local sfn = strip_folders[stripfol_select].fn..'/'..strip_files[lvar.stripbrowser.select].fn
            if SetStripQuickLoadSetting(sfn, false) then
              OpenMsgBox(1,'Quick load disabled.',1)
            end
          end
        end
      end
    end
  end

  function StripModuleList(fxmod)

    local cnt = 1
    local idxtab = {}
    local ddtab = {}
    local mstr = ''
    for i = 1, #plugdefstrips do
      if plugdefstrips[i].plug == string.lower(fxmod) then
        idxtab[cnt] = i
        cnt = cnt + 1
      end
    end
    for i = 1, cnt-1 do
      local idx = idxtab[i]
      if cnt == 1 then
        mstr = plugdefstrips[idx].stripfile
      elseif i == cnt-1 then
        mstr = mstr..'|<'..plugdefstrips[idx].stripfile
      else
        mstr = mstr..'|'..plugdefstrips[idx].stripfile
      end
      ddtab[i] = plugdefstrips[idx].stripfile
    end
    return mstr, idxtab, cnt-1, ddtab

  end

  function SwitcherMenu_RB()

    show_dd = false

    local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
    local switchid = ctl.switcherid
    if not switchid then return end

    if (switchers[switchid].switchmode or 0) == 0 then

      local sfad = strips[tracks[track_select].strip][page].controls[switcher_select].switchfader
      local mstr
      local sfcnt = #strip_favs
      if sfcnt > 0 then
        mstr = '>Add Strip'
        for fvs = 1, sfcnt do
          if fvs == sfcnt then
            mstr = mstr .. '|<' .. string.match(strip_favs[fvs],'.+/(.-).strip')
          else
            mstr = mstr .. '|' .. string.match(strip_favs[fvs],'.+/(.-).strip')
          end
        end
        mstr = mstr..'||'
      else
        mstr = ''
      end

      mstr = mstr .. 'Add page|Rename page|Remove page||Create Page Buttons||'
      mstr = mstr .. '!Pages Mode|Strip Switch Mode|'

      local exopts = 6
      local fm, lastp = FaderMenu(sfad,true)
      mstr = mstr ..'|'..fm..'|'
      local vo = '>Fader value offset'
      for i = 0, 127 do
        if sfad and faders[sfad] and switchers[switchid].switchmode ~= 1 then
          vo = vo .. '|'
          if i == faders[sfad].voffset then
            vo = vo .. '!'
          end
        else
          vo = vo .. '|#'
        end
        if i == 127 then
          vo = vo .. '<'
        end
        vo = vo.. string.format('%i',i)..'  -  '..num2note(i)
      end
      local exopts2 = exopts + lastp + 128
      mstr = mstr..vo..'|'


      local swc = #switchers[switchid].grpids
      for sid = 1, swc do
        mstr = mstr..'|'..string.format('%i',sid)..': '..tostring(switchers[switchid].grpids[sid].name)
      end

      gfx.x, gfx.y = mouse.mx, mouse.my
      local res = OpenMenu(mstr)
      if res > 0 then

        if res <= sfcnt then

          local fn = strip_favs[res]
          Switcher_AddStrip(fn, switcher_select)

        elseif res == sfcnt + 1 then

          Switcher_AddPage(switcher_select)

        elseif res == sfcnt + 2 then

          local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
          local switchid = ctl.switcherid
          local defname = ''
          for g = 1, #switchers[switchid].grpids do
            if switchers[switchid].grpids[g].id == switchers[switchid].current then
              defname = switchers[switchid].grpids[g].name
              break
            end
          end
          OpenEB(51,'Please enter page name:', defname)

        elseif res == sfcnt + 3 then

          Switcher_DeletePage(switchid)

        elseif res == sfcnt + 4 then

          Switcher_CreatePageButtons(switcher_select)

        elseif res == sfcnt + 5 then

          switchers[switchid].switchmode = 0

        elseif res == sfcnt + 6 then

          switchers[switchid].switchmode = 1

        elseif res >= sfcnt + exopts and res < sfcnt + exopts + lastp then
          res = res - (sfcnt + exopts)
          local f = {targettype = 6,
                     strip = tracks[track_select].strip,
                     page = page,
                     ctl = switcher_select,
                     c_id = strips[tracks[track_select].strip][page].controls[switcher_select].c_id,
                     voffset = 0}
          AssignFader(res,f)

        elseif res == sfcnt + exopts + lastp then

          DeleteFader(sfad)

        elseif res > sfcnt + exopts + lastp and res < sfcnt + exopts2 then

          res = res - (sfcnt + exopts2 -128)
          if sfad then

            faders[sfad].voffset = res-1

          end

        elseif res >= sfcnt + 1 + exopts2 then

          switchers[switchid].current = switchers[switchid].grpids[res - sfcnt - exopts2].id
          local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
          ctl.param_info.paramname = string.format('%i',res-sfcnt-exopts2)..': '..switchers[switchid].grpids[res - sfcnt-exopts2].name
          lupd.update_gfx = true
          lupd.update_bg = true

          SetCtlBitmapRedraw()
        end

      end

    elseif (switchers[switchid].switchmode or 0) == 1 then

      if mouse.ctrl or switchers[switchid].extendmode ~= true or mode ~= 0 then
        mstr = ''
        local stripfolders
        if switchers[switchid].stripfolder == '__LBXFAVS' then
          stripfolders = '|!FAVS|'
        else
          stripfolders = '|FAVS|'
        end
        local sfcnt = #strip_folders + 1
        for i = 0, sfcnt-1 do
          local tk = ''
          if switchers[switchid].stripfolder == strip_folders[i].fn then
            tk = '!'
          end
          if i == sfcnt-1 then
            stripfolders = stripfolders .. '|<' ..tk..strip_folders[i].fn
          else
            stripfolders = stripfolders .. '|' ..tk..strip_folders[i].fn
          end
        end

        local dll_cnt = 0
        local dllstr = ''
        local dlltab = {}
        if lvar.livemode == 2 and #(switchers[switchid].fxguids or {}) == 1 then
          local track = GetTrack(lvar.dynamicmode_trn)
          if track then
            local fxn = GetFXNFromGUID(track,switchers[switchid].fxguids[1])
            local _, mod = reaper.BR_TrackFX_GetFXModuleName(track,fxn,'',64)
            if mod then
              dllstr, dlltab, dll_cnt = StripModuleList(mod)
              if dllstr ~= '' then
                dllstr = '|>Select plugin strip|'..dllstr
              end
            end
          end
        end

        local tk2 = ''
        if switchers[switchid].copypinmap == true then
          tk2 = '!'
        end
        local tk3 = ''
        if switchers[switchid].extendmode == true then
          tk3 = '#!'
        end
        mstr = mstr .. '#Pages Mode|!Strip Switch Mode||>Select Strip Folder'..stripfolders..'|'..dllstr..'||Link To New InsertFX|'..tk2..'Copy PinMap To Plugins||'..tk3..'Auto Extend Mode'
        if mode == 1 and submode == 0 then
          mstr = mstr .. '||Set Strip Drop Location'
        else
          mstr = mstr .. '||#Set Strip Drop Location'
        end
        mstr = mstr .. '||Set Default Switcher Location||Set Gap X ('..(lvar.dm_padx)..')|Set Gap Y ('..(lvar.dm_pady)..')'
        mstr = mstr .. '||Save As Ext Switcher Default'
        gfx.x, gfx.y = mouse.mx, mouse.my
        local res = OpenMenu(mstr)
        if res > 0 then
          --DBG(sfcnt..'  '..res)
          if res == 1 then

            switchers[switchid].switchmode = 0

          elseif res > 2 and res <= 3+sfcnt then
            local fidx = res - 3 - 1
            if fidx >= 0 then
              switchers[switchid].stripfolder = strip_folders[fidx].fn
            else
              switchers[switchid].stripfolder = '__LBXFAVS'
            end
          elseif dll_cnt > 0 and res >= 4+sfcnt and res <= 4+sfcnt+dll_cnt then

            local idx = res-(4+sfcnt) + 1
            local idx2 = dlltab[idx]
            if idx2 then

              --local trn = lvar.dynamicmode_trn
              local fn = plugdefstrips[idx2].stripfol..'/'..plugdefstrips[idx2].stripfile

              switchers[switchid].grpids[1].stripfn = paths.strips_path..fn
              DM_RefreshPage()

              --[[loadstrip = LoadStripFN(fn)
              if loadstrip then

                lvar.addstripdialog_tracknum = lvar.dynamicmode_trn
                lvar.show_addstripdialog = true

                local pos = DM_Switcher_GetFXPos(switchid) or 0
                local fxdata = AddStripDialog_GetFxData(trn,pos)

                if #fxdata > 0 then
                  fxdata.loadstrip = loadstrip
                  fxdata.mode = 1
                  AddStripDialog_UpdateSel(fxdata)

                  local extpos = switchers[switchid].extendpos

                  local fx = pos
                  local swok = Switcher_AddStrip(nil, switcher_select, loadstrip, fxdata, trn, fx, nil, true)
                  local extid = switchers[switchid].extendid
                  Strip_ReposSwitcher_Ext(extid, 1)
                  UpdateControlValues3(reaper.time_precise(), ctls_upd, ctls_orr)
                  DM_RefreshFX()

                  DM_RefreshPage()
                  DM_StoreStripData()

                end
                lvar.show_addstripdialog = false
                loadstrip = nil

              end]]

            end
          elseif res == 4+sfcnt+dll_cnt then
            Switchers_AddInsertFX(switchid, tracks[track_select].strip, page, switcher_select)
          elseif res == 5+sfcnt+dll_cnt then
            switchers[switchid].copypinmap = not (switchers[switchid].copypinmap or false)
          elseif res == 6+sfcnt+dll_cnt then
            switchers[switchid].extendmode = not (switchers[switchid].extendmode or false)
            if switchers[switchid].extendmode == true then
              switchers[switchid].extenddir = 1
              switchers[switchid].extendid = GenID()
              switchers[switchid].extendpos = 1
            end
          elseif res == 7+sfcnt+dll_cnt then
            stripswitch_droploc = {c = switcher_select, swid = switchid, x = switchers[switchid].dropx or mouse.mx, y = switchers[switchid].dropy or mouse.my}

            lupd.update_surface = true
          elseif res == 8+sfcnt+dll_cnt then
            Switcher_SetPosDefLoc(switchid, ctl.x, ctl.y)
            local extid = switchers[switchid].extendid
            Strip_ReposSwitcher_Ext(extid, 1)
            GUI_DrawCtlBitmap()
            lupd.update_gfx = true

          elseif res == 9+sfcnt+dll_cnt then
            OpenEB(1500,'Please enter switcher gap X (pixels):')
          elseif res == 10+sfcnt+dll_cnt then
            OpenEB(1501,'Please enter switcher gap Y (pixels):')
          elseif res == 11+sfcnt+dll_cnt then
            local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
            SaveDefSwitchFormat(switchid, ctl)
          end
        end
      elseif mouse.shift == true then

        mstr = 'Edit Strip||Save Snapshots To Strip File||Insert Switcher||Delete Switcher||Delete Strip'
        gfx.x, gfx.y = mouse.mx, mouse.my
        local res = OpenMenu(mstr)
        if res > 0 then
          if res == 1 then

            DM_OpenEditMode(nil, switchid)

          elseif res == 2 then

            DM_SaveSnapsToStrip(switchid)

          elseif res == 3 then
            Switchers_Ext_Insert(switchid, switchers[switchid].extendpos)
          elseif res == 4 then

            Switcher_DeleteExt(switchid)
            UpdateControlValues3(nil, ctls_upd, ctls_orr)
            DM_RefreshFX()

          elseif res == 5 then

            DeleteSwitcherStrip(switchid, true, true)

            --local stripids, firstfxslot = Switcher_GetStripIDs(switchid)
            --for i = 1, #stripids do
            --  DeleteStrip(stripids[i],true, true)
            --end

            local extid = switchers[switchid].extendid
            Strip_ReposSwitcher_Ext(extid, 1)
            UpdateControlValues3(nil, ctls_upd, ctls_orr)
            DM_RefreshFX()

            local c = Switchers_FindCtl(switchid)
            local strip = tracks[track_select].strip
            local ctl = strips[strip][page].controls[c]
            if ctl then
              ctl.param_info.paramname = 'INSERT'
            end
            lupd.update_gfx = true
            lupd.update_bg = true
            SetCtlBitmapRedraw()
            reaper.MarkProjectDirty(0)

          end
        end

      elseif mouse.alt then

        SwitcherMenu_Alt()

      else

        SwitcherMenu_LB()

      end
    end
  end

  function Switcher_SetPosDefLoc(switchid, x, y)
    local extid = switchers[switchid].extendid
    if extid then
      for s = 1, #switchers do
        if switchers[s].switchmode == 1 and switchers[s].extendmode == true and switchers[s].extendid == extid then
          switchers[s].posfirstswitcher = {x = x, y = y}
        end
      end

    end
  end

  function Switcher_SetPadX(switchid, v)
    local extid = switchers[switchid].extendid
    if extid then
      for s = 1, #switchers do
        if switchers[s].switchmode == 1 and switchers[s].extendmode == true and switchers[s].extendid == extid then
          switchers[s].padx = v
        end
      end
    end
  end

  function Switcher_SetPadY(switchid, v)
    local extid = switchers[switchid].extendid
    if extid then
      for s = 1, #switchers do
        if switchers[s].switchmode == 1 and switchers[s].extendmode == true and switchers[s].extendid == extid then
          switchers[s].pady = v
        end
      end
    end
  end

  function SwitcherMenu_LB()

    --[[local mstr = ''
    local exopts = 0
    local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
    local switchid = ctl.switcherid
    local swc = #switchers[switchid].grpids
    for sid = 1, swc do
      if mstr ~= '' then mstr = mstr..'|' end
      mstr = mstr..string.format('%i',sid)..': '..tostring(switchers[switchid].grpids[sid].name)
    end
    gfx.x, gfx.y = mouse.mx, mouse.my
    local res = OpenMenu(mstr)
    if res > 0 then

      if res >= 1 then

        switchers[switchid].current = switchers[switchid].grpids[res].id
        local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
        ctl.param_info.paramname = string.format('%i',res)..': '..switchers[switchid].grpids[res].name
        lupd.update_gfx = true
        lupd.update_bg = true

        SetCtlBitmapRedraw()
      end

    end]]
    local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
    local switchid = ctl.switcherid

    if not switchers[ctl.switcherid] then return end

    if (switchers[ctl.switcherid].switchmode or 0) == 0 then

      local xx,yy
      if lvar.livemode == 0 then
        xx = ctl.xsc - surface_offset.x + obj.sections[10].x
        yy = ctl.ysc + ctl.hsc - surface_offset.y + obj.sections[10].y
      else
        xx = mouse.mx --lvar.spos[ctl.switcherid].x
        yy = mouse.my --lvar.spos[ctl.switcherid].y + lvar.spos[ctl.switcherid].sh
      end
      if not ddlist then
        local ddtab = {idx = 2, x = xx, y = yy, w = ctl.wsc, h = 100, items = {}, wpad = 40}
        local exopts = 0
        local swc = #switchers[switchid].grpids
        for sid = 1, swc do
          ddtab.items[sid] = string.format('%i',sid)..': '..tostring(switchers[switchid].grpids[sid].name)
        end
        OpenDropDown(2, ddtab, true, true)
      end

    elseif switchers[ctl.switcherid].switchmode == 1 then

      if not mouse.shift or switchers[ctl.switcherid].extendmode ~= true then
        local x,y
        if lvar.livemode == 0 then
          x = ctl.xsc - surface_offset.x + obj.sections[10].x
          y = ctl.ysc + ctl.hsc - surface_offset.y + obj.sections[10].y
        else
          local strip = tracks[track_select].strip
          if strips[strip][page].popidx and strips[strip][page].popidx[ctl.switcherid] and (lvar.showpop == true or lvar.popalpha) then
            local idx = strips[strip][page].popidx[ctl.switcherid]
            local pop = strips[strip][page].pop[idx]
            local swdata = lvar.stripdim.swdata[ctl.switcherid]

            x = obj.sections[10].x + pop.x
            y = obj.sections[10].y + pop.y
            
            --if lvar.livemode >= 1 then
              local xoff, yoff = 0, 0
              if lvar.popout_autoarrange then
                xoff = lvar.pop_xoff or 0
                yoff = lvar.pop_yoff or 0
              end
            --end
            
            if swdata.stripr then
              x = x + math.floor(((swdata.stripr - swdata.stripl)/2)*lvar.zoom - ((swdata.sr - swdata.sl)/2)*lvar.zoom)
              y = y + (swdata.sb - swdata.st)*lvar.zoom + yoff
            end
          else
            x = lvar.spos[ctl.switcherid].x + math.floor((lvar.spos[ctl.switcherid].w-lvar.shadowmax)/2 - lvar.spos[ctl.switcherid].sw/2)*lvar.zoom
            y = lvar.spos[ctl.switcherid].y + lvar.spos[ctl.switcherid].sh*lvar.zoom
          end
        end
        local w = ctl.wsc*lvar.zoom

        local ddtab = {idx = 2, x = x, y = y, w = w, h = 100, items = {}, wpad = 40, switchid = switchid}
        if lvar.mixmodealign == 1 and lvar.mixmodedir == 0 then
          if lvar.spos and lvar.spos[ctl.switcherid] then
            ddtab.x = lvar.spos[ctl.switcherid].x
          end
        end

        if switchers[switchid].stripfolder then

          if switchers[switchid].stripfolder == '__LBXFAVS' then
            local sfcnt = #strip_favs
            if sfcnt > 0 then
              local fn
              for fvs = 1, sfcnt do
                fn = string.match(strip_favs[fvs],'.+/(.-).strip')
                if fn then
                  ddtab.items[#ddtab.items+1] = fn
                end
              end
            end
            OpenDropDown(2, ddtab, true, true)

          else
            local spath = paths.strips_path..'/'..switchers[switchid].stripfolder
            if spath then
              local i = 0
              local sf = reaper.EnumerateFiles(spath,i)
              while sf ~= nil do
                local fn, suffix = string.match(sf,'(.+)%.(.*)')
                if suffix == 'strip' then
                  ddtab.items[#ddtab.items+1] = fn
                end
                i=i+1
                sf = reaper.EnumerateFiles(spath,i)
              end
              OpenDropDown(2, ddtab, true, true)

            end
          end
        end
      else



      end
    end

  end

  function SwitcherMenu_Alt()

    local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
    local switchid = ctl.switcherid

    local dll_cnt = 0
    local dllstr = ''
    local dlltab = {}
    local items
    if lvar.livemode == 2 and #(switchers[switchid].fxguids or {}) == 1 then
      local track = GetTrack(lvar.dynamicmode_trn)
      if track then
        local fxn = GetFXNFromGUID(track,switchers[switchid].fxguids[1])
        local _, mod = reaper.BR_TrackFX_GetFXModuleName(track,fxn,'',64)
        if mod then
          _, dlltab, dll_cnt, items  = StripModuleList(mod)

          if items and #items > 0 then
            local x,y

            local strip = tracks[track_select].strip
            if strips[strip][page].popidx and strips[strip][page].popidx[switchid] then
              local idx = strips[strip][page].popidx[switchid]
              local pop = strips[strip][page].pop[idx]
              local swdata = lvar.stripdim.swdata[switchid]

              x = obj.sections[10].x + pop.x + math.floor(((swdata.stripr - swdata.stripl)/2)*lvar.zoom - ((swdata.sr - swdata.sl)/2)*lvar.zoom)
              y = obj.sections[10].y + pop.y + (swdata.sb - swdata.st)*lvar.zoom

            else
              x = lvar.spos[switchid].x + math.floor((lvar.spos[switchid].w-lvar.shadowmax)/2 - lvar.spos[switchid].sw/2)*lvar.zoom
              y = lvar.spos[switchid].y + lvar.spos[switchid].sh*lvar.zoom
            end
            local w = ctl.wsc*lvar.zoom

            local ddtab = {idx = 4, x = x, y = y, w = w, h = 100, items = {}, wpad = 40, switchid = switchid}
            if lvar.mixmodealign == 1 and lvar.mixmodedir == 0 then
              ddtab.x = lvar.spos[switchid].x
            end

            ddtab.items = items
            ddtab.data = dlltab
            ddtab.cnt = dll_cnt
            OpenDropDown(4, ddtab, true, true)

          end

        end
      end
    end


  end

  function MenuMidiMsgType()

    local mstr = ''
    for i = 1, #lvar.midimsgtype_table do

      if mstr ~= '' then
        mstr = mstr .. '|'
      end
      mstr = mstr ..lvar.midimsgtype_table[i]

    end
    if mstr ~= '' then
      gfx.x, gfx.y = mouse.mx, mouse.my
      local res = OpenMenu(mstr)
      if res ~= 0 then
        return res
      end
    end
    return nil

  end

  function MenuMidiOuts()

    local mstr = ''
    for i = 0, #midiouts do

      if mstr ~= '' then
        mstr = mstr .. '|'
      end
      mstr = mstr ..midiouts[i].name

    end
    if mstr ~= '' then
      gfx.x, gfx.y = mouse.mx, mouse.my
      local res = OpenMenu(mstr)
      if res ~= 0 then
        return res
      end
    end
    return nil

  end

  function CheckUngroup()

    local ret = true
    if ctl_select and #ctl_select > 0 then
      local grpid
      for c = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[c].ctl]
        if ctl.grpid ~= nil and grpid then
          if grpid ~= ctl.grpid then
            ret = false
            break
          end
        elseif ctl.grpid ~= nil then
          grpid = ctl.grpid
        end
      end
      if ret == true and gfx3_select and #gfx3_select > 0 then
        for c = 1, #gfx3_select do
          local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[c].ctl]
          if ctl.grpid ~= nil and grpid then
            if grpid ~= ctl.grpid then
              ret = false
              break
            end
          elseif ctl.grpid ~= nil then
            grpid = ctl.grpid
          end
        end
      end
    else
      return false
    end
    return ret

  end

  function CheckGroup()

    local ret = true
    if ctl_select and #ctl_select > 0 then
      for c = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[c].ctl]
        if ctl.switcher ~= nil then
          ret = false
          break
        end
      end
      if ret == true and gfx3_select and #gfx3_select > 0 then
        for c = 1, #gfx3_select do
          local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[c].ctl]
          if ctl.switcher ~= nil then
            ret = false
            break
          end
        end
      end
    else
      return false
    end
    return ret

  end

  function RSMenuOut(x,y)

    local ctl = strips[tracks[track_select].strip][page].controls[rs5k_select]
    local track = GetTrack(ctl.tracknum or tracks[track_select].tracknum)

    local chans = math.min(reaper.GetMediaTrackInfo_Value(track, "I_NCHAN"))

    local mstr = ''
    for i = 1, chans/2 do
      if mstr ~= '' then
        mstr = mstr .. '|'
      end
      mstr = mstr .. (i-1)*2 +1 ..'+'..(i-1)*2 +2
    end
    if chans < 64 then
      mstr = mstr .. '|['..string.format('%i',chans+1)..'+'..string.format('%i',chans+2)..']'
    end

    gfx.x = x
    gfx.y = y
    local res = gfx.showmenu(mstr)
    if res > 0 then

      if res > chans/2 then
        --new chan

        if chans < 64 then
          chans = chans + 2
          reaper.SetMediaTrackInfo_Value(track, "I_NCHAN", chans)
        end

      end

      --bit
      local outchan0 = (res-1)*2
      local outchan1 = (res-1)*2 + 1

      local oLo = {}
      local oHi = {}

      if outchan0 < 32 then
        oLo[0] = 2^outchan0
        oHi[0] = 0
      else
        oLo[0] = 0
        oHi[0] = 2^(outchan0%32)
      end
      if outchan1 < 32 then
        oLo[1] = 2^outchan1
        oHi[1] = 0
      else
        oLo[1] = 0
        oHi[1] = 2^(outchan1%32)
      end

      SetPinMap(track,ctl.fxnum,nil,nil,oLo,oHi)
      lvar.rs.out = 'OUT '..string.format('%i',outchan0+1) ..'+'..string.format('%i',outchan1+1)
      lupd.update_samplemanager = true

    end

  end

  function RBMenu_Snapshot(snapmx, snapmy)

    if sstype_select == 1 then
      local fm, lp = FaderMenu(snapshot_fader, true, nil, 'Recall ')
      local cfm, clp = FaderMenu(capture_fader, true, nil, 'Capture ')
      local dttk = ''
      if lvar.snapcapture_midi_dt == true then
        dttk = '!'
      end
      mstr = 'Clone to subset (ctls only)||'..fm..'||'..cfm..'|'..dttk..'Requires double-tap on note'
      gfx.x, gfx.y = snapmx, snapmy
      local res = OpenMenu(mstr)
      if res > 0 then
        if res == 1 then
          local newsst = Snapshot_CloneToSubset(tracks[track_select].strip, page, 1, false)
          if newsst then
            sstype_select = newsst
            lupd.update_snaps = true
          end
        elseif res <= 1+lp then
          local f = {targettype = 5}
          res = res -1
          if res ~= lp then
            AssignFader(res, f)
          elseif res == lp then
            DeleteFader(snapshot_fader)
          end
        elseif res <= 1+lp+clp then
          local f = {targettype = 9}
          local p = res - (1+lp)
          if p ~= clp then
            AssignFader(p, f)
          elseif p == clp then
            DeleteFader(capture_fader)
          end
        elseif res == (1+lp+clp)+1 then
          lvar.snapcapture_midi_dt = not (lvar.snapcapture_midi_dt or false)
        end
      end

    elseif sstype_select > 1 then
      local fm, lp = FaderMenu(snapshot_fader, true, nil, 'Recall ')
      local cfm, clp = FaderMenu(capture_fader, true, nil, 'Capture ')
      local dttk = ''
      if lvar.snapcapture_midi_dt == true then
        dttk = '!'
      end
      mstr = 'Delete subset|Delete all subsets||Delete Empty/Orphaned Subsets||Clone to subset (ctls only)||'..fm..'||'..cfm..'|'..dttk..'Requires double-tap on note'
      gfx.x, gfx.y = snapmx, snapmy
      local res = OpenMenu(mstr)
      if res > 0 then
        if res == 1 then

          Snapshot_DeleteSubset(tracks[track_select].strip, page, sstype_select)
          SetCtlBitmapRedraw()
          lupd.update_gfx = true

        elseif res == 2 then

          if snapshots and snapshots[tracks[track_select].strip] and #snapshots[tracks[track_select].strip][page] > 1 then
            OpenMsgBox(3, 'Delete all subsets?', 2)
          end

        elseif res == 3 then
          local strip = tracks[track_select].strip
          Snapshot_DeleteOrphanedSubsets(strip, page)
          if sstype_select > #snapshots[strip][page] then
            sstype_select = #snapshots[strip][page]
          end
          lupd.update_snaps = true
        elseif res == 4 then
          local newsst = Snapshot_CloneToSubset(tracks[track_select].strip, page, sstype_select, false)
          if newsst then
            sstype_select = newsst
            lupd.update_snaps = true
          end

        elseif res <= 4+lp then
          local f = {targettype = 5}
          res = res -4
          if res ~= lastp then
            AssignFader(res, f)
          elseif res == lastp then
            DeleteFader(snapshot_fader)
          end

        elseif res <= 4+lp+clp then
          local f = {targettype = 9}
          local p = res - (4+lp)
          if p ~= clp then
            AssignFader(p, f)
          elseif p == clp then
            DeleteFader(capture_fader)
          end

        elseif res == (4+lp+clp)+1 then
          lvar.snapcapture_midi_dt = not (lvar.snapcapture_midi_dt or false)
        end

      end
    end

  end

  function CtlSelect_AlignTop()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'y','ysc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local y = ctls[cc].ysc
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dy = ctl.ysc - ctl.y
            ctl.y = y-dy
            local scale = ctl.scale
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'y'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local y = ctls[cc].y
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.y = y
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end
  end

  function CtlSelect_AlignBottom()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'y','ysc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local y = ctls[cc].ysc + ctls[cc].hsc
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dy = (ctl.ysc+ctl.hsc) - (ctl.y+ctl.ctl_info.cellh)
            ctl.y = y - ctl.hsc + dy
            local scale = ctl.scale
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'y'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local y = ctls[cc].y + ctls[cc].stretchh
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.y = y-ctl.stretchh
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end
  end

  function CtlSelect_AlignLeft()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'x','xsc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local x = ctls[cc].xsc
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dx = ctl.xsc - ctl.x
            ctl.x = x-dx
            local scale = ctl.scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'x'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local x = ctls[cc].x
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.x = x
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_AlignRight()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'x','xsc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local x = ctls[cc].xsc + ctls[cc].wsc
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dx = (ctl.xsc+ctl.wsc) - (ctl.x+ctl.w)
            ctl.x = x - ctl.wsc + dx
            local scale = ctl.scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'x'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local x = ctls[cc].x + ctls[cc].stretchw
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.x = x - ctl.stretchw
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_AlignCentreH()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'x','xsc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local x = ctls[cc].xsc + math.floor(ctls[cc].wsc/2)
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dx = ctl.xsc - ctl.x
            ctl.x = x-dx - math.floor(ctl.wsc/2)
            local scale = ctl.scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'x'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local x = ctls[cc].x + math.floor(ctls[cc].stretchw/2)
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.x = x - math.floor(ctl.stretchw/2)
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_AlignCentreV()

    if submode == 0 then
      if ctl_select and #ctl_select > 1 then
        Undo_Set({'y','ysc'})

        local cc = lvar.ctlpreview_sel or ctl_select[1].ctl
        local ctls = strips[tracks[track_select].strip][page].controls
        local y = ctls[cc].ysc + math.floor(ctls[cc].hsc/2)
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if ctl_select[i].ctl ~= cc and nz(ctl.poslock, false) == false then
            local dy = ctl.ysc - ctl.y
            ctl.y = y-dy - math.floor(ctl.hsc/2)
            local scale = ctl.scale
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 1 then
        Undo_Set({'y'})

        local cc = lvar.gfxpreview_sel or gfx4_select[1]
        local ctls = strips[tracks[track_select].strip][page].graphics
        local y = ctls[cc].y + math.floor(ctls[cc].stretchh/2)
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if gfx4_select[i] ~= cc and nz(ctl.poslock, false) == false then
            ctl.y = y - math.floor(ctl.stretchh/2)
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_SetX(x)

    if submode == 0 then
      if ctl_select then
        Undo_Set({'x','xsc'})

        local ctls = strips[tracks[track_select].strip][page].controls
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if nz(ctl.poslock, false) == false then
            local dx = ctl.xsc - ctl.x
            ctl.x = x-dx
            local scale = ctl.scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 0 then
        Undo_Set({'x'})

        local ctls = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if nz(ctl.poslock, false) == false then
            ctl.x = x
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_SetY(y)

    if submode == 0 then
      if ctl_select then
        Undo_Set({'y','ysc'})

        local ctls = strips[tracks[track_select].strip][page].controls
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if nz(ctl.poslock, false) == false then
            local dy = ctl.ysc - ctl.y
            ctl.y = y-dy
            local scale = ctl.scale
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 0 then
        Undo_Set({'y'})

        local ctls = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if nz(ctl.poslock, false) == false then
            ctl.y = y
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_SetW(w)

    if submode == 0 then
      if ctl_select then
        Undo_Set({'scale','xsc','ysc','wsc','hsc'})

        local ctls = strips[tracks[track_select].strip][page].controls
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if nz(ctl.poslock, false) == false then
            local scale = w/ctl.w
            ctl.scale = scale
            ctl.wsc = ctl.w*scale
            ctl.hsc = ctl.ctl_info.cellh*scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 0 then
        Undo_Set({'stretchw'})

        local ctls = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if nz(ctl.poslock, false) == false then
            ctl.stretchw = w
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_SetH(h)

    if submode == 0 then
      if ctl_select then
        Undo_Set({'scale','xsc','ysc','hsc','wsc'})

        local ctls = strips[tracks[track_select].strip][page].controls
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if nz(ctl.poslock, false) == false then
            local scale = h/ctl.ctl_info.cellh
            ctl.scale = scale
            ctl.wsc = ctl.w*scale
            ctl.hsc = ctl.ctl_info.cellh*scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    elseif submode == 1 then
      if gfx4_select and #gfx4_select > 0 then
        Undo_Set({'stretchh'})

        local ctls = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx4_select do
          local ctl = ctls[gfx4_select[i]]
          if nz(ctl.poslock, false) == false then
            ctl.stretchh = h
          end
        end
        --SetCtlBitmapRedraw()
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_bg = true
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function CtlSelect_SetScale(scale)

    if submode == 0 then
      if ctl_select then
        Undo_Set({'scale','xsc','ysc','hsc','wsc'})

        local ctls = strips[tracks[track_select].strip][page].controls
        for i = 1, #ctl_select do
          local ctl = ctls[ctl_select[i].ctl]
          if nz(ctl.poslock, false) == false then
            ctl.scale = scale
            ctl.wsc = ctl.w*scale
            ctl.hsc = ctl.ctl_info.cellh*scale
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
        end
        ReselectSelection()
        SetCtlBitmapRedraw()
        lupd.update_gfx = true
        movefrom_sc = nil
      end
    end

  end

  function RBMenu_SK2Edit()
    
    SK2CtlMenu_RB()
    
  end
  
  function RBMenu_Edit()
  
    if mouse.shift and strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].ctlcat == ctlcats.sk2ctl then 
      RBMenu_SK2Edit()
      return
    end
  
    local mm
    if poslockctl_select then
      mm = '!Lock position'
    else
      mm = 'Lock position'
    end
    local vv
    if strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].hidden == true then
      vv = 'Visible'
    else
      vv = '!Visible'
    end
    local ac
    if strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].ctlcat == ctlcats.action then
      ac = '||Assign command ID from selected item in Action list||Assign custom action by name|Assign action by command ID'
    else
      ac = '||#Assign command ID from selected item in Action list||#Assign custom action by name|#Assign action by command ID'
    end
    local cp
    if copy_ctls ~= nil then
      cp = '||Copy|Paste'
    else
      cp = '||Copy|#Paste'
    end
    local ps
    local psc = #lvar.pastespecial
    if copy_ctls ~= nil then
      ps = '|>Paste Special'
      for i = 1, psc do
        if i == psc then
          ps = ps..'|<'..lvar.pastespecial[i][1]
        else
          ps = ps..'|'..lvar.pastespecial[i][1]
        end
      end
    else
      ps = '|#>Paste Special'
      for i = 1, psc do
        if i == psc then
          ps = ps..'|#<'..lvar.pastespecial[i][1]
        else
          ps = ps..'|#'..lvar.pastespecial[i][1]
        end
      end
    end
    local cpg
    if gauge_copy ~= nil then
      cpg = '|Copy Gauge|Paste Gauge'
    else
      cpg = '|Copy Gauge|#Paste Gauge'
    end
    local gg = ''
    if CheckGroup() == true then
      gg = 'Group|'
    else
      gg = '#Group|'
    end
    if CheckUngroup() == true then
      gg = gg..'Ungroup||'
    else
      gg = gg..'#Ungroup||'
    end
    ss = 'Group As Strip||'
    local sw
    local ra
    local mc,ac2,si,ma
    local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
    local ctl
    if c then
      ctl = strips[tracks[track_select].strip][page].controls[c]
      if ctl.ctlcat == ctlcats.switcher and SwitcherInSelected(ctl.switcherid) == false then
        sw = 'Add To Switcher||'
      end
      if ctl.ctlcat == ctlcats.fxparam and tfxp_sel and ctl_select and #ctl_select == 1 then
        local i
        local cnt = 0
        for i = 0, #trackfxparams do
          if tfxp_sel[i] then
            cnt = cnt + 1
          end
        end
        if cnt == 1 then
          ra = '||Reassign Parameter'
        end
      end
      if ctl.ctlcat == ctlcats.midictl then
        mc = '||>Midi Control|Convert To MAIN Action via Shortcut|<Convert To MIDI EDITOR Action via Shortcut'
      end
      if ctl.ctlcat == ctlcats.action then
        if tonumber(ctl.param_info.paramstr) == 32060 then
          ac2  = '||>Action Options|Target Main|<!Target MIDI Editor'
        else
          ac2  = '||>Action Options|!Target Main|<Target MIDI Editor'
        end
      end
      if ctl.ctlcat == ctlcats.statectl or ctl.ctlcat == ctlcats.statectl_str then
        si = '||Set State Info'
      end
      if ctl.ctlcat == ctlcats.macro then
        if ctl.param_info.paramnum == 1 then
          ma = '||>Macro Options|<!Force Trigger'
        else
          ma = '||>Macro Options|<Force Trigger'
        end
      end
    end
    if sw == nil then
      sw = '#Add Controls To Switcher||'
    end
    if ra == nil then
      ra = '||#Reassign Parameter'
    end
    if mc == nil then
      mc = '||>#Midi Control|#Convert To Main Action via Shortcut|<#Convert To MIDI Editor Action via Shortcut'
    end
    if ac2 == nil then
        ac2  = '||>#Action Options|#Target Main|<#Target MIDI Editor'
    end
    if si == nil then
      si = '||#Set State Info'
    end
    if ma == nil then
      ma = '||>#Macro Options|<#Force Trigger'
    end
    local mstr = 'Duplicate||Align Top|Align Left|Distribute Vertically|Distribute Horizontally||'..gg..ss..sw..mm..'||'..vv..'||Delete'..ra..ac..cp..ps..cpg..
                 '||Control Info||Repatriate Lost Controls||>Cluster Controls|4 columns|8 columns|12 columns|16 columns|<Stack'..mc..ac2..ma..si
    gfx.x, gfx.y = mouse.mx, mouse.my
    local res = OpenMenu(mstr)
    if res == 1 then
      local c1 = #strips[tracks[track_select].strip][page].controls+1
      local dx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - (mouse.mx+surface_offset.x-obj.sections[10].x)
      local dy = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - (mouse.my+surface_offset.y-obj.sections[10].y)
      for i = 1, #ctl_select do
        local cc = c1+i-1
        strips[tracks[track_select].strip][page].controls[cc]=GetControlTable(tracks[track_select].strip, page, ctl_select[i].ctl)
        strips[tracks[track_select].strip][page].controls[cc].poslock = false
        strips[tracks[track_select].strip][page].controls[cc].x = strips[tracks[track_select].strip][page].controls[cc].x - dx
        strips[tracks[track_select].strip][page].controls[cc].y = strips[tracks[track_select].strip][page].controls[cc].y - dy
        strips[tracks[track_select].strip][page].controls[cc].xsc = strips[tracks[track_select].strip][page].controls[cc].xsc - dx
        strips[tracks[track_select].strip][page].controls[cc].ysc = strips[tracks[track_select].strip][page].controls[cc].ysc - dy
        strips[tracks[track_select].strip][page].controls[cc].id = nil
      end
      ctl_select = nil
      for i = c1, #strips[tracks[track_select].strip][page].controls do
        if ctl_select == nil then
          ctl_select = {}
          ctl_select[1] = {ctl = i}
        else
          local cs = #ctl_select+1
          ctl_select[cs] = {}
          ctl_select[cs].ctl = i
          ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
          ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
        end
      end
      SetCtlBitmapRedraw()
      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      lupd.update_gfx = true
    elseif res == 2 then

      CtlSelect_AlignTop()

    elseif res == 3 then

      CtlSelect_AlignLeft()

    elseif res == 4 then

      Distribute_Vert()

    elseif res == 5 then

      Distribute_Horiz()

    elseif res == 6 then

      local ngrp = GenID()
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl.switcherid ~= nil then
          switchers[ctl.switcherid].parent = nil
        end
        ctl.grpid = ngrp
        ctl.switcher = nil
      end
      if gfx3_select and #gfx3_select > 0 then
        for i = 1, #gfx3_select do
          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].grpid = ngrp
          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].switcher = nil
        end
      end
      lupd.update_bg = true
      lupd.update_gfx = true

    elseif res == 7 then

      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl.switcherid ~= nil then
          switchers[ctl.switcherid].parent = nil
        end
        ctl.grpid = nil
        ctl.switcher = nil
      end
      if gfx3_select and #gfx3_select > 0 then
        for i = 1, #gfx3_select do
          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].grpid = nil
          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].switcher = nil
        end
      end
      lupd.update_bg = true
      lupd.update_gfx = true

    elseif res == 8 then

      local nid = GenID()
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        ctl.id = nid
      end
      if gfx3_select and #gfx3_select > 0 then
        for i = 1, #gfx3_select do
          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].id = nid
        end
      end
      lupd.update_bg = true
      lupd.update_gfx = true

    elseif res == 9 then

      newgrp = {grpid = switchers[ctl.switcherid].current,
                switchid = c}
      DropCtls()
      SetCtlBitmapRedraw()

    elseif res == 10 then
      for i = 1, #ctl_select do
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].poslock = not poslockctl_select
      end
      SetPosLockCtl()
    elseif res == 11 then
      local hidd = not nz(strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].hidden,false)
      for i = 1, #ctl_select do
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hidden = hidd
      end
      lupd.update_gfx = true

    elseif res == 12 then
      DeleteSelectedCtls()
      lupd.update_gfx = true

    elseif res == 13 then
      ReassParam(tracks[track_select].strip, page, ctl_select[1].ctl, trackedit_select, trackfx_select, trackfxparam_select)
      lupd.update_gfx = true
    elseif res == 14 then
      AssActionFromList()
    elseif res == 15 then
      trackfxparam_select = ctl_select[1].ctl
      show_actionchooser = true
      action_tbl = LoadActionIDs()
      action_tblF = {}
      action_tblF = table.copy(action_tbl)

      lupd.update_gfx = true
      --OpenEB(12,'Please enter action name:')
    elseif res == 16 then
      trackfxparam_select = ctl_select[1].ctl
      retval, comid = reaper.GetUserInputs('Action Button', 1, 'Please enter action command ID: ,extrawidth=196', '')
      if retval == true and comid then
        local actnm,a2,a3 = AssAction_GetNameFromID2(comid)
        AssActionByID(comid,actnm,a2,a3)
        lupd.update_gfx = true
      end
      --OpenEB(13,'Please enter action command ID:')
    elseif res == 17 then
      Copy_Selected()
    elseif res == 18 then
      local keep_coords
      if mouse.shift then
        keep_coords = true
      end
      Paste_Selected(keep_coords)

      SetCtlBitmapRedraw()
      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      lupd.update_gfx = true
    elseif res >= 19 and res <= 19+psc-1 then
      local pastespecial = res-18
      PasteSpecial(pastespecial)

    elseif res == 19+psc then
      gauge_copy = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].gauge
    elseif res == 20+psc then
      for i = 1, #ctl_select do
        strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].gauge = gauge_copy
      end
      lupd.update_bg = true
      lupd.update_gfx = true
    elseif res == 21+psc then
      if ctl_select and #ctl_select > 0 then
        for c = 1, #ctl_select do
          CtlInfo(tracks[track_select].strip, page, ctl_select[c].ctl)
        end
      end
    elseif res == 22+psc then
      RepatriateControls()
    elseif res == 23+psc then
      ClusterControls(4)
    elseif res == 24+psc then
      ClusterControls(8)
    elseif res == 25+psc then
      ClusterControls(12)
    elseif res == 26+psc then
      ClusterControls(16)
    elseif res == 27+psc then
      ClusterControls(-1)
    elseif res == 28+psc then
      MidiCtl_ConvertToAction(0)
    elseif res == 29+psc then
      MidiCtl_ConvertToAction(32060)
    elseif res == 30+psc then
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl and ctl.ctlcat == ctlcats.action then
          ctl.param_info.paramstr = 0
        end
      end
    elseif res == 31+psc then
      for i = 1, #ctl_select do
        local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
        if ctl and ctl.ctlcat == ctlcats.action then
          ctl.param_info.paramstr = 32060
        end
      end
    elseif res == 32+psc then
      --Macro force
      ctl.param_info.paramnum = 1-(ctl.param_info.paramnum or 0)
    elseif res == 33+psc then
      --DBG('SetStateInfo')
      local stateinf = GetStateInfoData(ctl)
      if stateinf and ctl.ctlcat == ctlcats.statectl then
        if stateinf[1] ~= '' and stateinf[2] ~= '' then
          ctl.stateinfo.extname = stateinf[1]
          ctl.stateinfo.key = stateinf[2]
          ctl.stateinfo.min = tonumber(stateinf[3]) or 0
          ctl.stateinfo.max = tonumber(stateinf[4]) or 1
          ctl.stateinfo.step = tonumber(stateinf[5]) or 0.1
        else

        end
      elseif stateinf and ctl.ctlcat == ctlcats.statectl_str then
        if stateinf[1] ~= '' and stateinf[2] ~= '' then
          ctl.stateinfo.extname = stateinf[1]
          ctl.stateinfo.key = stateinf[2]
        else

        end
      end
    end
  end

  function GetStateInfoData(ctl)

    local si
    if ctl.ctlcat == ctlcats.statectl then
      local rv = (ctl.stateinfo.extname or '') ..','.. (ctl.stateinfo.key or '') ..','.. ctl.stateinfo.min ..','.. ctl.stateinfo.max ..','.. ctl.stateinfo.step
      local retval, input = reaper.GetUserInputs('State Info',5,'External State Name,Key,Min,Max,Step,extrawidth=200',rv)
      if retval == true then
        si = {input:match("^([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)$")}
        if si then
          return si
        end
      end
    elseif ctl.ctlcat == ctlcats.statectl_str then
      local rv = (ctl.stateinfo.extname or '') ..','.. (ctl.stateinfo.key or '')
      local retval, input = reaper.GetUserInputs('State Info',2,'External State Name,Key,extrawidth=200',rv)
      if retval == true then
        si = {input:match("^([^,]+),([^,]+)$")}
        if si then
          return si
        end
      end
    end
  end


  function MidiCtl_ConvertToAction(acttype)

    local kb_fn = reaper.GetResourcePath().."/reaper-kb.ini"
    if not reaper.file_exists(kb_fn) then
      DBG(kb_fn..' file not found')
      return
    end
    --[[file = io.open(kb_fn, "r")
    local kb_str = file:read("*all")
    file:close()]]

    data = {}
    for line in io.lines(kb_fn) do
      local linex = string.match(line,'(KEY.*)') --decipher(line)
      if linex then
        data[#data+1] = linex
      end
    end

    local strip = tracks[track_select].strip
    for c = 1, #ctl_select do
      local ctl = strips[strip][page].controls[ctl_select[c].ctl]

      if ctl.ctlcat == ctlcats.midictl then

        local mo = ctl.midiout
        local mtype = mo.msgtype
        local chan = mo.mchan
        local pnum = mo.msg3

        --DBG('ctl '..c..'  ID: '..ctl_select[c].ctl..'  '..tostring(ctl.ctlname_override))

        local ret = MidiCtl_GetShortcutCommandIDs(mtype, chan, pnum, data, acttype)

        --convert to action
        if #ret > 0 then
          ctl.param_info.paramstr = ret[1].section
          if tonumber(ret[1].comid) then
            ctl.param_info.paramnum = tonumber(ret[1].comid)
            ctl.param_info.paramidx = nil
          else
            ctl.param_info.paramnum = nil
            ctl.param_info.paramidx = ret[1].comid
          end
          ctl.ctlcat = ctlcats.action
          ctl.midiout = nil
        end

      end
    end

  end

  function MidiCtl_GetShortcutCommandIDs(mtype, chan, pnum, data, acttype)

    local ret = {}
    local schan

    if mtype == 4 then
      schan = 176+(chan-1)
    elseif mtype == 2 then
      schan = 144+(chan-1)
    elseif mtype == 1 then
      schan = 128+(chan-1)
    end
    if schan then
      for d = 1, #data do
        local a,b,c,d,e = string.match(data[d],'(.-)%s(.-)%s(.-)%s(.-)%s(.*)')

        if tonumber(b) == schan and tonumber(c)%128 == pnum and tonumber(e) == acttype then
          DBG('MATCHED: '..tostring(a)..'  '..tostring(b)..'  '..tostring(c)..'  '..tostring(d)..'  '..tostring(e))
          ret[#ret+1] = {comid = d, section = e}
        end

      end
    end
    return ret

  end

  function ClusterControls(col)

    local strip = tracks[track_select].strip
    if strips and strips[strip] and ctl_select then

      Undo_Set({'x','y','xsc','ysc'})
      local l,t,lctl = GetLeftTopControlSelected()
      local ctl = strips[strip][page].controls[ctl_select[lctl].ctl]

      local w, h = 0,0
      if ctl and col ~= -1 then
        w, h = ctl.wsc, ctl.hsc --gfx.getimgdim(ctl.ctl_info.imageidx)--
        --h = math.floor(h/ctl.ctl_info.frames)
      end

      for i = 1, #ctl_select do
        local ctl = strips[strip][page].controls[ctl_select[i].ctl]
        if ctl then
          local xp = (i-1) % col
          local yp = math.floor((i-1) / col)
          ctl.x = l + math.floor(xp*w)
          ctl.y = t + math.floor(yp*h)
          ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*ctl.scale)/2)
          ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*ctl.scale)/2)
        end
      end
      lupd.update_gfx = true
      SetCtlBitmapRedraw()
      ReselectSelection()
      movefrom_sc = nil
    end

  end

  function CheckControlAssignments()

    local strip = tracks[track_select].strip
    if strips and strips[strip] then

      if #strips[strip][page].controls > 0 then

        local sk2check

        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          local track = GetTrack(ctl.tracknum or tracks[track_select].tracknum)
          
          if (ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.fxmulti or ctl.ctlcat == ctlcats.fxgui or ctl.ctlcat == ctlcats.fxoffline) and ctl.fxnum and ctl.param then
            local r, pn = reaper.TrackFX_GetParamName(track, ctl.fxnum, ctl.param, '')
            if pn ~= ctl.param_info.paramname then
              local cnt = reaper.TrackFX_GetNumParams(track, ctl.fxnum)-1
              local fnd
              local fndcnt = 0
              
              if ctl.param_info.paramname == 'Open GUI' then
                if ctl.param ~= cnt + 3 then
                  fnd = cnt + 3
                else
                  fnd = -1
                end
              elseif ctl.param_info.paramname == 'Offline' then
                if ctl.param ~= cnt + 1 then
                  fnd = cnt + 1  
                else
                  fnd = -1
                end
              elseif ctl.param_info.paramname == 'Off/Byp/Wet' then
                if ctl.param ~= cnt + 2 then
                  fnd = cnt + 2  
                else
                  fnd = -1
                end
              elseif ctl.param_info.paramname == 'Dummy' then
                if ctl.param ~= cnt + 4 then
                  fnd = cnt + 4  
                else
                  fnd = -1
                end
              else
                for p = 0, cnt do
                  local r, pn = reaper.TrackFX_GetParamName(track, ctl.fxnum, p, '')
                  if pn == ctl.param_info.paramname then
                    if ctl.param ~= p then                        
                      fnd = p
                      fndcnt = 1
                    end
                    break
                  elseif string.match(pn, '.*'..ctl.param_info.paramname..'.*') or string.match(ctl.param_info.paramname, '.*'..pn..'.*') then
                    --DBG('XXX'..pn)
                    if ctl.param ~= p then                        
                      fnd = p
                    end
                    fndcnt = fndcnt + 1
                  end
                end
              end
              if fnd and fnd ~= -1 and fndcnt < 2 then
                ctl.param = fnd
                ctl.param_info.paramnum = fnd
                DBG('FIXED: '..ctl.param_info.paramname)
              elseif fnd ~= -1 then
                DBG('ERROR: '..ctl.param_info.paramname)            
              end
            else
              --DBG(ctl.param_info.paramname..' OK')          
            end
          elseif ctl.ctlcat == ctlcats.sk2ctl then
            sk2check = true
          end
        end
        
        if sk2check then
          --FixSK2Slots()
          CheckSK2Slots()
        end
      end
    end
      
  end

  function FixSK2Slots()

    local strip = tracks[track_select].strip
    if strips and strips[strip] then
    
      if #strips[strip][page].controls > 0 then
    
        local mapped = {}
        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          if ctl.ctlcat == ctlcats.sk2ctl then
            local idx = tonumber(ctl.param_info.paramidx)
            if idx then
              ctl.param_info.paramstr2 = lvar.sk2data_slots[idx].map
              DBG(i..'  '..ctl.param_info.paramstr..'  '..ctl.param_info.paramstr2)
            end
          end
        end
        
      end
    end
    
  end
  
  function CheckSK2Slots()
  
    local strip = tracks[track_select].strip
    if strips and strips[strip] then

      if #strips[strip][page].controls > 0 then

        local mapped = {}
        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          if ctl.ctlcat == ctlcats.sk2ctl then
            local idx = tonumber(ctl.param_info.paramidx)
            if idx then
              if lvar.sk2data_slots[idx] and ctl.param_info.paramstr == lvar.sk2data_slots[idx].name and 
                 (ctl.param_info.paramstr2 or '') == lvar.sk2data_slots[idx].map then
                mapped[idx] = i
              else
                ctl.param_info.paramidx = nil
              end
            end
          end
        end
        
        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          if ctl.ctlcat == ctlcats.sk2ctl then
            local idx = tonumber(ctl.param_info.paramidx)
            if not idx then
              for s = 0, #lvar.sk2data_slots do
                if ctl.param_info.paramstr == lvar.sk2data_slots[s].name and 
                   (ctl.param_info.paramstr2 or '') == lvar.sk2data_slots[s].map and 
                   mapped[s] == nil then
                  ctl.param_info.paramidx = s
                  mapped[s] = i
                  break
                end
              end
              if not ctl.param_info.paramidx then
                DBG('Failed to match SK2 ctl: '..i..'  '..tostring(ctl.param_info.paramstr2)..' - '..ctl.param_info.paramstr)
              end
            end
          end
        end
        
      end
    end
    --DBG('done')
  end
  
  function RepatriateControls()

    local strip = tracks[track_select].strip
    if strips and strips[strip] then

      local switches = {}
      local switchgrps = {}
      if #strips[strip][page].controls > 0 then

        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          if ctl.switcherid then
            switches[ctl.switcherid] = true
            for g = 1, #switchers[ctl.switcherid].grpids do
              switchgrps[switchers[ctl.switcherid].grpids[g].id] = true
            end
          end
        end
        
        for i = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[i]
          if ctl.xsc+ctl.wsc < 0 or ctl.ysc + ctl.hsc < 0 or ctl.xsc > surface_size.w or ctl.ysc > surface_size.h then
            ctl.x = 0
            ctl.y = 0
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*ctl.scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*ctl.scale)/2)
          end
          if ctl.switcher then
            if not switches[ctl.switcher] then
              ctl.switcher = nil
            elseif ctl.grpid and not switchgrps[ctl.grpid] then
              ctl.switcher = nil
            end
          end
        end
      end
      if #strips[strip][page].graphics > 0 then
        for i = 1, #strips[strip][page].graphics do
          local ctl = strips[strip][page].graphics[i]
          if ctl.x+ctl.stretchw < 0 or ctl.y + ctl.stretchh < 0 or ctl.x > surface_size.w or ctl.y > surface_size.h then
            ctl.x = 0
            ctl.y = 0
          end
          if ctl.switcher then
            if not switches[ctl.switcher] then
              ctl.switcher = nil
            elseif ctl.grpid and not switchgrps[ctl.grpid] then
              ctl.switcher = nil
            end
          end
        end
      end
      lupd.update_gfx = true
      SetCtlBitmapRedraw()
    end

  end

  function GfxInfo(strip, page, c)

    local ctl = strips[strip][page].graphics[c]
    DBG('')
    DBG('----------------------------------------------')
    DBG('GFX INFO:')
    DBG('----------------------------------------------')
    DBG('')
    DBG('Gfx ID: '..c)
    DBG('Strip ID: '..tostring(ctl.id))
    DBG('GID: '..tostring(ctl.g_id))
    DBG('Grp ID: '..tostring(ctl.grpid))
    DBG('Switcher: '..tostring(ctl.switcher))

  end

  function CtlInfo(strip, page, c)

    local ctl = strips[strip][page].controls[c]
    DBG('')
    DBG('----------------------------------------------')
    DBG('CTL INFO:')
    DBG('----------------------------------------------')
    DBG('')
    DBG('Ctl ID: '..c)
    DBG('Strip ID: '..tostring(ctl.id))
    DBG('CID: '..tostring(ctl.c_id))
    DBG('Grp ID: '..tostring(ctl.grpid))
    DBG('Switcher: '..tostring(ctl.switcher))
    if ctl.ctlcat == ctlcats.switcher then
      DBG('SwitcherID: '..tostring(ctl.switcherid))
    end
    DBG('Type: '..lvar.ctltype_table[ctl.ctltype])
    DBG('Cat: '..ctl.ctlcat..' - '..string.upper(lvar.ctlcats_nm[ctl.ctlcat+1]))
    if ctl_files[ctl.knob_select] then
      DBG('Image FN: '..tostring(ctl_files[ctl.knob_select].fn))
    else

    end
    DBG('FX Name: '..ctl.fxname)
    DBG('Param: '..(ctl.param or 'nil'))
    DBG('Param Name: '..ctl.param_info.paramname)
    DBG('Param Num: '..(ctl.param_info.paramnum or 'nil'))
    DBG('Param Str: '..(ctl.param_info.paramstr or 'nil'))
    DBG('Param Str2: '..(ctl.param_info.paramstr2 or 'nil'))
    DBG('Param Idx: '..(ctl.param_info.paramidx or 'nil'))
    DBG('Display Name: '..tostring(ctl.ctlname_override))
    DBG('')
    DBG('Pos x: '..ctl.x)
    DBG('Pos y: '..ctl.y)
    DBG('Image Width: '..ctl.w)
    DBG('Image Height: '..ctl.ctl_info.cellh)
    DBG('')
    DBG('Scale: '..ctl.scale)
    DBG('Pos x (scaled): '..ctl.xsc)
    DBG('Pos y (scaled): '..ctl.ysc)
    DBG('Width (scaled): '..ctl.wsc)
    DBG('Height (scaled): '..ctl.hsc)
    DBG('')
    if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.rs5k then
      DBG('FX GUID: '..ctl.fxguid)
      local track = GetTrack(nz(ctl.tracknum,tracks[track_select].tracknum))
      if track then
        local fxguid = reaper.TrackFX_GetFXGUID(track, ctl.fxnum)
        local _, fxname = reaper.TrackFX_GetFXName(track, ctl.fxnum,'')
        local pname
        if ctl.param_info.paramnum then
          _, pname = reaper.TrackFX_GetParamName(track, ctl.fxnum,ctl.param_info.paramnum,'')
        end
        DBG('LINKED FX GUID: '..tostring(fxguid))
        DBG('LINKED FX NAME: '..tostring(fxname))
        DBG('LINKED PARAM NAME: '..tostring(pname))
      end
      DBG('OFFLINE: '..tostring(ctl.offline))
    end
    DBG('----------------------------------------------')
    if ctl.switcherid then
      DBG('Switcher ID: '..ctl.switcherid)
      DBG('Switcher SwitchMode: '..tostring(switchers[ctl.switcherid].switchmode))
      DBG('Switcher ExtendMode: '..tostring(switchers[ctl.switcherid].extendmode))
      DBG('Switcher ExtendID: '..tostring(switchers[ctl.switcherid].extendid))
      DBG('Switcher ExtendPos: '..tostring(switchers[ctl.switcherid].extendpos))
      for i = 1, #switchers[ctl.switcherid].grpids do
        DBG('Switcher GrpIDs: '..tostring(switchers[ctl.switcherid].grpids[i].id))
      end
    end
    DBG('----------------------------------------------')
  end

  function MenuStripFolders()

    local mstripfolders = {}
    local mstr = ''
    local cnt = 0
    local filcnt = 0
    local i = 0
    local sfol = reaper.EnumerateSubdirectories(paths.strips_path, i)
    while sfol ~= nil do

      local mfol = sfol
      i=i+1
      sfol = reaper.EnumerateSubdirectories(paths.strips_path, i)
      if sfol == nil then
        mstr = mstr ..'|<>'.. mfol
      else
        mstr = mstr ..'|>'.. mfol
      end

      local j = 0
      local sfil = reaper.EnumerateFiles(paths.strips_path..mfol, j)
      if sfil == nil then
        mstr = mstr ..'|<#Empty'
        mstripfolders[#mstripfolders+1] = ''
        cnt = cnt + 1
      else
      
        local sfc = 0
        while sfil ~= nil do
          local sfil2 = ''
          while sfil2 and string.sub(sfil2, string.len(sfil2)-5) ~= '.strip' do
            j=j+1
            sfil2 = reaper.EnumerateFiles(paths.strips_path..mfol, j)
          end
          --DBG(paths.strips_path..mfol..'     '..tostring(sfil2))
          if string.sub(sfil, string.len(sfil)-5) == '.strip' then
            sfc = sfc + 1
            cnt = cnt + 1
            filcnt = filcnt + 1

            local mfil = sfil
            mstripfolders[#mstripfolders+1] = mfol..'/'..mfil

            --j=j+1
            --sfil = reaper.EnumerateFiles(paths.strips_path..mfol, j)

            if sfil2 == nil then
              mstr = mstr ..'|<'..string.sub(mfil, 1, string.len(mfil)-6)
            else
              mstr = mstr ..'|'..string.sub(mfil, 1, string.len(mfil)-6)
            end
            sfil = sfil2
          else
            --j=j+1
            sfil = sfil2--reaper.EnumerateFiles(paths.strips_path..mfol, j)
          end

        end
        if sfc == 0 then
          mstr = mstr ..'|<#Empty'
          mstripfolders[#mstripfolders+1] = ''
          cnt = cnt + 1
        end
      end
    end
    --if filcnt == 0 then cnt = 0 end
    return cnt, mstr, mstripfolders

  end

  function RBMenu_Capture()

    if tracks[track_select] and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
      local snaps = snapshots[tracks[track_select].strip][page][sstype_select]

      local mod = ''
      if snaps.capturemods then
        mod = '!'
      end
      local iv = ''
      if snaps.ignorevals then
        iv = '!'
      end
      local ivv = ''
      if sstype_select == 1 then
        if #snaps > 0 then
          ivv = '#'
        end
      else
        if #snaps.snapshot > 0 then
          ivv = '#'
        end
      end
      local mstr = 'Capture faderbox settings|'..mod..'Capture modulators||'..ivv..iv..'Capture mods/faders only'
      if snaps.capturefaders then
        mstr = '!'..mstr
      end
      gfx.x, gfx.y = obj.sections[160].x + mouse.mx, obj.sections[160].y + mouse.my
      res = OpenMenu(mstr)

      if res ~= 0 then
        if res == 1 then
          settings_savefaderboxassinsnapshots = not settings_savefaderboxassinsnapshots
          snaps.capturefaders = not nz(snaps.capturefaders, false)
          lupd.update_gfx = true
        elseif res == 2 then
          settings_savemodsinsnapshots = not settings_savemodsinsnapshots
          snaps.capturemods = not nz(snaps.capturemods, false)
          lupd.update_gfx = true
        elseif res == 3 then
          snaps.ignorevals = not nz(snaps.ignorevals, false)
          lupd.update_gfx = true
        end
      end

    end
  end

  function TakeSwitcherMenu_RB(c)
    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]

    local mod = '||Clear Modulator'
    if not strips[strip][page].controls[c].mod then
      mod = '||#Clear Modulator'
    end
    local sno = ''
    if ctl.iteminfo and ctl.iteminfo.noteoff then
      sno = '!'
    end
    local mstr = 'Reassign to currently selected item||Refresh item info'..mod..'||'..sno..'Send Note Offs'
    gfx.x, gfx.y = mouse.mx, mouse.my
    res = OpenMenu(mstr)
    if res ~= 0 then
      if res == 1 then
        local pname = 'Take Selector'
        local item = reaper.GetSelectedMediaItem(0, 0)
        local iteminfo
        local itemno, tracknum, trackguid
        if item then
          iteminfo = GetMediaItemDetails(item, true)
          itemno = iteminfo.itemno
          tracknum = iteminfo.tracknum
          trackguid = iteminfo.trackguid

          ctl.iteminfo = iteminfo
          ctl.param = itemno
          ctl.fxname = pname

          if tracknum == track_select then
            ctl.tracknum = nil
            ctl.trackguid = nil
          else
            ctl.tracknum = tracknum
            ctl.trackguid = trackguid
          end

          SetCtlDirty(c)
          lupd.update_ctls = true
        end

      elseif res == 2 then
        if ctl.iteminfo then

          local item = GetMediaItemByGUID(ctl.iteminfo.guid)
          if item then
            iteminfo = GetMediaItemDetails(item, true)
            ctl.iteminfo = iteminfo
          end
          SetCtlDirty(c)
          lupd.update_ctls = true
        end
      elseif res == 3 then
        Mod_RemoveAssign(strip,page,c)
        ctl.mod = nil
        ctl.dirty = true
        lupd.update_ctls = true
        lupd.update_lfoedit = true

        SetCtlDirty(c)
      elseif res == 4 then
        if ctl.iteminfo then
          ctl.iteminfo.noteoff = not (ctl.iteminfo.noteoff or false)
          if ctl.iteminfo.noteoff == true then
            local fxn, fxg, tracknum
            fxn, fxg, tracknum = InsertTrackUtil(ctl.iteminfo.tracknum, ctl.iteminfo.trackguid)
            if fxn and tracknum then

              ctl.iteminfo.tracknum = tracknum
              ctl.iteminfo.utilfxn = fxn
              ctl.iteminfo.utilguid = fxg

            else
              ctl.iteminfo.utilfxn = nil
              ctl.iteminfo.utilguid = nil
            end
          end
        end
      end
    end

  end

  function RS5kMenu_RB(i)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[i]

    local rsc = '#'
    if ctl.rsdata and ctl.rsdata.samplefolder then
      rsc = ''
    end

    local mstr = 'Open Plugin Window||'..rsc..'Open Sample Folder||'..rsc..'Rescan Current Folder||Load Folder|Load Folder (include subfolders)||Manage Samples'
    if #ctl.rsdata.samples > 0 then
      local smps = '|'
      for i = 1, #ctl.rsdata.samples do
        smps = smps .. '|'.. (ctl.rsdata.samples[i].fn or '[No sample]')
      end
      mstr = mstr .. smps
    end

    gfx.x, gfx.y = mouse.mx, mouse.my
    res = OpenMenu(mstr)
    if res > 0 then

      if res == 2 then

        OpenURL(ctl.rsdata.samplefolder)

      elseif res == 3 then

        RS5k_RescanFolder(strip, page, i)

      elseif res == 4 then

        RS5k_LoadFolder(strip, page, i, false)

      elseif res == 5 then

        RS5k_LoadFolder(strip, page, i, true)

      elseif res == 1 then

        OpenFXGUI(ctl)

      elseif res == 6 then

        SetShowSampleManager(true, i)

      elseif res >= 7 then

        local v = res - 6
        if ctl.rsdata.samples[v].fn then
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', ctl.rsdata.samples[v].fol..ctl.rsdata.samples[v].fn)
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        else
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'FILE0', '')
          reaper.TrackFX_SetNamedConfigParm(track, ctl.fxnum, 'DONE', '')
        end
        ctl.val = math.floor((v-1) / lvar.maxsamples)
        SetCtlDirty(i)
        lupd.update_ctls = true

      end

    end

  end

  --Thanks X-Raym
  function OpenURL(url)
    local OS = reaper.GetOS()
    if OS == "OSX32" or OS == "OSX64" then
      os.execute('open "" "' .. url .. '"')
    else
      os.execute('start "" "' .. url .. '"')
    end
  end

  function GetTrackFXTable(trn)

    local tab = {}
    local track = GetTrack(trn)
    if track then
      local fxcnt = reaper.TrackFX_GetCount(track)-1
      local _, trnm = reaper.GetTrackName(track,'')
      tab.fxcnt = fxcnt
      tab.trackname = trnm
      for i = 0, fxcnt do
        local _, fxnm = reaper.TrackFX_GetFXName(track, i, '')
        tab[i] = {name = fxnm,
                  guid = reaper.TrackFX_GetFXGUID(track, i)}
      end
    end
    return tab

  end

  function GetAllTrackFXTable()

    local tab = {}
    local trcnt = reaper.GetNumTracks()-1
    tab.trcnt = trcnt
    for i = -1, trcnt do
      tab[i] = GetTrackFXTable(i)
    end
    return tab

  end

  function FXMultiMenu_RB(i)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[i]

    local fxtab = GetAllTrackFXTable()
    local ctrtab = GetTrackFXTable(tracks[track_select].tracknum)

    local guids = {}
    guids[ctl.fxguid] = '!'
    if ctl.addfx then
      for i = 1, #ctl.addfx do
        guids[ctl.addfx[i].guid] = '!'
      end
    end

    local mstr = ''
    if ctrtab.fxcnt >= 0 then
      mstr = '>Current Track'
    else
      mstr = '>#Current Track'
    end
    for i = 0, ctrtab.fxcnt do
      mstr = mstr .. '|'
      if i == ctrtab.fxcnt then
        mstr = mstr .. '<'
      end
      mstr = mstr .. (guids[ctrtab[i].guid] or '') .. ctrtab[i].name
    end
    mstr = mstr .. '|'
    for i = -1, fxtab.trcnt do
      if fxtab[i].fxcnt >= 0 then
        mstr = mstr .. '|>'..i+1 ..': ' .. fxtab[i].trackname
      else
        mstr = mstr .. '|#'..i+1 ..': ' .. fxtab[i].trackname
      end
      for f = 0, fxtab[i].fxcnt do
        mstr = mstr .. '|'
        if f == fxtab[i].fxcnt then
          mstr = mstr .. '<'
        end
        mstr = mstr .. (guids[fxtab[i][f].guid] or '') .. fxtab[i][f].name
      end
    end

    gfx.x = mouse.mx
    gfx.y = mouse.my
    local res = gfx.showmenu(mstr)
    if res > 0 then
      res = res - 1
      if res <= ctrtab.fxcnt then
        --DBG(ctrtab[res].name)
        if not guids[ctrtab[res].guid] then
          CtlAddFX_Add(ctl, tracks[track_select].tracknum, res, ctrtab[res].guid)
        else
          CtlAddFX_Rem(ctl, ctrtab[res].guid)
        end
      else
        res = res - (ctrtab.fxcnt+1)
        local trn
        for tr = -1, fxtab.trcnt do
          if fxtab[tr].fxcnt >= 0 then
            if res <= fxtab[tr].fxcnt then
              trn = tr
              break
            end
            res = res - (fxtab[tr].fxcnt+1)
          else
            res = res - 1
          end
        end
        --DBG('fx: '..fxtab[trn][res].name)
        if not guids[fxtab[trn][res].guid] then
          CtlAddFX_Add(ctl, trn, res, fxtab[trn][res].guid)
        else
          CtlAddFX_Rem(ctl, fxtab[trn][res].guid)
        end
      end

    end

  end

  function CtlAddFX_Add(ctl, trn, fxnum, guid)
    if not ctl.addfx then
      ctl.addfx = {}
    end
    local trguid = tracks[trn].guid
    ctl.addfx[#ctl.addfx+1] = {trn = trn, trguid = trguid, fxnum = fxnum, guid = guid}
  end

  function CtlAddFX_Rem(ctl, guid)
    if ctl.addfx then
      local tab = {}
      for i = 1, #ctl.addfx do
        if ctl.addfx[i].guid ~= guid then
          table.insert(tab, ctl.addfx[i])
        end
      end
      ctl.addfx = tab
      if ctl.addfx and #ctl.addfx == 0 then
        ctl.addfx = nil
      end
    end
  end

  function SK2CtlMenu_RB(i)
  
    local strip = tracks[track_select].strip
    
    local csel
    if not i then
      i = ctl_select[1].ctl
      csel = true
    end

    local ctls = strips[strip][page].controls
    local ctl = ctls[i]
    if ctl then
      
      if mouse.shift then
        --local mstr = '>Mapped control|'
        local ddtab = {idx = 6, ctl = ctl, bottom = true, hcentre = true, x = mouse.mx, y = mouse.my, w = 200, h = 100, items = {}, itemcol = {}, itemdisabled = {}, indcol = {}, data = {}, wpad = 40, scroll = -1}
        
        local usedidx = {}
        for c = 1, #ctls do
          if ctls[c].ctlcat == ctlcats.sk2ctl then
            local idx = tonumber(ctls[c].param_info.paramidx)
            if idx then
              usedidx[idx] = 1
            end
          end
        end
        
        local tcg = 'OFF'
        if tonumber(ctl.param_info.paramnum or 0)&1 == 1 then
          tcg = 'ON'
        end
        local tct = 'OFF'
        if tonumber(ctl.param_info.paramnum or 0)&2 == 2 then
          tct = 'ON'
        end
        ddtab.items[1] = 'Tint control graphics: '..tcg
        ddtab.items[2] = 'Tint control text: '..tct
        ddtab.items[3] = '-------'
        ddtab.itemdisabled[3] = true
        local offs = 3
        
        for s = 1, #lvar.sk2data_slots do
          local tick = ''
          if ctl.param_info.paramidx == s-1 then
            tick = '!'
          end
          ddtab.items[s+offs] = tostring(lvar.sk2data_slots[s-1].name or '')
          if usedidx[s-1] == 1 then
            --DBG('s'..s..' ')
            ddtab.itemdisabled[s+offs] = true
          end
  
          --mstr = mstr .. tick .. (lvar.sk2data_slots[s-1].name or '') .. '|'
        
        end
        
        OpenDropDown(7, ddtab, true, true)
      
      end
      
      --[[gfx.x = mouse.mx
      gfx.y = mouse.my
      local res = gfx.showmenu(mstr)
      if res > 0 then
          ctl.param_info.paramidx = res-1
          lvar.sk2data_assign = nil
      end]]
    end
  end
  
  function InfoCtlMenu_RB(i)

    local strip = tracks[track_select].strip

    local csel
    if not i then
      i = ctl_select[1].ctl
      csel = true
    end

    local ctl = strips[strip][page].controls[i]
    --local mstr = ''
    local main = ''
    local suskip = 0
    local trn = ctl.tracknum or tracks[track_select].tracknum
    local fxnum

    if ctl.param == 2 then
      fxnum = ctl.param_info.paramidx + (lvar.slotoffset[trn] or 0)

      local tr = GetTrack(trn)
      if not tr then return end

      local paste = '#'
      local pastefxname = ''
      local pastestr = 'Paste FX'
      if lvar.copyfx then
        local str = GetTrack(lvar.copyfx.trn)
        local sfxnum, str = GetFXNFromGUID(str,lvar.copyfx.guid,true)
        if sfxnum and str then
          paste = ''
          pastefxname = ' ('..lvar.copyfx.name..')'
        end
      end

      if fxnum < reaper.TrackFX_GetCount(tr) and csel ~= true then
        main = 'Delete FX||Copy FX|'..paste..'Paste FX'..pastefxname..'|'..paste..'Paste FX'..pastefxname..' (Delete Original)'
      else
        main = '#Delete FX||#Copy FX|'..paste..'Paste FX'..pastefxname..'|'..paste..'Paste FX'..pastefxname..' (Delete Original)'
      end
      suskip = 4
    end

    cspec = ''
    if suskip ~= 0 then
      cspec = cspec ..'||'
    end
    cspec = cspec..'>InfoCtl Setup'
    local xtr
    for i = 1, #lvar.infoctl_table do
      cspec = cspec..'|'
      if ctl.param == i then
        cspec = cspec..'!'
        xtr = i
      end
      cspec = cspec..lvar.infoctl_table[i]
    end
    if xtr == 2 then
      cspec = cspec..'||>Select FX Slot'
      for i = 1, 64 do
        cspec = cspec..'|'
        if tonumber(ctl.param_info.paramidx) == i-1 then
          cspec = cspec..'!'
        end
        cspec = cspec..'FX '..i
      end
    end

    local mstr = main .. cspec
    gfx.x, gfx.y = mouse.mx, mouse.my
    res = OpenMenu(mstr)
    if res ~= 0 then
      if res >= 1+suskip and res < 1+suskip +#lvar.infoctl_table then
        if csel then
          for c = 1, #ctl_select do
            local cc = ctl_select[c].ctl
            local ctl = strips[strip][page].controls[cc]
            if ctl then
              ctl.param = res - (1+suskip)+1
              ctl.param_info.paramidx = 0
            end
          end
        else
          ctl.param = res - (1+suskip)+1
          ctl.param_info.paramidx = 0
        end
      elseif ctl.param == 2 and res >= 1+suskip +#lvar.infoctl_table then
        --fx
        if csel then
          for c = 1, #ctl_select do
            local cc = ctl_select[c].ctl
            local ctl = strips[strip][page].controls[cc]
            if ctl then
              ctl.param_info.paramidx = res - (1+suskip +#lvar.infoctl_table)
            end
          end
        else
          ctl.param_info.paramidx = res - (1+suskip +#lvar.infoctl_table)
        end
      elseif ctl.param == 2 and res < 1+suskip then
        if res == 1 then
          --Delete FX
          --local trn = ctl.tracknum or tracks[track_select].tracknum
          --local fxnum = ctl.param_info.paramidx + (lvar.slotoffset[trn] or 0)
          DeleteFX(trn, fxnum+1)
        elseif res == 2 then
          local tr = GetTrack(trn)
          if not tr then return end
          local _, fxname = reaper.TrackFX_GetFXName(tr, fxnum, '')
          lvar.copyfx = {guid = reaper.TrackFX_GetFXGUID(tr, fxnum),
                         name = TrimStr(CropFXName(fxname)),
                         trn = trn}
        elseif res == 3 then
          local str = GetTrack(lvar.copyfx.trn)
          local sfxnum, str = GetFXNFromGUID(str,lvar.copyfx.guid,true)
          if sfxnum and str then
            local tr = GetTrack(trn)
            if not tr then return end
            reaper.Undo_BeginBlock()
            local ubtxt = 'LBX Paste FX'
            if tr == str and sfxnum < fxnum then --fix some weirdness
              reaper.TrackFX_CopyToTrack(str,sfxnum,tr,fxnum-1,false)
            else
              reaper.TrackFX_CopyToTrack(str,sfxnum,tr,fxnum,false)
            end
            reaper.Undo_EndBlock(ubtxt, 0)
          else
            OpenMsgBox(1, 'Cannot find FX to copy', 1)
            lvar.copyfx = nil
          end

        elseif res == 4 then
          local str = GetTrack(lvar.copyfx.trn)
          local sfxnum, str = GetFXNFromGUID(str,lvar.copyfx.guid,true)
          if sfxnum and str then
            local tr = GetTrack(trn)
            if not tr then return end
            reaper.Undo_BeginBlock()
            local ubtxt = 'LBX Cut + Paste FX'
            if tr == str and sfxnum < fxnum then --fix some weirdness
              reaper.TrackFX_CopyToTrack(str,sfxnum,tr,fxnum-1,false)
            else
              reaper.TrackFX_CopyToTrack(str,sfxnum,tr,fxnum,false)
            end
            local sfxnum, str = GetFXNFromGUID(str,lvar.copyfx.guid,true)
            if sfxnum and str then
              reaper.TrackFX_Delete(str, sfxnum)
              lvar.copyfx = nil
            end
            reaper.Undo_EndBlock(ubtxt, 0)

          else
            OpenMsgBox(1, 'Cannot find FX to copy', 1)
            lvar.copyfx = nil
          end
        end
      end
    end

  end

  function InfoCtlMenu(mx, my)

    local strip = tracks[track_select].strip
    local i
    local csel
    if not i then
      i = ctl_select[1].ctl
      csel = true
    end

    local ctl = strips[strip][page].controls[i]
    --local mstr = ''
    local main = ''
    local suskip = 0
    local trn = ctl.tracknum or tracks[track_select].tracknum

    cspec = ''
    local xtr
    for i = 1, #lvar.infoctl_table do
      cspec = cspec..'|'
      if ctl.param == i then
        cspec = cspec..'!'
        xtr = i
      end
      cspec = cspec..lvar.infoctl_table[i]
    end
    if xtr == 2 then
      cspec = cspec..'||>Select FX Slot'
      for i = 1, 64 do
        cspec = cspec..'|'
        if tonumber(ctl.param_info.paramidx) == i-1 then
          cspec = cspec..'!'
        end
        cspec = cspec..'FX '..i
      end
    end

    local mstr = main .. cspec
    gfx.x, gfx.y = mx, my
    res = OpenMenu(mstr)
    if res ~= 0 then
      if res >= 1+suskip and res < 1+suskip +#lvar.infoctl_table then
        if csel then
          for c = 1, #ctl_select do
            local cc = ctl_select[c].ctl
            local ctl = strips[strip][page].controls[cc]
            if ctl then
              ctl.param = res - (1+suskip)+1
              ctl.param_info.paramidx = 0
            end
          end
        else
          ctl.param = res - (1+suskip)+1
          ctl.param_info.paramidx = 0
        end
      elseif ctl.param == 2 and res >= 1+suskip +#lvar.infoctl_table then
        --fx
        if csel then
          for c = 1, #ctl_select do
            local cc = ctl_select[c].ctl
            local ctl = strips[strip][page].controls[cc]
            if ctl then
              ctl.param_info.paramidx = res - (1+suskip +#lvar.infoctl_table)
            end
          end
        else
          ctl.param_info.paramidx = res - (1+suskip +#lvar.infoctl_table)
        end
      elseif ctl.param == 2 and res < 1+suskip then
        if res == 1 then
          --Delete FX
          --local trn = ctl.tracknum or tracks[track_select].tracknum
          --local fxnum = ctl.param_info.paramidx + (lvar.slotoffset[trn] or 0)
          DeleteFX(trn, fxnum+1)
        end
      end
    end

  end

  function IndexExtIdentifiers(s, p)
  
    if strips and strips[s] and strips[s][p] then

      local ctls = strips[s][p].controls
      local eids = lvar.extidentifiers
      for c = 1, #ctls do
        local ctl = ctls[c]
        if ctl.ext_identifier then
          eids[ctl.ext_identifier] = {ctl = ctl, strip = s, page = p, c = c}
          --DBG(ctl.ext_identifier..' '..s..' '..p..' '..c)
        end
      end
    end
  end

  function IndexAllExtIdentifiers()
    lvar.extidentifiers = {}
    for s = 1, #strips do
      if strips and strips[s] then
        for p = 1, lvar.maxpage do
          if strips[s][p] then
            local ctls = strips[s][p].controls
            local eids = lvar.extidentifiers
            for c = 1, #ctls do
              local ctl = ctls[c]
              if ctl.ext_identifier then
                eids[ctl.ext_identifier] = {ctl = ctl, strip = s, page = p, c = c}
              end
            end
          end
        end
      end
    end
  end
  
  function SetExtIdentifier(ctl, c)
  
    local retval, id = reaper.GetUserInputs('External Identifier',1,'External Identifier String:,extrawidth=220',ctl.ext_identifier or '')
    if retval then
      if id ~= '' then
        local eid = lvar.extidentifiers[id]
        if eid then
          if eid.strip == tracks[track_select].strip and eid.page == page and eid.c == c then
            ctl.ext_identifier = id
            lvar.extidentifiers[id] = {ctl = ctl, strip = tracks[track_select].strip, page = page, c = c}
          else
            reaper.MB('External identifier already assigned to another control','External Identifier',0)
          end
        else
          ctl.ext_identifier = id
          lvar.extidentifiers[id] = {ctl = ctl, strip = tracks[track_select].strip, page = page, c = c}
        end
      else
        ctl.ext_identifier = nil
        local eid = lvar.extidentifiers[id]
        if eid then
          if eid.strip == tracks[track_select].strip and eid.page == page and eid.c == c then
            lvar.extidentifiers[id] = nil
          end
        end
      end
    end
  
  end
  
  function RBMenu(mtype,ccat,i)
    if mtype == 0 then

      if ccat == ctlcats.switcher then
        switcher_select = i
        SwitcherMenu_RB()
      elseif ccat == ctlcats.takeswitcher then
        TakeSwitcherMenu_RB(i)
      elseif ccat == ctlcats.rs5k then
        RS5kMenu_RB(i)
      elseif ccat == ctlcats.fxmulti then
        FXMultiMenu_RB(i)
      elseif ccat == ctlcats.infoctl then
        InfoCtlMenu_RB(i)
      elseif ccat == ctlcats.sk2ctl and mouse.shift then
        --SK2CtlMenu_RB(i)
      else
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[i]
        local mstr
        local mm = ''
        if show_snapshots then
          mm = '!'
        end
        lspfx = ''
        if settings_locksurface then
          lspfx = '!'
        end
        local mido = '>Midi/OSC Out|#Set|<#Clear'
        if ccat == ctlcats.fxparam or ccat == ctlcats.trackparam or ccat == ctlcats.macro or ccat == ctlcats.midictl or ctlcats.action then
          local moclr = '|<#Clear'
          if ctl.midiout then
            moclr = '|<Clear'
          end
          mido = '>Midi/OSC Out|Set'..moclr
        end
        local ff = ''
        local fft = ''
        if ctl.macrofader then
          fft = '!'
          ff = '   [Fader '..string.format('%i',ctl.macrofader)..']'
        end
        local fdinact = false
        if ccat == ctlcats.fxparam then
        elseif ccat == ctlcats.trackparam or ccat == ctlcats.tracksend or ccat == ctlcats.macro or ccat == ctlcats.snapshot or ccat == ctlcats.midictl then
        else
          fdinact = true
        end
        local fd, lastp = FaderMenu(-1,true,fdinact)

        local cspec = ''
        if ccat == ctlcats.snapshot then
          local asc, bsc, fsc, ffsc = '', '', '', '#'
          if ctl.param_info.paramnum == 1 then
            bsc = '!'
          elseif ctl.param_info.paramnum == 2 then
            fsc = '!'
            ffsc = ''
          else
            asc = '!'
          end
          cspec = '||>Control Specific|'..asc..'Advanced Snapshot Control|'..bsc..'Basic Snapshot Control||'..fsc..'Fixed Snapshot Control||<'..ffsc..'Assign To Selected Subset/Snapshot'
        elseif ccat == ctlcats.fxparam then
          cspec = '||>Control Specific|Threshold Switch'
        elseif ccat == ctlcats.threshold then
          --[[if ctl.thresh == nil then
            ctl.thresh = {off = 5,
                          on = 10}
          end]]
          local threshinv = ''
          if ctl.thresh.invert == true then
            threshinv = '!'
          end
          cspec = '||>Control Specific|!Threshold Switch||Set Off Threshold To Current Value|Set On Threshold To Current Value||#Off Threshold = '..ctl.thresh.thresh_off..'|#On Threshold =  '..
                  ctl.thresh.thresh_on..'||'..threshinv..'Invert On/Off Values'
        elseif ccat == ctlcats.paramvalue_glob then
          local pnpn = ''
          if tonumber(ctl.param_info.paramidx) == 1 then
            pnpn = '!'
          end
          cspec = '||>Control Specific|Strip only||'..pnpn..'Show parameter name'
        elseif ccat == ctlcats.paramvalue_strip then
          local pnpn = ''
          if tonumber(ctl.param_info.paramidx) == 1 then
            pnpn = '!'
          end
          cspec = '||>Control Specific|!Strip only||'..pnpn..'Show parameter name'

        end

        local mod = '||Clear Modulator'
        if not strips[tracks[track_select].strip][page].controls[i].mod then
          mod = '||#Clear Modulator'
        end


        local unl = '||Unlock All Controls'
        local ext 
        if lvar.livemode == 0 then
          if ctl.ext_identifier then
            ext = '||External Identifier: '..ctl.ext_identifier
          else
            ext = '||Set External Identifier'
          end
        else
          ext = '||#Set External Identifier'
        end
        if ccat == ctlcats.fxparam then
          mstr = fft..'Faderbox learn (global)'..ff..'||'..fd..mod..'||Param Modulation||Enter value||'..mido..'||Open FX window||Add Envelope|Add All Envelopes For Plugin||'..mm..'Snapshots||>Tools|<Regenerate ID   (emergency only)||Toggle Topbar|Toggle Sidebar||'..lspfx..'Lock Surface'..unl..ext..cspec
        elseif ccat == ctlcats.trackparam or ccat == ctlcats.tracksend or ccat == ctlcats.macro or ccat == ctlcats.snapshot or ccat == ctlcats.midictl then
          mstr = fft..'Faderbox learn (global)'..ff..'||'..fd..mod..'|#Param Modulation||Enter value||'..mido..'||#Open FX window||#Add Envelope|#Add All Envelopes For Plugin||'..mm..'Snapshots||>Tools|<Regenerate ID   (emergency only)||Toggle Topbar|Toggle Sidebar||'..lspfx..'Lock Surface'..unl..ext..cspec
        else
          mstr = fft..'#Faderbox learn (global)'..ff..'||'..fd..mod..'|#Param Modulation||Enter value||'..mido..'||#Open FX window||#Add Envelope|#Add All Envelopes For Plugin||'..mm..'Snapshots||>Tools|<Regenerate ID   (emergency only)||Toggle Topbar|Toggle Sidebar||'..lspfx..'Lock Surface'..unl..ext..cspec
        end

        --if ccat ~= ctlcats.macro then
          --if #strip_favs > 0 then
          --  mstr = mstr .. '||#>Insert strip (favorites)'
          --end
          trackfxparam_select = i
          gfx.x, gfx.y = mouse.mx, mouse.my
          res = OpenMenu(mstr)
          if res ~= 0 then
            if res == 1 then
              --SetParam2(true)
              --reaper.Main_OnCommand(41144,0,0)
              --reaper.OscLocalMessageToHost('/lbx/midilearn')
              lbx_midilrnctl = i

              lbx_midilrnval = strips[tracks[track_select].strip][page].controls[lbx_midilrnctl].macrofader
              if lbx_midilrnval then
                lbx_midilrnoff = nz(faders[lbx_midilrnval].voffset,0)
              else
                lbx_midilrnoff = 0
              end
              lupd.update_surface = true
            elseif res < 2 + lastp then

              if res == 1 + lastp then
                DeleteFader(ctl.macrofader)
                ctl.macrofader = nil
              else
                local fd = res-1

                if ctl.ctlcat == ctlcats.snapshot then
                  tt = 7
                else
                  tt = 4
                end

                local f = {targettype = tt,
                           strip = tracks[track_select].strip,
                           page = page,
                           ctl = i,
                           c_id = ctl.c_id,
                           voffset = 0}
                if lvar.livemode == 2 then
                  f.dm_trn = lvar.dynamicmode_trn
                  f.dm_guid = lvar.dynamicmode_guid
                end

                AssignFader(fd,f)
              end

            elseif res == 2 +lastp then
              if lvar.livemode == 2 then
                Mod_RemoveAssign(strip,page,i,lvar.dynamicmode_guid)
              else
                Mod_RemoveAssign(strip,page,i)
              end
              ctl.mod = nil
              ctl.dirty = true
              lupd.update_ctls = true
              lupd.update_lfoedit = true

              SetCtlDirty(i)

            elseif res == 3 +lastp then
              SetParam2(true)
              reaper.Main_OnCommand(41143,0)
            elseif res == 4 +lastp then
              --EditValue(5)
              OpenEB(5,'Please enter value:')
            elseif res == 5 +lastp then
              midioutedit_select = i
              midiout_select = ctl.midiout
              if midiout_select == nil then
                midiout_select = {output = nil,
                                  msgtype = 4,
                                  mchan = 1,
                                  msg3 = 1,
                                  msg4 = 0,
                                  vmin = 0,
                                  vmax = 127,
                                  focus = 1,
                                  focus_wintit = nil,
                                  focus_winexact = false,
                                  updategfx = false}
              end
              show_midiout = true
              lupd.update_gfx = true
              RedrawGUIBitmap()
              
            elseif res == 6 +lastp then
              ctl.midiout = nil

            elseif res == 7 +lastp then
              if ctl.fxfound then
                OpenFXGUI(ctl)
              end

            elseif res == 8 +lastp then
              Envelope_Add(strip,page,i)
            elseif res == 9 +lastp then
              Envelope_AddAllFX(strip,page,i)
            elseif res == 10 +lastp then
              SetShowSS(not show_snapshots)
              lupd.update_gfx = true
            elseif res == 11 +lastp then
              i = tonumber(string.format('%i',i))
              ctl = GetControlTable(strip, page, i)
              ctl.c_id = GenID()
              lupd.update_gfx = true
            elseif res == 12 +lastp then
              ToggleTopbar()
            elseif res == 13 +lastp then
              ToggleSidebar()
              lupd.update_surface = true
            elseif res == 14 +lastp then
              settings_locksurface = not settings_locksurface
            elseif res == 15 +lastp then
              UnlockControls(tracks[track_select].strip,page)
            elseif res == 16 +lastp then
              SetExtIdentifier(ctl, i)
              
            elseif res == 17 +lastp then
              if ccat == ctlcats.snapshot then
                ctl.param_info.paramnum = nil
              elseif ccat == ctlcats.fxparam then
                ctl.param_info.paramidx = ctlcats.fxparam
                ctl.ctlcat = ctlcats.threshold
                ctl.thresh = {thresh_off = 5, thresh_on = 10, val_off = 0, val_on = 1, invert = false}

              elseif ccat == ctlcats.threshold then
                ctl.ctlcat = tonumber(ctl.param_info.paramidx)
              elseif ccat == ctlcats.paramvalue_glob then
                ctl.ctlcat = ctlcats.paramvalue_strip
              elseif ccat == ctlcats.paramvalue_strip then
                ctl.ctlcat = ctlcats.paramvalue_glob
              end
              SetCtlDirty(i)
              lupd.update_ctls = true
            elseif res == 18 +lastp then
              if ccat == ctlcats.snapshot then
                ctl.param_info.paramnum = 1
              elseif ccat == ctlcats.threshold then
                ctl.thresh.thresh_off = math.floor(ctl.val*127)
              elseif ccat == ctlcats.paramvalue_glob then
                ctl.param_info.paramidx = 1 - tonumber(ctl.param_info.paramidx or 0)
              elseif ccat == ctlcats.paramvalue_strip then
                ctl.param_info.paramidx = 1 - tonumber(ctl.param_info.paramidx or 0)
              end
            elseif res == 19 +lastp then
              if ccat == ctlcats.snapshot then
                local xsstype_select = ctl.param
                if snapshots and snapshots[strip] and snapshots[strip][page][xsstype_select]
                                            and snapshots[strip][page][xsstype_select].selected then
                  local xss_select = snapshots[strip][page][xsstype_select].selected
                  ctl.param_info.paramnum = 2
                  ctl.param_info.paramidx = xss_select
                  SetCtlDirty(i)
                end
              elseif ccat == ctlcats.threshold then
                ctl.thresh.thresh_on = math.floor(ctl.val*127)
              end
            elseif res == 20 +lastp then
              if ccat == ctlcats.snapshot then
                ctl.param = sstype_select
                ctl.param_info.paramidx = ss_select
                SetCtlDirty(i)
              end
            elseif res == 22 +lastp then
              if ccat == ctlcats.threshold then
                ctl.thresh.invert = not ctl.thresh.invert
              end
            end


          end
        --end
      end
    elseif mtype == 1 then

      mm = ''
      if show_snapshots then
        mm = '!'
      end
      local mstr = ''
      local sfcnt = #strip_favs
      if sfcnt > 0 then
        mstr = mstr .. '>Insert strip (favorites)'
        for fvs = 1, sfcnt do
          if fvs == sfcnt then
            mstr = mstr .. '|<' .. string.match(strip_favs[fvs],'.+/(.-).strip')
          else
            mstr = mstr .. '|' .. string.match(strip_favs[fvs],'.+/(.-).strip')
          end
        end
      else
        mstr = mstr .. '>Insert strip (favorites)|<#Empty'
        sfcnt = 1
      end
      local sffcnt, sflist, msf = MenuStripFolders()
      if sflist ~= '' then
        mstr = mstr .. '|>Insert strip (folders)' .. sflist
        sfcnt = sfcnt + sffcnt
      end

      local lspfx = ''
      if settings_locksurface then
        lspfx = '!'
      end
      mstr = mstr .. '||#Faderbox learn (global)|#Modulation||#Enter value||#Open FX window||'..mm..'Snapshots||Toggle Topbar|Toggle Sidebar||'..lspfx..'Lock Surface'..
                     '||>Envelopes|Bypass Envelopes|Enable Envelopes|Clear Envelopes||Bypass Strip Envelopes|Enable Strip Envelopes|<Clear Strip Envelopes||Unlock All Controls'
      local mmstr = ''
      if mode == 0 and lvar.livemode >= 1 then
        local mo, mo2, mo6, mo7, mo8, mo9 = '', '', '', '', '', ''
        if lvar.mixmodedir == 0 then
          mo = '!'
          mo2 = ''
        else
          mo = ''
          mo2 = '!'
        end
        if lvar.mm_disablenonpoppedctls then
          mo6 = '!'
        end
        if lvar.showpoponly then
          mo7 = '!'
        end
        if lvar.mmtouch then
          mo8 = '!'
        end
        local ma = ''
        if lvar.mixmodealign == 1 then
          ma = '!'
        end
        local fp = ''
        if lvar.mm_fadepop ~= 1 then
          fp = '!'
        end
        if lvar.dm_singlepopup then
          mo9 = '!'
        end
        local mt = ''
        if lvar.dm_showtrackname then
          mt = '!'
        end
        local puaa = ''
        if lvar.popout_autoarrange then
          puaa = '!'
        end
        local puaafx = ''
        if lvar.autoarrange_activefx then
          puaafx = '!'
        end
        mmstr = '||>Mix Mode Options|'..mo2..'Horizontal Layout|'..mo..'Vertical Layout||'..ma..'Align Left/Top||'
                ..fp..'Fade Stack When Strip Popped|Fade Alpha ('..string.format('%i',lvar.mm_fadepopamt*100)..')||'..mo6..'Disable Stack When Strip Popped'..
                '|'..mo7..'Pop Up Only Mode|'..mo9..'Single Pop Up Only Mode|'..puaa..'Pop Up: Auto Arrange|'..puaafx..'Pop Up: Auto Arrange - Active FX||'..mo8..'Enable SK2 Touch||<'..mt..'Show Track Name On Surface (DM Mode)'

      else
        mmstr = '||>#Mix Mode Options|Horizontal Layout|Vertical Layout||Align Left/Top||Fade Stack When Strip Popped|Fade Alpha||Disable Stack When Strip Popped|Pop Up Only Mode|'..
                'Single Pop Up Only Mode|Pop Up: Auto Arrange|Pop Up: Auto Arrange - Active FX||Enable SK2 Touch||<Show Track Name On Surface (DM Mode)'
      end

      local bstr = ''
      if mode == 0 then
        local mo3, mo4, mo5 = '', '', ''
        if lvar.mmov_bgimgon then
          mo3 = '!'
        end
        if lvar.bgstretch then
          mo4 = '!'
        end
        if lvar.livebg then
          mo5 = '!'
        end
        local bg0 = ''
        if lvar.bgcentred then
          bg0 = '!'
        end

        local ta = lvar.mmov_tint
        bstr = '||Set Background Image|Clear Background Image||>BG Options|'..mo4..'Stretch Image|'
                ..'Brightness ('..string.format('%i',lvar.bgbright)..')||'
                ..mo3..'Add Image To Surface Toolbars|Tint Amount ('..ta..')||'..mo5..'Add Image To Live Mode Pages||'..bg0..'Centre Image In Mix/Dynamic Modes|<'
                ..'Set Image Offset'
      else
        bstr = '||#Set BG Image|#Clear BG Image||>#BG Options|Stretch Image|Brightness||Add Image To Surface Toolbars|Tint Amount||Add Image To Live Mode Pages||<Centre Pages In Mix/Dynamic Modes|'
                ..'Set Image Offset'        
      end
      
      local xstr = ''
      if lvar.livemode == 0 then
        xstr = '||>Track Templates|Create Track Template Strips (selected tracks) - rename track|<Create Track Template Strips (selected tracks)'
      else
        xstr = '||>Track Templates|#Create Track Template Strips (selected tracks) - rename track|<#Create Track Template Strips (selected tracks)'
      end
      mstr = mstr .. mmstr .. bstr .. xstr
      gfx.x, gfx.y = mouse.mx, mouse.my
      --DBG(mstr)
      res = OpenMenu(mstr)
      if res ~= 0 then
        if res == sfcnt + 5 then
          SetShowSS(not show_snapshots)
        elseif res == sfcnt + 6 then
          ToggleTopbar()
        elseif res == sfcnt + 7 then
          ToggleSidebar()
          lupd.update_surface = true
        elseif res == sfcnt + 8 then
          settings_locksurface = not settings_locksurface

        elseif res <= sfcnt then
          loadstrip = nil

          if res <= #strip_favs then
            local fn = strip_favs[res]
            InsStrip(fn)
          else

            local fn = msf[res-math.max(#strip_favs,1)]
            InsStrip(fn)
          end

        elseif res == sfcnt + 9 then
          Envelopes_SetProps(false,nil,false,false)
        elseif res == sfcnt + 10 then
          Envelopes_SetProps(true,nil,true,false)
        elseif res == sfcnt + 11 then
          --delete envs
          Envelopes_SetProps(nil,nil,nil,true)
        elseif res == sfcnt + 12 then
          Envelopes_SetProps(false,nil,false,false,tracks[track_select].strip,page)
        elseif res == sfcnt + 13 then
          Envelopes_SetProps(true,nil,true,false,tracks[track_select].strip,page)
        elseif res == sfcnt + 14 then
          --delete strip envs
          Envelopes_SetProps(nil,nil,nil,true,tracks[track_select].strip,page)
        elseif res == sfcnt + 15 then
          --unlock controls
          UnlockControls(tracks[track_select].strip,page)
        elseif res == sfcnt + 16 then
          --mix mode horiz
          lvar.mixmodedir = 1
          Repos5001()
          GUI_DrawCtlBitmap_Mix()
          lupd.update_gfx = true
        elseif res == sfcnt + 17 then
          --mix mode vert
          lvar.mixmodedir = 0
          Repos5001()
          GUI_DrawCtlBitmap_Mix()
          lupd.update_gfx = true
        elseif res == sfcnt + 18 then
          --mix mode alignment
          lvar.mixmodealign = 1-lvar.mixmodealign
          GUI_DrawCtlBitmap_Mix()
          lupd.update_gfx = true
        elseif res == sfcnt + 19 then
          if lvar.mm_fadepop == 1 then
            lvar.mm_fadepop = lvar.mm_fadepopamt
          else
            lvar.mm_fadepop = 1
          end
          lupd.update_gfx = true
        elseif res == sfcnt + 20 then
          local ret, val = reaper.GetUserInputs('Fade Alpha',1,'Enter fade alpha (0-100)',lvar.mm_fadepopamt*100)
          if ret and tonumber(val) then
            lvar.mm_fadepopamt = tonumber(val)/100
            lvar.mm_fadepop = lvar.mm_fadepopamt
            lupd.update_gfx = true
          end
        elseif res == sfcnt + 21 then
          lvar.mm_disablenonpoppedctls = not lvar.mm_disablenonpoppedctls
          lupd.update_gfx = true
          SetCtlBitmapRedraw()

        elseif res == sfcnt + 22 then
          lvar.showpoponly = not lvar.showpoponly
          if lvar.showpoponly then
            lvar.showpop = true
          end
          lupd.update_gfx = true
          SetCtlBitmapRedraw()

        elseif res == sfcnt + 23 then
          lvar.dm_singlepopup = not lvar.dm_singlepopup
          PopOut_DeleteAll(true)

        elseif res == sfcnt + 24 then
          lvar.popout_autoarrange = not lvar.popout_autoarrange
          lupd.update_gfx = true
          SetCtlBitmapRedraw()

        elseif res == sfcnt + 25 then
          lvar.autoarrange_activefx = not lvar.autoarrange_activefx
          lupd.update_gfx = true
          SetCtlBitmapRedraw()
          
        elseif res == sfcnt + 26 then
          lvar.mmtouch = not lvar.mmtouch

        elseif res == sfcnt + 27 then
          lvar.dm_showtrackname = not lvar.dm_showtrackname
          lupd.update_surface = true
          
        elseif res == sfcnt + 28 then
          local fn = file_bgimage --string.match(file_bgimage,'(.+[\\/]).*')
          local retval, nfn = reaper.GetUserFileNameForRead(fn or '', 'Load background image:', '*.jpg;*.png')
          if retval then
            if reaper.file_exists(nfn) then
              file_bgimage = nfn
              LoadBGImage(nfn)
              lupd.update_bg = true
              lupd.update_gfx = true
            end
          end
        elseif res == sfcnt + 29 then
          file_bgimage = nil
          LoadBGImage(file_bgimage)
          lupd.update_bg = true
          lupd.update_gfx = true

        elseif res == sfcnt + 30 then

          lvar.bgstretch = not lvar.bgstretch
          LoadBGImage(file_bgimage)
          lupd.update_bg = true
          lupd.update_gfx = true

        elseif res == sfcnt + 31 then

          local ret, val = reaper.GetUserInputs('Background Brightness',1,'Enter brightness (-100 to 100)',lvar.bgbright)
          if ret and tonumber(val) then
            lvar.bgbright = F_limit(tonumber(val),-100,100)
            LoadBGImage(file_bgimage)
            lupd.update_bg = true
            lupd.update_gfx = true
          end

        elseif res == sfcnt + 32 then

          lvar.mmov_bgimgon = not lvar.mmov_bgimgon
          lupd.update_gfx = true

        elseif res == sfcnt + 33 then

          local ret, val = reaper.GetUserInputs('Surface Toolbar Tint',1,'Enter tint amount (0-0.7)',lvar.mmov_tint)
          if ret and tonumber(val) then
            lvar.mmov_tint = F_limit(tonumber(val),0,0.7)
            lupd.update_gfx = true
          end

        elseif res == sfcnt + 34 then

          lvar.livebg = not lvar.livebg
          lupd.update_bg = true
          lupd.update_gfx = true

        elseif res == sfcnt + 35 then

          lvar.bgcentred = not lvar.bgcentred
          lupd.update_surface = true

        elseif res == sfcnt + 36 then
          local ret, vals = reaper.GetUserInputs('Centred Image Offset',2,'X,Y',(lvar.bg_coffx or 0)..','..(lvar.bg_coffy or 0))
          if ret then
            local valtab = split2(vals,',')
            if tonumber(valtab[1]) and tonumber(valtab[2]) then
              lvar.bg_coffx, lvar.bg_coffy = valtab[1], valtab[2]
            end
            lupd.update_surface = true
          end

        elseif res == sfcnt + 37 then
          CreateTrackTemplateStrips()
        elseif res == sfcnt + 38 then
          CreateTrackStrips()
        end
      end


    elseif mtype == 2 then

      mm = ''
      if show_snapshots then
        mm = '!'
      end
      local mstr = ''
      local sfcnt = #strip_favs
      if sfcnt > 0 then
        for fvs = 1, sfcnt do
          if mstr ~= '' then
            mstr = mstr .. '|'
          end
          mstr = mstr .. string.match(strip_favs[fvs],'.+/(.-).strip')
        end
      end
      local sffcnt, sflist, msf = MenuStripFolders()
      if sflist ~= '' then
        mstr = mstr .. sflist
        sfcnt = sfcnt + sffcnt
      end

      gfx.x, gfx.y = mouse.mx, mouse.my
      res = OpenMenu(mstr)
      if res ~= 0 then

        if res <= #strip_favs and #strip_favs > 0 then

          local fn = strip_favs[res]
          InsStrip(fn)

          --[[local fn = strip_favs[res]
          --PopulateStrips()
          loadstrip = LoadStripFN(fn)
          if loadstrip then
            GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
            --image_count = image_count_add

            local dx, dy = GetLeftControlInStrip2(loadstrip.strip)
            insertstrip = {x = mouse.mx, y = mouse.my, dx = dx, dy = dy}
          end
          --loadstrip = nil]]
        else
          local fn = msf[res-#strip_favs]
          InsStrip(fn)

          --[[loadstrip = LoadStripFN(fn)
          if loadstrip then
            GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
            --image_count = image_count_add

            local dx, dy = GetLeftControlInStrip2(loadstrip.strip)
            insertstrip = {x = mouse.mx, y = mouse.my, dx = dx, dy = dy}
          end]]

        end
      end
    end

  end

  function UnlockControls(strip, page, stripid)

    if strips[strip] then
      for c = 1, #strips[strip][page].controls do

        local ctl = strips[strip][page].controls[c]
        if not stripid or ctl.id == stripid then
          if ctl.ctllock == true then
            ctl.ctllock = nil
            SetCtlDirty(c)
          end
          lupd.update_ctls = true
        end
      end
    end

  end

  function InsStrip(fn, dragmode)

    if loadstrip == nil then
      loadstrip = LoadStripFN(fn)
      if loadstrip then
        loadstrip.fn = fn
      end
    end
    if loadstrip then

      if lvar.livemode == 2 and #loadstrip.fx == 0 then
        insertstrip = nil
        loadstrip = nil
        dragstrip = nil
        dragstripx = nil
        ctl_select = nil
        mouse.context = nil
        return
      end

      loadstrip.strip_w, loadstrip.strip_h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
      --local dx, dy = GetLeftControlInStrip2(loadstrip.strip)
      dx, dy = 0, 0
      insertstrip = {x = mouse.mx, y = mouse.my, dx = dx, dy = dy, dragmode = dragmode, alpha = 0.3,
                     xoff = math.floor((loadstrip.strip_w*lvar.zoom)/2),
                     yoff = math.floor((loadstrip.strip_h*lvar.zoom)/2)}

    end

    if lvar.livemode == 0 then

      if loadstrip and stripgallery_view == 1 or settings_stripautosnap == true then
        stlay_data = AutoSnap_GetStripLocs(true)
        local x,y = AutoSnap_GetEndInsertPos(loadstrip.strip_w,loadstrip.strip_h)
        dragstrip = {x = x+obj.sections[10].x-surface_offset.x, y = y+obj.sections[10].y-surface_offset.y, xx = x, yy = y}
        lupd.update_surface = true

        if settings_stripautosnap == true then
          ignore = true
        end
        if show_striplayout == true then
          --if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].h then
            Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y,ignore)
            SetASLocs()
          --end
        else
          --if dragstrip.x >= obj.sections[10].x and dragstrip.x < obj.sections[10].w and dragstrip.y >= obj.sections[10].y
            --and dragstrip.y < obj.sections[10].h then
            --if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].h then
              Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y,ignore)
            --end
          --end
        end
        stlay_data = AutoSnap_GetStripLocs(true)

        insertstrip = nil
        loadstrip = nil
        dragstrip = nil
        dragstripx = nil
        ctl_select = nil
        lupd.update_gfx = true

        SetCtlBitmapRedraw()
        reaper.MarkProjectDirty(0)

      end

    else

      if not dragmode then
        mouse.alt = gfx.mouse_cap&16==16
        if mouse.alt and not lvar.livemode == 2 then
          lvar.addstripdialog_tracknum = track_select
          local fxdata = AddStripDialog_GetFxData()
          if #fxdata > 0 then

            fxdata.dx = dx
            fxdata.dy = dy
            fxdata.insertstrip = insertstrip
            fxdata.loadstrip = loadstrip
            fxdata.mode = 2

            AddStripDialog_UpdateSel(fxdata)
            lvar.fxdata = fxdata
            lvar.show_addstripdialog = true
            lupd.update_gfx = true
            retain = true
            RedrawGUIBitmap()
            
          end
          insertstrip = nil
          dragstrip = nil
          dragstripx = nil
          ctl_select = nil

        else
          local switchid, switchid2
          local strip = tracks[track_select].strip
          if strip == -1 then
            strip = Strip_INIT()
          end
          local ctls = strips[strip][page].controls
          for i = 1, #ctls do
            if ctls[i].ctlcat == ctlcats.switcher then
              local swid = ctls[i].switcherid
              if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                switchid = swid
                break
              end
            end
          end

          local extid
          local maxpos = 0
          if switchid then
            extid = switchers[switchid].extendid
            maxpos = Switcher_Ext_GetMaxPos(extid)

            for s = 1, #switchers do
              if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                 switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                switchid2 = s
                break
              end
            end
            if switchid2 and #switchers[switchid2].grpids > 0 then
              maxpos = maxpos + 1
            end
          end

          local c = Switchers_Ext_Insert(switchid, maxpos)
          if lvar.livemode == 2 then
            local trn = lvar.dynamicmode_trn
            local track = GetTrack(trn)
            if track then
              local fx = reaper.TrackFX_GetCount(track) --math.max(maxpos-1,0)
              local swid = ctls[c].switcherid
              local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, nil, true) --, nil, true)
              local extid = switchers[swid].extendid
              Strip_ReposSwitcher_Ext(extid, 1)

              UpdateControlValues3(nil, ctls_upd, ctls_orr)
              DM_RefreshFX()
            end
          else
            local swok = Switcher_AddStrip(nil, c, loadstrip)
            if swok ~= true then
              Switcher_DeleteExt(ctls[c].switcherid)
            end
          end

          if lvar.livemode == 2 then
            DM_StoreStripData()
          end

          insertstrip = nil
          loadstrip = nil
          dragstrip = nil
          dragstripx = nil
          ctl_select = nil
          lupd.update_gfx = true

          SetCtlBitmapRedraw()
          reaper.MarkProjectDirty(0)
          
          return maxpos
        end
      end

    end
  end

  function TopMenu()

    local mstr
    local ds
    local ls = ''
    local d = gfx.dock(-1)
    if d%256 == 0 then
      ds = 'Dock Window'
    else
      ds = 'Undock Window'
    end
    if settings_locksurface then
      ls = '!'
    end
    local dt = ''

    if (strips and tracks[track_select].strip and strips[tracks[track_select].strip] and #strips[tracks[track_select].strip][page].controls > 0) or strip_default == nil then
      dt = '#'
    end
    local sub = '||>Strip Set'
    local cs = tonumber(string.match(lvar.STRIPSET,'%d'))
    for i = 1, 8 do
      if i < 8 then
        if cs and cs == i then
          sub = sub .. '|!Set '..string.format('%i',i)
        else
          sub = sub .. '|Set '..string.format('%i',i)
        end
      else
        if cs and cs == i then
          sub = sub .. '|<!Set '..string.format('%i',i)
        else
          sub = sub .. '|<Set '..string.format('%i',i)
        end
      end
    end
    local gv
    if mode == 0 and stripgallery_view == 0 then
      gv = '!Page View|#Gallery View'
    elseif mode == 0 then
      gv = 'Page View|#Gallery View'
    else
      gv = '#Page View|#Gallery View'
    end
    sub = sub .. '||Load Set|Merge Set|Save Set||Clear Set||>Script Data|Load Data File|Load Backup Data File||<Save Data File|Statistics||Quit without saving'
    if mode == 0 then
      mstr = 'Toggle Topbar|Toggle Sidebar||'..gv..'||Lock X|Lock Y|Scroll Up|Scroll Down||Save Project|Open Settings||>Pages|Page 1|Page 2|Page 3|<Page 4||'..ds..'||'..ls..'Lock Surface||'..dt..'Insert Default Strip'
    else
      mstr = 'Toggle Topbar|#Toggle Sidebar||'..gv..'||Lock X|Lock Y|Scroll Up|Scroll Down||Save Script Data|Open Settings||>Pages|Page 1|Page 2|Page 3|<Page 4||'..ds..'||'..ls..'Lock Surface||'..dt..'Insert Default Strip'
    end
    mstr = mstr .. sub
    gfx.x, gfx.y = mouse.mx, butt_h
    res = OpenMenu(mstr)
    if res ~= 0 then
      if res == 1 then
        ToggleTopbar()
      elseif res == 2 then
        ToggleSidebar()
      elseif res == 3 then
        stripgallery_view = 0
        lupd.update_surface = true
      elseif res == 4 then
        stripgallery_view = 0
        if settings_usectlbitmap then
          local xpos = 0
          stlay_data = AutoSnap_GetStripLocs(true)
          GUI_DrawCtlBitmap2()
        else
          stripgallery_view = 0
          OpenMsgBox(1, 'You must enable \'use bitmap mask control detection\' setting to use this viewing mode.', 1)
        end
        lupd.update_surface = true
      elseif res == 5 then
        LockX()
      elseif res == 6 then
        LockY()
      elseif res == 7 then
        ScrollUp()
      elseif res == 8 then
        ScrollDown()
      elseif res == 9 then
        SaveProj(true, true)
        --lastprojdirty = 0
        --infomsg = "*** DATA SAVED ***"
        OpenMsgBox(1,'Data Saved.',1)
        lupd.update_gfx = true
      elseif res == 10 then
        show_settings = not show_settings
        lupd.update_surface = true
        RedrawGUIBitmap()
        
      elseif res >= 11 and res <= 14 and navigate then
        SetPage(res-10)
      elseif res == 15 then
        --[[if d%256 == 0 then
          d=d+1
        else
          d=d-1
        end
        gfx.dock(d)]]
        if d%256 == 0 then
          if dockstate and dockstate%256 ~= 0 then
            gfx.dock(dockstate)
          else
            gfx.dock(d+1)
          end
        else
          dockstate = d
          gfx.dock(256)
        end

      elseif res == 16 then
        settings_locksurface = not settings_locksurface
      elseif res == 17 then
        stripfol_select = strip_default.stripfol_select
        strip_select = strip_default.strip_select
        PopulateStrips()
        loadstrip = LoadStrip(strip_select)
        if loadstrip then
          GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
          Strip_AddStrip(loadstrip,0,0,true)
          --image_count = image_count_add
          loadstrip = nil
          --SaveSingleStrip(strip)
          reaper.MarkProjectDirty(0)
        end
      elseif res >= 18 and res <= 25 then
        --SaveProj()
        local oscript = lvar.SCRIPT
        if res == 18 then
          lvar.SCRIPT = 'LBX_STRIPPER'
          lvar.STRIPSET = 'STRIP SET 1'
        else
          lvar.SCRIPT = 'LBX_STRIPPER_'..res-17
          lvar.STRIPSET = 'STRIP SET '..string.match(tostring(res-17),'(.-)%.')
        end
        if oscript ~= lvar.SCRIPT then
          DBGOut('')
          DBGOut('*** LOADING NEW PROJECT ***')

          newloc = true
        end
      elseif res == 26 then
        --load set
        loadset_fn = LoadSet(false)
      elseif res == 27 then
        --merge set
        loadset_fn = LoadSet(true)
      elseif res == 28 then
        --save set
        OpenEB(20,'Please enter name of strip set:')
      elseif res == 29 then
      elseif res == 30 then
        local fn = datafile
        if fn == nil then fn = '' end
        local ret, rfn = reaper.GetUserFileNameForRead(fn or '', 'Load LBXStripper data file:', nz(string.match(fn, '.+%.(lbxstripper.*)') or '',''))
        if ret == true then
          LoadDataFile(rfn)
        end
      elseif res == 31 then
        local fn = datafile
        local ret, rfn = reaper.GetUserFileNameForRead(string.match(fn or '','(.+).lbxstripper.*') or '', 'Load LBXStripper data file:', 'lbxbak')
        if ret == true then
          LoadDataFile(rfn)
        end
      elseif res == 32 then
        local retval, fileName = reaper.JS_Dialog_BrowseForSaveFile('Save Data File As...', paths.projsave_path, '', "LBXStripper data files (.lbxstripper)\0*.lbxstripper\0\0")
        if retval == 1 then
          local status = PCALL_SaveData(false, true, false, fileName)
        end
      elseif res == 33 then
        ShowStats()
      elseif res == 34 then
        fquit()
      end
      lupd.update_gfx = true
    end

  end

  function ShowStats()

    --GUI_DrawStateWin(obj,gui,'Strip Statistics',true)
    --GUI_DrawStateWin(obj,gui,'')
    DBG('Strip Statistics')
    DBG('')
    local totc = 0
    local totsub = 0
    local totsnap = 0
    for s = 1, #strips do
      local stripc = 0
      local subsetsc = 0
      local snapsc = 0
      for p = 1, lvar.maxpage do

        if strips[s][p] then
          stripc = stripc + #strips[s][p].controls
        end
        if snapshots and snapshots[s] and snapshots[s][p] then
          subsetsc = subsetsc + #snapshots[s][p]
          if snapshots[s][p][1] then
            snapsc = snapsc + #snapshots[s][p][1]
          end
          if #snapshots[s][p] > 1 then
            for i = 2, #snapshots[s][p] do

              if snapshots[s][p][i] and snapshots[s][p][i].snapshot then
                snapsc = snapsc + #snapshots[s][p][i].snapshot
              end

            end
          end
        end

      end
      if stripc > 0 then
        local tr = ''
        if strips[s].track.tracknum == -1 then
          tr = '(Master)'
        else
          tr = '(Track '..strips[s].track.tracknum+1 ..')'
        end
        local str = 'Strip '..s..' '.. tr ..' ................ #Controls = '..stripc..'  #Snapshot sets = '..subsetsc..'  #Snapshots = '..snapsc
        totc=totc+stripc
        totsub=totsub+subsetsc
        totsnap=totsnap+snapsc

        --GUI_DrawStateWin(obj,gui,str)
        DBG(str)
      end
    end
    --GUI_DrawStateWin(obj,gui,'')
    --GUI_DrawStateWin(obj,gui,'Total Controls = '..totc)
    --GUI_DrawStateWin(obj,gui,'Total Subsets = '..totsub)
    --GUI_DrawStateWin(obj,gui,'Total Snapshots = '..totsnap)
    DBG('')
    DBG('Total Controls = '..totc)
    DBG('Total Snapshot sets = '..totsub)
    DBG('Total Snapshots = '..totsnap)
    --reaper.MB('Close statistics', 'Stats', 0)
  end

  function ToggleTopbar()

    hide_topbar = not hide_topbar
    obj = GetObjects()
    lupd.update_surface = true
    lupd.update_topbar = true
    lupd.update_sidebar = true
    lupd.update_trbtns = true
    force_resize = true

  end

  function ToggleSidebar()

    --if mode == 0 or hide_topbar == true and settings_showminimaltopbar == false then
      show_editbar = not show_editbar
      if show_editbar then
        plist_w = oplist_w
      else
        plist_w = 0
      end
      force_resize = true
    --end

  end

  function LockX()
    lockx = not lockx
    if lockx then
      surface_offset.x = 0
    end
    obj = GetObjects()
  end

  function LockY()
    locky = not locky
    if locky then
      surface_offset.y = 0
    end
    obj = GetObjects()
  end

  function ScrollUp()
    --if settings_locksurface == false then
      if surface_offset.y > 0 then
        if lockh > 0 then
          surface_offset.y = surface_offset.y - lockh
        else
          surface_offset.y = surface_offset.y - math.floor(obj.sections[10].h/settings_gridsize)*settings_gridsize
        end
      end
    --end
  end

  function ScrollDown()
    --if settings_locksurface == false then
      if surface_offset.y < surface_size.h-obj.sections[10].h then
        if lockh > 0 then
          surface_offset.y = surface_offset.y + lockh
        else
          surface_offset.y = surface_offset.y + math.floor(obj.sections[10].h/settings_gridsize)*settings_gridsize
        end
      --end
    end
  end

  function CheckGlobalTrack()

    local track = reaper.GetTrack(0, LBX_GTRACK)
    local _, trn = reaper.GetTrackName(track,'')
    if trn ~= LBX_GTRACK_NAME then
      PopulateTracks()
      lupd.update_gfx = true
    end

  end

  function CheckGlobalTrackSel(skipcheck)

    if LBX_GTRACK then
      if not skipcheck then
        CheckGlobalTrack()
      end
      if gpage == true then
        if track_select ~= LBX_GTRACK then
          SetGlobalPage(true)
        end
      else
        if track_select == LBX_GTRACK then
          SetGlobalPage(true)
        end
      end
    else
      if track_select == LBX_GTRACK then
        SetPage(0)
      end
    end

  end

  function SetGlobalPage(force)
    if lvar.dm_editmode_data then return end
    local ots, opg, omixx, omixy = track_select, page, surface_offset.mixx, surface_offset.mixy
 
    if gpage == true and not force then SetPage(nz(gpage_opage,1)) return end
    if LBX_GTRACK == nil then
      PopulateTracks()
    else
      CheckGlobalTrack()
    end
    if LBX_GTRACK then

      local strip = tracks[track_select].strip
      if strips[strip] then
        strips[strip][page].mixy = surface_offset.mixy
        strips[strip][page].mixx = surface_offset.mixx
        
        if lvar.livemode == 2 then
          DM_StoreStripData()
        end
      end

      if show_fsnapshots then
        show_fsnapshots = false
        show_xysnapshots = false
        lupd.update_surface = true
        RedrawGUIBitmap()
      end

      gpage = true
      if track_select ~= LBX_GTRACK then
        gpage_otrackselect = track_select
        gpage_opage = page
      end

      track_select = LBX_GTRACK
      local strip = tracks[track_select].strip

      page = 1

      local strip = tracks[track_select].strip
      if strips[strip] and strips[strip][page].mixy then
        surface_offset.mixy = strips[strip][page].mixy
        surface_offset.mixx = strips[strip][page].mixx
      else
        surface_offset.mixy = 0
        surface_offset.mixx = 0
      end
      lvar.mixupdate = nil

      --[[if strips[strip] and strips[strip][page].lmode then
        lvar.livemode = strips[strip][page].lmode
      else
        lvar.livemode = lvar.glivemode
      end]]

    if strips[strip] and strips[strip][page].lmode then
      if lvar.livemode ~= strips[strip][page].lmode then
        SetLiveMode(strips[strip][page].lmode, ots, opg, omixx, omixy)
        --lvar.livemode = strips[strip][page].lmode
        --if obj then
        --  SetSurfaceSize2(obj)
        --end
      end
    else
      if lvar.livemode ~= lvar.glivemode then
        SetLiveMode(lvar.glivemode, ots, opg, omixx, omixy)
        --lvar.livemode = lvar.glivemode
        --if obj then
        --  SetSurfaceSize2(obj)
        --end
      end
    end

   if lvar.livemode ~= 2 then
      if lvar.analyzer.active then
        DM_ShowAnalyzer(false)
        lupd.update_trbtns = true
        lvar.saveanalactive = true
      end
    end
    
      ctl_select = nil
      gfx2_select = nil
      gfx3_select = nil
      gfx4_select = nil
      gfx4_selectidx = nil
      lvar.ctlpreview_sel = nil
      lvar.gfxpreview_sel = nil

      ss_select = nil
      sstype_select = 1
      CloseActChooser()
      showctlbrowser(false)
      show_samplemanager = false

      SetASLocs()
      SetGalleryView()

      if strips and tracks[track_select] and strips[strip] then
        strips[tracks[track_select].strip].page = 1
        surface_offset.x = tonumber(strips[tracks[track_select].strip][page].surface_x)
        surface_offset.y = tonumber(strips[tracks[track_select].strip][page].surface_y)
      else
        surface_offset.x = 0
        surface_offset.y = 0
      end

      InsertDefaultStrip()

      GUI_DrawCtlBitmap()

      if settings_trackchangemidi == true then
        TrackChangeMidi()
      end

      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      lupd.update_gfx = true
    else

    end

  end

  function SetGalleryView()
    stripgallery_view = 0
    if stripgallery_view ~= 0 then

      stlay_data = AutoSnap_GetStripLocs(true)
      if show_striplayout == false or (stlay_data and #stlay_data.reordered > 0) then
        GUI_DrawCtlBitmap2()
      else
        show_striplayout = false
      end

    end

  end

  function SetASLocs()

    stlay_data = nil
    striplayout_selstripid = nil
    if show_striplayout == true then

      stlay_data = AutoSnap_GetStripLocs(true)
      striplayout_data = StripLayout_GetData()
      StripLayout_DrawImage(striplayout_data)

    end

  end

  function SetReturnPage(track_select, npage)

    local strip = tracks[track_select].strip
    local trs = track_select
    if npage == 0 and tracks[LBX_GTRACK] then
      strip = tracks[LBX_GTRACK].strip
      trs = LBX_GTRACK
      npage = 1
    elseif track_select == LBX_GTRACK and gpage_otrackselect then
      strip = tracks[gpage_otrackselect].strip
      trs = gpage_otrackselect
      npage = gpage_opage
    end
    if npage < 1 then return end

    if (strips[strip] and strips[strip][npage].lmode == 2) then
    else
      lvar.dm_ret_track = trs
      lvar.dm_ret_page = npage
    end

  end

  function SetPage(lpage)

    if lvar.dm_editmode_data then return end
    if mouse.context ~= nil and mouse.context ~= contexts.hold then return end
    
    UnhideCtls()
    
    local ots, opg, omixx, omixy = track_select, page, surface_offset.mixx, surface_offset.mixy
    
    if show_randomopts or show_samplemanager then
      show_randomopts = false
      show_samplemanager = false
      RedrawGUIBitmap()
    end

    local strip = tracks[track_select].strip
    SetReturnPage(track_select, lpage)

    --if track_select == LBX_GTRACK then page = 1 return end
    if lpage == 0 then
      if gpage == false and track_select ~= LBX_GTRACK then
        SetGlobalPage()
      end
      return
    end

    if show_fsnapshots then
      show_fsnapshots = false
      show_xysnapshots = false
      lupd.update_surface = true
      RedrawGUIBitmap()
    end

    if strips[strip] then
      strips[strip][page].mixy = surface_offset.mixy
      strips[strip][page].mixx = surface_offset.mixx
      if lvar.livemode == 2 then
        DM_StoreStripData()
      end
    end

    gpage = false

    if track_select == LBX_GTRACK and gpage_otrackselect then
      track_select = gpage_otrackselect
      --Set track selected
      if settings_followselectedtrack then
        --Select track
        local tr = GetTrack(track_select)
        if tr then
          if tr ~= nil then
            reaper.SetOnlyTrackSelected(tr)
            reaper.SetTrackSelected(tr, true)
          end
        end
      end
      --gpage_otrackselect = nil
    end
    page = lpage

    local strip = tracks[track_select].strip
    if strips[strip] and strips[strip][page].mixy then
      surface_offset.mixy = strips[strip][page].mixy
      surface_offset.mixx = strips[strip][page].mixx
    else
      surface_offset.mixy = 0
      surface_offset.mixx = 0
    end
    lvar.mixupdate = nil

    if lvar.dm_fixtrack and track_select == lvar.dm_fixtrack and page == 1 then
      SetLiveMode(2, ots, opg, omixx, omixy)
      --lvar.livemode = 2
      --if obj then
      --  SetSurfaceSize2(obj)
      --end
    else
      if strips[strip] and strips[strip][page].lmode then
        if lvar.livemode ~= strips[strip][page].lmode then
          SetLiveMode(strips[strip][page].lmode, ots, opg, omixx, omixy)
          --lvar.livemode = strips[strip][page].lmode
          --if obj then
          --  SetSurfaceSize2(obj)
          --end
        end
      else
        if lvar.livemode ~= lvar.glivemode then
          SetLiveMode(lvar.glivemode, ots, opg, omixx, omixy)
          --lvar.livemode = lvar.glivemode
          --if obj then
          --  SetSurfaceSize2(obj)
          --end
        end
      end
    end
    
    if lvar.livemode ~= 2 then
      if lvar.analyzer.active then
        DM_ShowAnalyzer(false)
        lupd.update_trbtns = true
        lvar.saveanalactive = true
      end
    else
      settings_followselectedtrack = false
    end

    ctl_select = nil
    gfx2_select = nil
    gfx3_select = nil
    gfx4_select = nil
    gfx4_selectidx = nil
    lvar.ctlpreview_sel = nil
    lvar.gfxpreview_sel = nil
    lvar.selctl = nil

    ss_select = nil
    sstype_select = 1
    CloseActChooser()
    showctlbrowser(false)

    if lvar.livemode == 2 then
      DM_AddStrips()
    end

    GUI_DrawCtlBitmap()

    SetASLocs()
    striplayout_selstripid = nil
    SetGalleryView()

    if strips and tracks[track_select] and strips[tracks[track_select].strip] then
      strips[tracks[track_select].strip].page = page
      surface_offset.x = tonumber(strips[tracks[track_select].strip][page].surface_x)
      surface_offset.y = tonumber(strips[tracks[track_select].strip][page].surface_y)
    else
      surface_offset.x = 0
      surface_offset.y = 0
    end

    InsertDefaultStrip()

    if settings_trackchangemidi == true then
      TrackChangeMidi()
    end

    ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
    lvar.readpeaks = PopReadPeaks()

    --if settings_autocentrectls then
    --  AutoCentreCtls()
    --end
    --UpdateControlValues3(nil, ctls_upd, ctls_orr)
    lupd.update_gfx = true

    SK2Data_ReadAssign()
    
    SetSurfaceFade()
    
    --[[local ctls = strips[tracks[track_select].strip][page].controls
    for c = 1, #ctls do
      if ctls[c].ctlcat == ctlcats.sk2ctl then
        local i = tonumber(ctls[c].param_info.paramidx)
        lvar.sk2data_assign[i].sscolor = ''
      end
    end]]
    
  end

  function TrackChangeMidi()

    if tracks[track_select] then
      local strip = tracks[track_select].strip
      if strips[strip] then
        local ctls = strips[strip][page].controls
        for c = 1, #ctls do
          local ctl = ctls[c]
          if ctl.ctlcat ~= ctlcats.midictl and ctl.midiout then
            SendMIDIMsg(ctl.midiout, ctl.val)
          end
        end
      end
    end

  end

  function SetCtlSelectVals()
    if ctl_select and #ctl_select > 0 then
      local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
      ctltype_select = ctl.ctltype
      knob_select = ctl.knob_select
      scale_select = ctl.scale
      textcol_select = ctl.textcol
      textcolv_select = ctl.textcolv
      show_paramname = ctl.show_paramname
      show_paramval = ctl.show_paramval
      textoff_select = ctl.textoff
      textoffval_select = ctl.textoffval
      textoff_selectx = ctl.textoffx
      textoffval_selectx = ctl.textoffvalx
      textsize_select = ctl.textsize
      textsizev_select = ctl.textsizev
      defval_select = ctl.defval
      enabledefval_select = ctl.enabledefval
      maxdp_select = nz(ctl.maxdp,-1)
      dvaloff_select = nz(ctl.dvaloffset,'')
      --knob_scalemode_select = nz(ctl.scalemode,1)
      scalemode_select = nz(ctl.scalemode,8)
      framemode_select = nz(ctl.framemode,1)
      horiz_select = nz(ctl.horiz,false)
      noss_select = ctl.noss
      knobsens_select = nz(ctl.knobsens,settings_defknobsens)

      if ctl.cycledata and ctl.cycledata.statecnt > 0 then
        mapptof_select = ctl.cycledata.mapptof
        draggable_select = ctl.cycledata.draggable
        spread_select = ctl.cycledata.spread
      end
      local gt = Gauge_CopySelect(ctl.gauge)
      if gt then
        gauge_select = gt
      end
      ctlfont_select = ctl.font
      bypass_bgdraw_c_select = ctl.bypassbg_c
      bypass_bgdraw_n_select = ctl.bypassbg_n
      bypass_bgdraw_v_select = ctl.bypassbg_v
      clickthrough_select = ctl.clickthrough
      dnu_select = ctl.dnu
      orr_select = ctl.orr

      targetseltrack_select = false
      if ctl.tracknum == -3 then
        targetseltrack_select = true
      end
      limittext_select = ctl.limittext or 0
      wwtext_select = ctl.wwtext or 0
      flags_select = ctl.textflags
      animatetime_select = ctl.animatetime
      animateshape_select = ctl.animateshape or 1
      SetKnobScaleMode()
      cycle_select = Cycle_CopySelectIn(ctl_select[1].ctl)
      local min, max = GetParamMinMax_ctl(ctl_select[1].ctl)
      minov_select = min
      maxov_select = max

      adjust_active_select = ctl.adjust_active or 0
      if ctl.adjust then

        adjust_bright_select = ctl.adjust.bright or 255
        adjust_contrast_select = ctl.adjust.contrast or 255
        adjust_r_select = ctl.adjust.r or 255
        adjust_g_select = ctl.adjust.g or 255
        adjust_b_select = ctl.adjust.b or 255
      else
        adjust_bright_select = 255
        adjust_contrast_select = 255
        adjust_r_select = 255
        adjust_g_select = 255
        adjust_b_select = 255
        --ctl.adjust = {bright = adjust_bright_select, contrast = adjust_contrast_select, r = adjust_r_select, g = adjust_g_select, b = adjust_b_select}
      end

    end
  end

  function SetKnobScaleMode()

    if scalemode_select == 8 and framemode_select == 1 then
      knob_scalemode_select = 2
    elseif scalemode_select == 12 and framemode_select == 2 then
      knob_scalemode_select = 3
    else
      knob_scalemode_select = 1
    end

  end

  function SetGfxSelectVals()
    gfx_font_select.name = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.name
    gfx_font_select.size = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.size
    gfx_font_select.bold = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.bold
    gfx_font_select.italic = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.italic
    gfx_font_select.underline = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.underline
    gfx_font_select.vertical = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.vertical
    gfx_font_select.shadow = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.shadow
    gfx_font_select.shadow_x = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.shadow_x
    gfx_font_select.shadow_y = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.shadow_y
    gfx_font_select.shadow_a = strips[tracks[track_select].strip][page].graphics[gfx2_select].font.shadow_a
    gfx_textcol_select = strips[tracks[track_select].strip][page].graphics[gfx2_select].text_col
    gfx_text_select = strips[tracks[track_select].strip][page].graphics[gfx2_select].text
    poslock_select = strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock
  end

  function SetGfx4SelectVals()
    if gfx4_select and #gfx4_select > 0 then
      local i = gfx4_select[1]
      local gfxx = strips[tracks[track_select].strip][page].graphics[i]
      gfx_font_select.name = gfxx.font.name
      gfx_font_select.size = gfxx.font.size
      gfx_font_select.bold = gfxx.font.bold
      gfx_font_select.italic = gfxx.font.italic
      gfx_font_select.underline = gfxx.font.underline
      gfx_font_select.vertical = gfxx.font.vertical
      gfx_font_select.shadow = gfxx.font.shadow
      gfx_font_select.shadow_x = gfxx.font.shadow_x
      gfx_font_select.shadow_y = gfxx.font.shadow_y
      gfx_font_select.shadow_a = gfxx.font.shadow_a
      gfx_textcol_select = gfxx.text_col
      gfx_text_select = gfxx.text
    end
  end

  function SetGfxSelectVals2()
    gfxbright_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].bright,0.5)
    gfxcontr_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].contr,0.5)
    gfxr_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].rmult,0.5)
    gfxg_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].gmult,0.5)
    gfxb_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].bmult,0.5)
    gfxa_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].alpha,1)
    gfxstretchmode_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchmode,1)
    gfxedgesz_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].edgesz,8)
    gfx_shadow_select = nz(strips[tracks[track_select].strip][page].graphics[gfx2_select].shadow,false)
  end

  function SetGfx4SelectVals2()
    if gfx4_select and #gfx4_select > 0 then
      local i = gfx4_select[1]
      local gfxx = strips[tracks[track_select].strip][page].graphics[i]
      gfxbright_select = nz(gfxx.bright,0.5)
      gfxcontr_select = nz(gfxx.contr,0.5)
      gfxr_select = nz(gfxx.rmult,0.5)
      gfxg_select = nz(gfxx.gmult,0.5)
      gfxb_select = nz(gfxx.bmult,0.5)
      gfxa_select = nz(gfxx.alpha,1)
      gfxstretchmode_select = nz(gfxx.stretchmode,1)
      gfxedgesz_select = nz(gfxx.edgesz,8)
      gfx_shadow_select = nz(gfxx.shadow,false)
    end
  end

  function GetValFromDVal(c, dv, checkov)
    if checkov == nil then checkov = true end

    if c then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[c]
      local t = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        t = ctl.tracknum
      end
      local cc = ctl.ctlcat
      if cc == ctlcats.fxparam or cc == ctlcats.trackparam or cc == ctlcats.tracksend then

        local sldiv = 400

        local f = ctl.fxnum
        local p = ctl.param
        track = GetTrack(t)

        local min, max = GetParamMinMax_ctl(c, checkov)
        local v = GetParamValue_Ctl(c)

        local dvoff = ctl.dvaloffset
        trackfxparam_select = c
        SetParam3(strip,page,c,ctl,min)
        os.sleep((auto_delay/sldiv)*10)
        --for i = 1, 100 do i=i end
        miv = tonumber(GetParamDisp(cc,t,f,p,dvoff,c))
        --for i = 1, 10 do i=i end

        SetParam3(strip,page,c,ctl,max)
        os.sleep((auto_delay/sldiv)*10)
        --for i = 1, 100 do i=i end
        mav = tonumber(GetParamDisp(cc,t,f,p,dvoff,c))
        if (miv == nil or mav == nil) or (miv and mav and mav > miv) then

          local pinc = 0
          local found = false
          local mdp = 50
          local nval, dval, dval2, rval = 0, '', '', 0
          for j = 0, mdp do
            for i = 0, 9 do
              local inc = (1/(10^j))*i
              nval = rval + inc
              SetParam3(strip,page,c,ctl,nval)
              os.sleep((auto_delay/sldiv)*10)
              dval2 = GetParamDisp(cc,t,f,p,dvoff,c)
              dval = GetNumericPart(dval2)
              if tonumber(dval) then
                if tonumber(dval) == tonumber(dv) then
                  found = true
                  rval = nval
                  break
                elseif tonumber(dval) < tonumber(dv) then
                  if i ==9 then
                    rval = rval + inc
                  else
                    pinc = inc
                  end
                elseif tonumber(dval) > tonumber(dv) then
                  rval = rval + pinc
                  break
                end
              else
                pinc = inc
                rval = rval + inc
              end
            end

            if found then
              break
            end
          end
          A_SetParam(strip,page,c,ctl)
          return rval, dval2
        else
          OpenMsgBox(1, 'Currently unavailable for this parameter.', 1)
  --[[
                  local pinc = 0
                  local found = false
                  local mdp = 50
                  local nval, dval, dval2, rval = 0, '', '', 0
                  for j = 0, mdp do
                    pinc = 0
                    for i = 0, 9 do
                      local inc = (1/(10^j))*i
                      nval = rval + inc
                      SetParam3(nval)
                      for x = 1,20 do x=x end
                      dval2 = GetParamDisp(t,f,p,dvoff)
                      dval = GetNumericPart(dval2)
                      if tonumber(dval) then
                        if tonumber(dval) == tonumber(dv) then
                          found = true
                          rval = nval
                          break
                        elseif tonumber(dval) > tonumber(dv) then
                          if i == 9 then
                            rval = rval + inc
                          else
                            pinc = inc
                          end
                        elseif tonumber(dval) < tonumber(dv) then
                          rval = rval + pinc - inc
                          break
                        end
                      else
                        pinc = inc
                        rval = rval + inc
                      end
                    end

                    if found then
                      break
                    end
                  end
                  SetParam()
                  return rval
       ]]
          return 0
        end
      end
    end

  end

  function SetPosLockCtl()

    if ctl_select and #ctl_select > 0 then
      poslockctl_select = true
      for i = 1, #ctl_select do
        if nz(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].poslock,false) == false then
          poslockctl_select = false
          break
        end
      end
    else
      poslockctl_select = false
    end

  end

  --courtesy mpl from http://forum.cockos.com/showthread.php?t=169760
  function Get_ID_By_Name(name)
    kb_table = {}
    filename = reaper.GetResourcePath()..'/'..'reaper-kb.ini'
    file = io.open(filename, "r")
    content = file:read("*all")
    for line in io.lines(filename) do table.insert(kb_table, line) end
    file:close()

    for i = 1, #kb_table do
      if string.find(kb_table[i], name) ~= nil then
        temp_t = {}
        for word in string.gmatch(kb_table[i], '.-[%s]') do table.insert(temp_t, word) end
        local actnm = string.match(kb_table[i], '"(.-)"')
        return '_'..string.sub(temp_t[4],0,-2), actnm
      end
    end
  end


  function ActionListFilter(txt)

    txt = string.upper(txt)..' '
    tbl = {}

    local temp_t = {}
    for word in string.gmatch(txt, '(.-)[%s]') do table.insert(temp_t, word) end
    for i = 1, #action_tbl do

      local cd = string.upper(action_tbl[i].command_desc or 'unknown')

      local match = true
      for w = 1, #temp_t do
        local m = string.match(cd,temp_t[w])
        if m == nil then
          match = false
          break
        end
      end

      if match then
        table.insert(tbl, action_tbl[i])
      end
    end

    return tbl
  end

  function LoadActionIDs()

    local actcnt = 0

    local action_tbl = {}
    local kb_table

    --enumerate dump folderr
    local j = 0
    local i = 0

    local sd = reaper.EnumerateSubdirectories(paths.resource_path, j)
    while sd ~= nil do

      if sd == 'actiondumps' then
        local df = reaper.EnumerateFiles(paths.actiondump_path,i)
        while df ~= nil do

          kb_table = {}
          filename = paths.actiondump_path..'/'..df
          file = io.open(filename, "r")
          content = file:read("*all")
          for line in io.lines(filename) do table.insert(kb_table, line) end
          file:close()

          for i = 3, #kb_table do
            local actid, actnm = string.match(kb_table[i],'.-(%d+).-(%w.*)')
            if actid and actnm then
              actcnt = actcnt + 1
              action_tbl[actcnt] = {dcommand_id = actid, command_desc = actnm}
            end
          end
          i=i+1
          df = reaper.EnumerateFiles(paths.actiondump_path,i)
        end
        break
      end
      j=j+1
      sd = reaper.EnumerateSubdirectories(paths.resource_path, j)
    end

    kb_table = {}
    filename = reaper.GetResourcePath()..'/'..'reaper-kb.ini'
    if reaper.file_exists(filename) then
      file = io.open(filename, "r")
      content = file:read("*all")
      for line in io.lines(filename) do table.insert(kb_table, line) end
      file:close()

      for i = 1, #kb_table do
        temp_t = {}
        for word in string.gmatch(kb_table[i], '.-[%s]') do table.insert(temp_t, word) end
        if temp_t[1] == 'SCR ' then
          actcnt = actcnt + 1
          local actnm = string.match(kb_table[i], '"(.-)"')
          local actid = '_'..string.sub(temp_t[4],0,-2)
          action_tbl[actcnt] = {command_id = actid, command_desc = actnm}
        end
      end

      kb_table = {}
      filename = reaper.GetResourcePath()..'/'..'S&M_Cyclactions.ini'
      if reaper.file_exists(filename) then
        file = io.open(filename, "r")
        content = file:read("*all")
        for line in io.lines(filename) do table.insert(kb_table, line) end
        file:close()

        local cycacttype, cyctype
        for i = 1, #kb_table do
          local l = string.match(kb_table[i], '%[(.*)%]')
          if l then
            cycacttype = l
            if cycacttype == 'Main_Cyclactions' then
              cyctype = '_S&M_CYCLACTION_'
            elseif cycacttype == 'MainAlt_Cyclactions' then
              cyctype = '_S&M_MAIN_ALT_CYCLACTION'
            elseif cycacttype == 'MediaEx_Cyclactions' then
              cyctype = '_S&M_MEDIAEX_CYCLACTION'
            elseif cycacttype == 'ME_Piano_Cyclactions' then
              cyctype = '_S&M_ME_PIANO_CYCLACTION'
            elseif cycacttype == 'ME_List_Cyclactions' then
              cyctype = '_S&M_ME_LIST_CYCLACTION'
            elseif cycacttype == 'ME_Inline_Cyclactions' then
              cyctype = '_S&M_ME_INLINE_CYCLACTION'
            else
              cyctype = nil
            end
          else
            if cyctype then
              local l = string.match(kb_table[i], 'Action(%d)=')
              if l then
                actcnt = actcnt + 1
                local actid = cyctype..l
                local actnm = string.match(kb_table[i], '"(.-)|')
                action_tbl[actcnt] = {command_id = actid, command_desc = actnm}
              end
            end
          end

        end
      end
    end

    kb_table = {}
    filename = reaper.GetResourcePath()..'/'..'S&M.ini'
    if reaper.file_exists(filename) then
      file = io.open(filename, "r")
      content = file:read("*all")
      for line in io.lines(filename) do table.insert(kb_table, line) end
      file:close()
      local readacts = false
      for i = 1, #kb_table do
        local l = string.match(kb_table[i], '%[(.*)%]')
        if l and readacts == false then
          if l == 'NbOfActions' then
            readacts = true
          else
            readacts = false
          end
        elseif readacts then
          local l = string.match(kb_table[i], 'S&M_.-=(%d+) ')
          if l then
            local aid = string.match(kb_table[i], '(S&M_.-)=')
            local an = string.match(kb_table[i], '; (.*)')
            local s, e = string.find(an,'.%-%-')
            if s then
              an = string.sub(an,1,s-1)
            end
            for j = 1, l do

              actcnt = actcnt + 1
              local actid = aid..j
              local an = string.gsub(an,'([^a-z])n([^a-z])','%1'..j..'%2')
              an = string.gsub(an,'( [^a-z])(n)$','%1'..j)
              an = string.gsub(an,'( )(n)$','%1'..j)
              local actnm = an
              action_tbl[actcnt] = {command_id = actid, command_desc = actnm}
            end
          end
        end
      end
    end

    return action_tbl

  end

  function AssActionByName(txt)

  end

  function AssAction_GetNameFromID(comid)

    if string.sub(comid,1,1) == '_' then
      comid = string.sub(comid,2)
    end
    local ret = 'Action: '..comid
    local acttbl = LoadActionIDs()
    for i = 1, #acttbl do

      if acttbl[i].command_id then
        if string.sub(acttbl[i].command_id,1,1) == '_' then
          acttbl[i].command_id = string.sub(acttbl[i].command_id,2)
        end
        if acttbl[i].command_id == comid then
          ret = acttbl[i].command_desc

          break
        end
      elseif acttbl[i].dcommand_id then
        if string.sub(acttbl[i].dcommand_id,1,1) == '_' then
          acttbl[i].dcommand_id = string.sub(acttbl[i].dcommand_id,2)
        end
        if acttbl[i].dcommand_id == comid then
          ret = acttbl[i].command_desc

          break
        end
      end
    end
    return ret

  end

  function testact()
    local id = '_RS7ace89f6324562fdd2373e61c8ad3897e212814c'
    local ret, ret2 = AssAction_GetNameFromID2(id)
    DBG(ret..'  '..tostring(ret2))
  end

  function AssAction_GetNameFromID2(comid, atab, section)

    if not comid then
      return
    end

    local seclist = {0,100,32060,32061,32062,32063}
    if string.sub(comid,1,1) == '_' then
      comid = string.sub(comid,2)
    end
    local ret = 'Action: '..comid
    local ret2
    local ret3 = section

    if atab == nil then
      atab = GetActionListTables()
    end

    for i = 1, #seclist do
      if section == nil or section == seclist[i] then

        --atab = GetActionListTable_Name(seclist[i])
        if atab[i].id[comid] then
          ret = atab[i].id[comid].cmdtxt
          ret2 = ret
          ret3 = seclist[i]
          return ret, ret2, ret3
        end
      end
    end

    return ret, ret2, ret3
  end

  function ActionCommandID_RepairCtls(ctls)

    local seclist = {0,100,32060,32061,32062,32063}
    local t = reaper.time_precise()

    local atab = GetActionListTables()

    for c = 1, #ctls do

      local ctl = ctls[c]
      --DBG(c..'  '..tostring(ctl.param_info.paramstr))

      if ctl.ctlcat == ctlcats.action and ctl.param_info.paramstr2 then

        local ps = ctl.param_info.paramstr2
        local sec = tonumber(ctl.param_info.paramstr)

        for x = 1, #atab do

          if sec == nil or seclist[x] == sec then
            if atab[x].desc[ps] then

              if atab[x].desc[ps].cmdid then
                if '_'..atab[x].desc[ps].cmdid ~= ctl.param_info.paramidx then
                  --DBG('updating:  '..atab[x].desc[ps].cmdid)
                  ctl.param_info.paramidx = '_'..atab[x].desc[ps].cmdid
                end
              end

              --DBG('idx = '..tostring(ctl.param_info.paramidx))
              --DBG('num = '..tostring(ctl.param_info.paramnum))
              --DBG(ps..' :    '..tostring(atab[x].desc[ps].cmdid)..'    -     '..atab[x].desc[ps].cmdnum)
              break
            end
          end
        end

      end
    end


  end

  function ActionCommandID_Repair()

    local seclist = {0,100,32060,32061,32062,32063}
    local t = reaper.time_precise()

    local atab = GetActionListTables()

    for s = 1, #strips do
      if strips[s] then
        for p = 1, lvar.maxpage do

          if #strips[s][p].controls > 0 then
            for c = 1, #strips[s][p].controls do

              local ctl = strips[s][p].controls[c]
              if ctl.ctlcat == ctlcats.action and ctl.param_info.paramstr2 then

                local ps = ctl.param_info.paramstr2
                local sec = tonumber(ctl.param_info.paramstr)

                for x = 1, #atab do

                  if sec == nil or seclist[x] == sec then
                    if atab[x].desc[ps] then

                      if atab[x].desc[ps].cmdid then
                        if '_'..atab[x].desc[ps].cmdid ~= ctl.param_info.paramidx then
                          --DBG('updating')
                          ctl.param_info.paramidx = '_'..atab[x].desc[ps].cmdid
                        end
                      end

                      --DBG('idx = '..tostring(ctl.param_info.paramidx))
                      --DBG('num = '..tostring(ctl.param_info.paramnum))
                      --DBG(ps..' :    '..tostring(atab[x].desc[ps].cmdid)..'    -     '..atab[x].desc[ps].cmdnum)
                      break
                    end
                  end

                end


              end
            end
          end

        end
      end
    end

    local tt = reaper.time_precise() - t
    --DBG(tt)

  end

  function GetActionListTables()
    local seclist = {0,100,32060,32061,32062,32063}
    local atab = {}
    for i = 1, #seclist do
      atab[i] = GetActionListTable_Name(seclist[i])
    end
    return atab
  end

  function GetActionListTable_Name(section)
    local tab = {id = {}, desc = {}}
    if reaper.APIExists('CF_EnumerateActions') then
      for i = 0, 1000000 do
        local id, nm = reaper.CF_EnumerateActions(section,i,'')
        if id == 0 then
          break
        end
        local cmdid = reaper.ReverseNamedCommandLookup(id)
        tab.desc[nm] = {cmdnum = id,
                        cmdtxt = nm,
                        cmdid = cmdid}
        tab.id[id] = tab.desc[nm]
        if cmdid then
          tab.id[cmdid] = tab.desc[nm]
        end
      end
    end
    return tab
  end

  function GetActionInfoFromList()
    local list1ID = 0x52B
    if reaper.APIExists('JS_ReaScriptAPI_Version') then
      if reaper.JS_ReaScriptAPI_Version() >= 0.961 then
        local hwnd = reaper.JS_Window_Find('Actions',true)
        if hwnd then
          local lhwnd = reaper.JS_Window_FindChildByID(hwnd, list1ID)
          --local lhwndCB = reaper.JS_Window_FindChild(hwnd, 'ComboBox1', true)
          --local id = reaper.JS_Window_GetLongPtr(lhwnd, "ID")
          --DBG('list1 id: '..tostring(id))
          if lhwnd then
            local lhwnd_sec = reaper.JS_Window_FindChildByID(hwnd,1317)
            local secstr = 0

            if lhwnd_sec then
              secstr = reaper.JS_Window_GetTitle(lhwnd_sec)
            end
            local retval, text = reaper.JS_ListView_GetFocusedItem(lhwnd)
            if retval then
              local desc = reaper.JS_ListView_GetItemText(lhwnd, retval, 1)
              local commandID = reaper.JS_ListView_GetItemText(lhwnd, retval, 3)
              if commandID then
                return commandID, desc
              end
            end
          end
        end
      end
    end
  end

  function AssActionFromList()
    local list1ID = 0x52B
    if reaper.APIExists('JS_ReaScriptAPI_Version') then
      if reaper.JS_ReaScriptAPI_Version() >= 0.961 then
        local hwnd = reaper.JS_Window_Find('Actions',true)
        if hwnd then
          local lhwnd = reaper.JS_Window_FindChildByID(hwnd, list1ID)
          --local lhwndCB = reaper.JS_Window_FindChild(hwnd, 'ComboBox1', true)
          --local id = reaper.JS_Window_GetLongPtr(lhwnd, "ID")
          --DBG('list1 id: '..tostring(id))
          if lhwnd then
            local lhwnd_sec = reaper.JS_Window_FindChildByID(hwnd,1317)
            local secstr = 0

            if lhwnd_sec then
              secstr = reaper.JS_Window_GetTitle(lhwnd_sec)
            end
            local retval, text = reaper.JS_ListView_GetFocusedItem(lhwnd)
            if retval then
              local desc = reaper.JS_ListView_GetItemText(lhwnd, retval, 1)
              local commandID = reaper.JS_ListView_GetItemText(lhwnd, retval, 3)
              if commandID then
                if (desc or '') == '' then
                  desc = 'Cmd ID: '..string.gsub(commandID,'_','')
                end
                trackfxparam_select = ctl_select[1].ctl
                --DBG(ConvSectionStr(secstr))
                AssActionByID(commandID, desc, desc, ConvSectionStr(secstr))
                update_gfx = true
              end
            else
              OpenMsgBox(1, 'Unable to retrieve focused item.', 1)
            end
          end
        else
          OpenMsgBox(1, 'This function requires the action list to be open.', 1)
        end
      else
        OpenMsgBox(1, 'This function requires JS_ReaScriptAPI extension version 0.961 (or greater).', 1)
      end
    else
      OpenMsgBox(1, 'This function requires JS_ReaScriptAPI extension version 0.961 (or greater).', 1)
    end
  end

  function ConvSectionStr(s)

    if s == 'Main' then
      return 0
    elseif s == 'Main (alt recording)' then
      return 100
    elseif s == 'Media Explorer' then
      return 32063
    elseif s == 'MIDI Editor' then
      return 32060
    elseif s == 'MIDI Event List Editor' then
      return 32061
    elseif s == 'MIDI Inline Editor' then
      return 32062
    end

  end

  function AssActionByID(txt, p_actnm, actiondesc, section)
    local actnm = 'Action: '..txt
    if p_actnm then
      actnm = p_actnm
    end
    strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramname = actnm
    if tonumber(txt) == nil then
      strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramidx = txt
      strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramnum = nil
    else
      strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramidx = nil
      strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramnum = tonumber(txt)
    end
    if section then
      strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramstr = section
    end
    strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramstr2 = actiondesc --store exact description name for identifying when sharing
    lupd.update_gfx = true

  end

  function table.shift(t, old, new)
    local value = t[old]
    if new < old then
      table.move(t, new, old - 1, new + 1)
    else
      table.move(t, old + 1, new, old)
    end
    t[new] = value
  end

  function table.copy(t)
    if t == nil then return nil end
    local u = { }
    for k, v in pairs(t) do u[k] = v end
    return setmetatable(u, getmetatable(t))
  end

  function table.deepcopy(o, seen)
    seen = seen or {}
    if o == nil then return nil end
    if seen[o] then return seen[o] end


    local no = {}
    seen[o] = no
    setmetatable(no, table.deepcopy(getmetatable(o), seen))

    for k, v in next, o, nil do
      k = (type(k) == 'table') and table.deepcopy(k, seen) or k
      v = (type(v) == 'table') and table.deepcopy(v, seen) or v
      no[k] = v
    end
    return no
  end

  function table_slowsort_val(tbl, startidx, rev)

     local dtbl = {}
     local rtbl
     local cnt = #tbl
     local sidx = startidx or 1
     if cnt > 0 then
       for st = sidx, cnt do
         if st == sidx then
           --insert
           table.insert(dtbl, tbl[st])
         else
           local inserted = false
           local dcnt = #dtbl
           for dt = 1, dcnt do
             if dtbl[dt].val then
               if tbl[st] and dtbl[dt] and nz(tonumber(tbl[st].val),0) > nz(tonumber(dtbl[dt].val),0) then
                 table.insert(dtbl, dt, tbl[st])
                 inserted = true
                 break
               end
             else
               break
             end
           end
           if inserted == false then
             table.insert(dtbl, tbl[st])
           end
         end
       end
       rtbl = {}
       local offset = 0
       if sidx ~= 1 then
         offset = -1+sidx
       end
       if rev then
         for dt = 1, #dtbl do
           rtbl[dt+offset] = dtbl[dt]
         end
       else
         for dt = #dtbl, sidx, -1 do
           rtbl[#dtbl-(dt-1)+offset] = dtbl[dt]
         end
       end
     end
     return rtbl
  end

  function table_slowsort_val2(tbl, startidx, rev, caseinsensitive)

     local dtbl = {}
     local rtbl
     local cnt = #tbl
     local sidx = startidx or 1
     if cnt > 0 then
       for st = sidx, cnt do
         if st == sidx then
           --insert
           table.insert(dtbl, tbl[st])
         else
           local inserted = false
           local dcnt = #dtbl
           for dt = 1, dcnt do
             if dtbl[dt].val then
               if caseinsensitive then
                 if tbl[st] and dtbl[dt] and string.lower((tbl[st]) or '') > string.lower((dtbl[dt]) or '') then
                   table.insert(dtbl, dt, tbl[st])
                   inserted = true
                   break
                 end
               else
                 if tbl[st] and dtbl[dt] and ((tbl[st]) or '') > ((dtbl[dt]) or '') then
                   table.insert(dtbl, dt, tbl[st])
                   inserted = true
                   break
                 end
                end
             else
               break
             end
           end
           if inserted == false then
             table.insert(dtbl, tbl[st])
           end
         end
       end
       rtbl = {}
       local offset = 0
       if sidx ~= 1 then
         offset = -1+sidx
       end
       if rev then
         for dt = 1, #dtbl do
           rtbl[dt+offset] = dtbl[dt]
         end
       else
         for dt = #dtbl, sidx, -1 do
           rtbl[#dtbl-(dt-1)+offset] = dtbl[dt]
         end
       end
     end
     return rtbl
  end

  function table_slowsort_gen(tbl,idxfield)

     local dtbl = {}
     local rtbl
     local cnt = #tbl
     if cnt > 0 then
       for st = 1, cnt do
         if st == 1 then
           --insert
           table.insert(dtbl, tbl[st])
         else
           local inserted = false
           local dcnt = #dtbl
           for dt = 1, dcnt do
             if dtbl[dt][idxfield] then
               if tbl[st] and dtbl[dt] and (tonumber(tbl[st][idxfield]) or 0) > (tonumber(dtbl[dt][idxfield]) or 0) then
                 table.insert(dtbl, dt, tbl[st])
                 inserted = true
                 break
               end
             else
               break
             end
           end
           if inserted == false then
             table.insert(dtbl, tbl[st])
           end
         end
       end
       rtbl = {}
       for dt = #dtbl, 1, -1 do
         rtbl[#dtbl-(dt-1)] = dtbl[dt]
       end
     end
     return rtbl
  end

  function table_slowsort_gen2(tbl,idxfield,startidx,caseinsensitive)

     local dtbl = {}
     local rtbl
     local cnt = #tbl
     local sidx = startidx or 1
     if cnt > sidx-1 then
       for st = sidx, cnt do
         if st == sidx then
           --insert
           table.insert(dtbl, tbl[st])
         else
           local inserted = false
           local dcnt = #dtbl
           for dt = 1, dcnt do
             if dtbl[dt][idxfield] then
               if caseinsensitive then
                 if tbl[st] and dtbl[dt] and (string.lower(tbl[st][idxfield])) > (string.lower(dtbl[dt][idxfield])) then
                   table.insert(dtbl, dt, tbl[st])
                   inserted = true
                   break
                 end
               else
                 if tbl[st] and dtbl[dt] and ((tbl[st][idxfield])) > ((dtbl[dt][idxfield])) then
                   table.insert(dtbl, dt, tbl[st])
                   inserted = true
                   break
                 end
               end
             else
               break
             end
           end
           if inserted == false then
             table.insert(dtbl, tbl[st])
           end
         end
       end
       rtbl = {}
       local offset = 0
       if sidx ~= 1 then
         offset = -1+sidx
       end
       for dt = #dtbl, sidx, -1 do
         rtbl[#dtbl-(dt-1)+offset] = dtbl[dt]
       end
     end
     return rtbl
  end

  function cycledata_slowsort(tbl)

    local dtbl = {}
    if tbl.statecnt > 0 then
      for st = 1, tbl.statecnt do
        if st == 1 then
          --insert
          table.insert(dtbl, tbl[st])
        else
          local inserted = false
          local dcnt = #dtbl
          for dt = 1, dcnt do
            if dtbl[dt].val then
              if tbl[st] and dtbl[dt] and nz(tonumber(tbl[st].val),0) > nz(tonumber(dtbl[dt].val),0) then
                table.insert(dtbl, dt, tbl[st])
                inserted = true
                break
              end
            else
              break
            end
          end
          if inserted == false then
            table.insert(dtbl, tbl[st])
          end
        end
      end
    end

    local otbl = {statecnt = tbl.statecnt,
                  selected = tbl.selected,
                  mapptof = tbl.mapptof,
                  invert = tbl.invert,
                  draggable = tbl.draggable,
                  spread = tbl.spread,
                  pos = 1,
                  tspactive = tbl.tspactive,
                  {}}
    local dcnt = #dtbl
    for i = 1, dcnt do
      otbl[i] = {val = dtbl[dcnt-(i-1)].val, dispval = dtbl[dcnt-(i-1)].dispval, dv = dtbl[dcnt-(i-1)].dv,
                 startval = dtbl[dcnt-(i-1)].startval, nextval = dtbl[dcnt-(i-1)].nextval, tsp = dtbl[dcnt-(i-1)].tsp}
    end

    return otbl

  end

  function CloseActChooser()

    show_actionchooser = false
    action_tbl = {}
    action_tblF = {}
    al_select = 0
    lupd.update_actcho = true

  end

  function GetSnapshotCtlIdx(strip, page, sstype, ctl)

    local idx = nil

    if sstype > 1 then
      if snapshots[strip][page][sstype].ctls then
        for c = 1, #snapshots[strip][page][sstype].ctls do

          if snapshots[strip][page][sstype].ctls[c].c_id == strips[strip][page].controls[ctl].c_id then
            idx = c
            break
          end
        end
      end
    end
    return idx
  end

  function GetMacroCtlIdx(strip, page, ctl, selc)

    local idx = nil

    if strips[strip][page].controls[ctl].macroctl then
      for c = 1, #strips[strip][page].controls[ctl].macroctl do

        if strips[strip][page].controls[ctl].macroctl[c].c_id == strips[strip][page].controls[selc].c_id then
          idx = c
          break
        end
      end
    end
    return idx
  end

  function SetParam_ToDef(i)
    local ctltype = strips[tracks[track_select].strip][page].controls[i].ctltype
    trackfxparam_select = i
    local ctl = strips[tracks[track_select].strip][page].controls[i]
    if ctl.enabledefval == false then return end
    if ctltype == 1 or ctltype == 11 then

      ctl.val = ctl.defval
      SetParam()
      ctl.dirty = true
      lupd.update_ctls = true

    elseif ctltype == 4 then
      ctl.cycledata.pos = round(ctl.cycledata.statecnt *
                                ctl.defval)
      if ctl.cycledata.pos < 1 then ctl.cycledata.pos = 1
      elseif ctl.cycledata.pos > ctl.cycledata.statecnt then
        ctl.cycledata.pos = ctl.cycledata.statecnt
      end

      ctl.val = ctl.cycledata[ctl.cycledata.pos].val or 0
      SetParam()
      ctl.dirty = true

      lupd.update_ctls = true

    end
    SetCtlDirty(i)
  end

  function SetParam_EnterVal(i)

    --if strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.macro then return end

    local ctltype = strips[tracks[track_select].strip][page].controls[i].ctltype
    if ctltype == 1 then
      trackfxparam_select = i
      OpenEB(5,'Please enter value:')
    elseif ctltype == 6 then
      trackfxparam_select = i
      strips[tracks[track_select].strip][page].controls[i].defval = GetParamValue_Ctl(i)
    end

  end

  function Env_Test(strip, page)

    if strips and strips[strip] then
      local ctls = strips[strip][page].controls
      reaper.PreventUIRefresh(1)-- Prevent UI refreshing. Uncomment it only if the script works.
      for i = 1, #ctls do

        Envelope_SetProps(strip,page,i, false, false, false)
      end
      reaper.PreventUIRefresh(-1)
      for i = 1, #ctls do

        Envelope_SetProps(strip,page,i, nil, true, nil)

        reaper.TrackList_AdjustWindows(false)
        reaper.UpdateTimeline()
        reaper.UpdateArrange()

      end
    end
  end

  function Envelope_Clear(env)

   --[[ local _, envchunk = reaper.GetEnvelopeStateChunk(env, "", false)
    envchunk = envchunk:gsub("\n", "¤¤")
    reaper.SetEnvelopeStateChunk(env, envchunk, false)]]
    local env_points_count = reaper.CountEnvelopePoints(env)
    local retval_last, time_last, valueSource_last, shape_last, tension_last, selectedOut_last = reaper.GetEnvelopePoint(env, env_points_count-1)
    reaper.DeleteEnvelopePointRange(env, 0, time_last+1)
    --Envelope_SetProps2(env,true,true,true)

  end

  function Envelope_Add(strip,page,c)
    local ctl = strips[strip][page].controls[c]
    if ctl.ctlcat == ctlcats.fxparam then
      local track
      if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end
      env = reaper.GetFXEnvelope(track, ctl.fxnum, ctl.param_info.paramnum,true)
      reaper.TrackList_AdjustWindows(false)
      reaper.UpdateTimeline()
      reaper.UpdateArrange()
    end
  end

  function Envelope_AddAllFX(strip,page,c)
    local ctl = strips[strip][page].controls[c]
    if ctl.ctlcat == ctlcats.fxparam then
      local track
      if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end
      for cc = 1, #strips[strip][page].controls do
        local cctl = strips[strip][page].controls[cc]
        if cctl.ctlcat == ctlcats.fxparam then
          if cctl.fxguid == ctl.fxguid then
            local env = reaper.GetFXEnvelope(track, cctl.fxnum, cctl.param_info.paramnum, true)
          end
        end
      end
      reaper.TrackList_AdjustWindows(false)
      reaper.UpdateTimeline()
      reaper.UpdateArrange()
    end
  end

  function Envelopes_SetProps(active, visible, armed, clear, strip, page)

    if strips and #strips > 0 then
      if strip == nil then
        reaper.PreventUIRefresh(1)
        for s = 1, #strips do
          for p = 1, lvar.maxpage do
            for c = 1, #strips[s][p].controls do

              local ctl = strips[s][p].controls[c]
              Envelope_SetProps(s,p,c,active,false,armed, clear)

            end
          end
        end
        reaper.PreventUIRefresh(-1)
        for s = 1, #strips do
          for p = 1, lvar.maxpage do
            for c = 1, #strips[s][p].controls do

              local ctl = strips[s][p].controls[c]
              Envelope_SetProps(s,p,c,active,nz(visible,true),armed, clear)

            end
          end
        end
      else
        local s, p = strip, page
        if strip and page and strips[s] then
          reaper.PreventUIRefresh(1)
          for c = 1, #strips[s][p].controls do

            local ctl = strips[s][p].controls[c]
            Envelope_SetProps(s,p,c,active,false,armed, clear)

          end
          reaper.PreventUIRefresh(-1)
          for c = 1, #strips[s][p].controls do

            local ctl = strips[s][p].controls[c]
            Envelope_SetProps(s,p,c,active,nz(visible,true),armed, clear)

          end
        end
      end
      reaper.TrackList_AdjustWindows(false)
      reaper.UpdateTimeline()
      reaper.UpdateArrange()
    end

  end

  function Envelope_SetProps(strip, page, c, active, visible, armed, clear)

    if strips and strips[strip] and strips[strip][page].controls[c] then

      local ctl = strips[strip][page].controls[c]
      local track
      if ctl.tracknum == nil then
        track = GetTrack(strips[strip].track.tracknum)
      else
        track = GetTrack(ctl.tracknum)
      end

      if track then

        local env
        if ctl.ctlcat == ctlcats.fxparam then
          env = reaper.GetFXEnvelope(track, ctl.fxnum, ctl.param_info.paramnum,false)

        elseif ctl.ctlcat == ctlcats.trackparam then
          local env_count = reaper.CountTrackEnvelopes(track)
          for j = 0, env_count-1 do

            local e = reaper.GetTrackEnvelope(track, j)
            retval, envName = reaper.GetEnvelopeName(e, "")

            if envName == string.sub(ctl.param_info.paramname,7) then
              env = e
              break
            end
          end

        elseif ctl.ctlcat == ctlcats.tracksend then
          --mute all envelopes?]]
        end

        if env then
          if clear == true then
            Envelope_Clear(env)
          else
            Envelope_SetProps2(env, active, visible, armed)
          end
        end
      end

    end

  end

  function Envelope_SetProps2(env, active_out, visible_out, armed_out)

    local br_env = reaper.BR_EnvAlloc(env, false)
    local active, visible, armed, inLane, laneHeight, defaultShape, minValue, maxValue, centerValue, type, faderScaling =
                                          reaper.BR_EnvGetProperties(br_env, true, true, true, true, 0, 0, 0, 0, 0, 0, true)
    if active_out == nil then active_out = active end
    if visible_out == nil then visible_out = visible end
    if armed_out == nil then armed_out = armed end

    --reaper.BR_EnvSetProperties(br_env, active_out, false, armed_out, inLane, laneHeight, defaultShape, faderScaling)
    reaper.BR_EnvSetProperties(br_env, active_out, visible_out, armed_out, inLane, laneHeight, defaultShape, faderScaling)
    reaper.BR_EnvFree(br_env, 1)

  end

  ------------------------------------------------------------

  function ChangeTrack(t, noscrollreset)

    if lvar.dm_editmode_data then return end
    if mouse.context ~= nil and mouse.context ~= contexts.hold then return end

    UnhideCtls()

    local ots, opg, omixx, omixy = track_select, page, surface_offset.mixx, surface_offset.mixy

    --if settings_localfaders == true then
      StoreFaders()
    --end

    if show_randomopts or show_samplemanager then
      show_randomopts = false
      show_samplemanager = false
      RedrawGUIBitmap()
    end

    --if lvar.livemode == 2 then
    --else
      if tracks[track_select] then
        local strip = tracks[track_select].strip
        if strips[strip] then
        --DBG('store '..strip..'  '..tostring(surface_offset.mixy))
          strips[strip][page].mixy = surface_offset.mixy
          strips[strip][page].mixx = surface_offset.mixx
        
          if lvar.livemode == 2 then
            DM_StoreStripData()
          end
        end
      end
    --end

    if tracks[t] == nil then
      t = -1
    end

    if gpage == true or t ~= LBX_GTRACK then
      gpage = false
    end

    if t == LBX_GTRACK then
      gpage_opage = page
      gpage_otrackselect = track_select
    end

    SetReturnPage(t, page)

    track_select = t
    trackedit_select = t

    local strip = tracks[track_select].strip
    if lvar.dm_fixtrack and track_select == lvar.dm_fixtrack and page == 1 then
      SetLiveMode(2, ots, opg, omixx, omixy)
      --DM_RestoreStripData()
      --lvar.livemode = 2
      --if obj then
      --  SetSurfaceSize2(obj)
      --end
    else
      if strips[strip] and strips[strip][page].lmode then
        if lvar.livemode ~= strips[strip][page].lmode then
          SetLiveMode(strips[strip][page].lmode, ots, opg, omixx, omixy)
          if lvar.livemode == 2 then
            --DM_RestoreStripData()
          end
          --lvar.livemode = strips[strip][page].lmode
          --if obj then
          --  SetSurfaceSize2(obj)
          --end
        end
      elseif lvar.livemode ~= lvar.glivemode then
        SetLiveMode(lvar.glivemode, ots, opg, omixx, omixy)
        --lvar.livemode = lvar.glivemode
        --if obj then
        --  SetSurfaceSize2(obj)
        --end
      end
    end
    
    if lvar.livemode == 2 and not noscrollreset then
      surface_offset.mixy = -40
      surface_offset.mixx = -40

    elseif not noscrollreset or (lvar.livemode == 2 and noscrollreset) then
      if strips[strip] and strips[strip][page].mixy then
        surface_offset.mixy = strips[strip][page].mixy
        surface_offset.mixx = strips[strip][page].mixx
      else
        surface_offset.mixy = 0
        surface_offset.mixx = 0
      end
      --DBG('recall '..strip..'  '..tostring(surface_offset.mixy))
    end
    lvar.mixupdate = nil

    if lvar.livemode ~= 2 then
      if lvar.analyzer.active then
        DM_ShowAnalyzer(false)
        lupd.update_trbtns = true
        lvar.saveanalactive = true
      end
    else
      settings_followselectedtrack = false
    end

    --[[if stripgallery_view == 1 then
      show_striplayout = false
    end]]

    gfx2_select = nil
    gfx3_select = nil
    gfx4_select = nil
    gfx4_selectidx = nil
    lvar.ctlpreview_sel = nil
    lvar.gfxpreview_sel = nil
    lvar.selctl = nil

    ctl_select = nil

    GUI_DrawCtlBitmap()
    RedrawGUIBitmap()

    SetASLocs()
    striplayout_selstripid = nil
    SetGalleryView()

    if T_butt_cnt then
      tlist_offset = CalcTListPos(track_select)
    end
    InsertDefaultStrip()

    if settings_trackchangemidi == true then
      TrackChangeMidi()
    end

    ctls_dnu, ctls_upd, ctls_orr = CtlDNU()

    --if settings_localfaders == true then
      RecallFaders()
    --end

    if show_modass then
      lvar.modass = PopModAssObj()
      if lvar.modass then
        lvar.modass.offset = 0
      end
    end
    lvar.readpeaks = PopReadPeaks()

    --UpdateControlValues3(rt, ctls_upd, ctls_orr)
    
    --Env_Test(tracks[track_select].strip, page)
    SetSurfaceFade()
    
  end

  function ChangeTrack2(t, p, loadmixmodeoffsets)

    if lvar.dm_editmode_data then return end
    if mouse.context ~= nil and mouse.context ~= contexts.hold then return end
    
    UnhideCtls()
    
    local fnd
    if show_eqcontrol then

      fnd = false
      if tracks and tracks[t] and tracks[t].strip and strips[tracks[t].strip] and strips[tracks[t].strip][page].controls then
        for c = 1, #strips[tracks[t].strip][page].controls do

          if strips[tracks[t].strip][page].controls[c].ctlcat == ctlcats.eqcontrol then

            eqcontrol_select = c
            if strips[tracks[t].strip][page].controls[c].eqbands and #strips[tracks[t].strip][page].controls[c].eqbands then
              eqcontrolband_select = 1
            else
              eqcontrolband_select = nil
            end
            fnd = true

            break
          end

        end
      end
    else
      fnd = true
    end

    if fnd then
      if tracks[track_select] and strips[tracks[track_select].strip] then
        strips[tracks[track_select].strip].page = page
      end
      if p then
        page = p
      else
        local strip = tracks[t].strip
        if not p and strips and strip and strips[strip] then
          page = strips[strip].page
          surface_offset.x = strips[strip][page].surface_x
          surface_offset.y = strips[strip][page].surface_y
        elseif not p then
          page = 1
          surface_offset.x = 0
          surface_offset.y = 0
        end
      end

      ChangeTrack(t,loadmixmodeoffsets)
      ss_select = nil
      sstype_select = 1
      ssoffset = 0
      if loadmixmodeoffsets then

      end
      if settings_followselectedtrack and gpage == false then
        --Select track
        local tr = GetTrack(t)
        if tr then
          tracks[t].name = reaper.GetTrackState(tr)

          if tr ~= nil then
            reaper.SetOnlyTrackSelected(tr)
            reaper.SetTrackSelected(tr, true)
          end
        end
      end

      CheckStripSends()
      PopulateTrackSendsInfo()
      PopulateSpecial()

      CheckStripControls()
      lupd.update_gfx = true

    end
    --DBG(track_select..'     '..page)
  end
  ------------------------------------------------------------

  function Faders_INIT(force, fads)

    local faders = fads
    if faders == nil or force then
      faders = {}
    end
    if LBX_CTL_TRACK_INF then
      for f = 1, lvar.LBX_FB_CNT*LBX_CTL_TRACK_INF.count do

        if faders[f] == nil or force then
          faders[f] = {}
        end

      end

    end
    return faders

  end

  function FaderMenu_2(sel,x,y)

    local mstr,lastp = FaderMenu(sel, true)
    gfx.x = x
    gfx.y = y
    local ret = gfx.showmenu(mstr)

    return ret, lastp

  end

  function FaderMenu(sel, returnonly, inactive, prefix)

    if LBX_CTL_TRACK_INF and LBX_CTL_TRACK_INF.count > 0 then
      local mstr = ''
      local act = ''
      if inactive == true then
        act = '#'
      end
      for fxnum = 0, LBX_CTL_TRACK_INF.count-1 do
        local fs = fxnum*lvar.LBX_FB_CNT+1
        local fe = fs+lvar.LBX_FB_CNT-1
        if mstr ~= '' then
          mstr = mstr .. '|'
        end
        mstr = mstr .. '>'..act..(prefix or '')..'Fader '..string.format('%i',fs)..'-'..string.format('%i',fe)

        for pf = 0, lvar.LBX_FB_CNT-1 do
          local p = fs + pf
          local assigned = ''
          local ticked = ''
          if faders[p].targettype then
            assigned = '#'
            if p == sel then
              ticked = '!'
            end
          end

          if nz(returnonly,false) == false then
            if pf ~= lvar.LBX_FB_CNT-1 then
              mstr = mstr .. '|'..ticked..assigned..'Fader '..fs + pf
            else
              mstr = mstr .. '|<'..ticked..assigned..'Fader '..fs + pf
            end
          else
            if assigned == '' then
              if pf ~= lvar.LBX_FB_CNT-1 then
                mstr = mstr .. '|'..ticked..'Fader '..fs + pf
              else
                mstr = mstr .. '|<'..ticked..'Fader '..fs + pf
              end
            else
              if pf ~= lvar.LBX_FB_CNT-1 then
                mstr = mstr .. '|'..ticked..'[ Fader '..fs + pf..' ]'
              else
                mstr = mstr .. '|<'..ticked..'[ Fader '..fs + pf..' ]'
              end
            end
          end
        end
      end
      local lastp = LBX_CTL_TRACK_INF.count * lvar.LBX_FB_CNT+1
      mstr = mstr .. '|'..act..'Clear Fader'
      return mstr, lastp
    else
      mstr = '#No Faderbox'
      return mstr, 1
    end

  end

  function SetAutomationFader(fad_tab, sel, returnonly, mx, my)

    if LBX_CTL_TRACK_INF and LBX_CTL_TRACK_INF.count > 0 then

      local mstr, lastp = FaderMenu(sel, returnonly)

      local menx = mx or mouse.mx
      local meny = my or mouse.my

      gfx.x = menx
      gfx.y = meny
      local ret = gfx.showmenu(mstr)

      if nz(returnonly,false) == false then
        if ret > 0 and ret ~= lastp then
          faders[ret] = fad_tab
          if sel then
            faders[sel] = {}
          end
        elseif ret == lastp then
          faders[sel] = {}
          ret = nil
        else
          ret = -1
        end
      elseif ret == lastp then
        ret = -2
      end

      return ret
    else
      return -1
    end
  end

  function Faders_SetOVAL()

    if LBX_CTL_TRACK then
      local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
      if tracks[LBX_CTL_TRACK].guid ~= GetTrackGUID(track) then
        PopulateTracks()
      end
      if LBX_CTL_TRACK then
        for fxnum = 0, LBX_CTL_TRACK_INF.count-1 do
          for pf = 0, lvar.LBX_FB_CNT-1 do
            p = fxnum * lvar.LBX_FB_CNT + pf
            if faders[p+1] then
              faders[p+1].val = round(reaper.TrackFX_GetParam(track, fxnum, pf),5)
              faders[p+1].oval = faders[p+1].val
            else
              Faders_INIT(_,faders)
              faders[p+1].val = round(reaper.TrackFX_GetParam(track, fxnum, pf),5)
              faders[p+1].oval = faders[p+1].val
            end
          end
        end
      end
    end

  end

  function ReadAutomationFaders()

    if LBX_CTL_TRACK --[[and faders]] then

      local faders = faders --or {}

      if lbx_midilrnctl == nil then
        local ccc = trackfxparam_select

        local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
        if tracks[LBX_CTL_TRACK].guid ~= GetTrackGUID(track) then
          PopulateTracks()
        end
        if xxyrecord == false then
          for fxnum = 0, LBX_CTL_TRACK_INF.count-1 do
            for pf = 0, lvar.LBX_FB_CNT-1 do
              p = fxnum * lvar.LBX_FB_CNT + pf
              faders[p+1].val = round(reaper.TrackFX_GetParam(track, fxnum, pf),7)
              if faders[p+1].val and faders[p+1].val >= 0 and (tostring(faders[p+1].val) ~= tostring(faders[p+1].oval) or faders[p+1].targettype == 3 --[[or faders[p+1].targettype == 5 or faders[p+1].targettype == 6]]) then

                if faders[p+1].targettype then
                  if faders[p+1].targettype == 0 then
                    if xxy and xxy[faders[p+1].strip] then
                      if faders[p+1].xy == 0 then
                        xxy[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype].x = faders[p+1].val
                      else
                        xxy[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype].y = faders[p+1].val
                      end
                      XXY_Set(faders[p+1].strip,faders[p+1].page,faders[p+1].sstype)
                      if show_xxy then
                        lupd.update_xxypos = true
                      end
                    else
                      --check fader
                      DeleteFader(p+1)
                    end
                  elseif faders[p+1].targettype == 1 then
                    XXYPath_SetPos(faders[p+1].strip,faders[p+1].page,faders[p+1].sstype,faders[p+1].val, p+1)
                    if show_xxy then
                      lupd.update_xxypos = true
                    end
                  elseif faders[p+1].targettype == 2 then
                    if strips[faders[p+1].strip] and strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl] then
                      strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl].oval = strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl].val
                      strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl].val = faders[p+1].val
                      --strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl].mval = faders[p+1].val
                      strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl].dirty = true
                      SetMacro(faders[p+1].strip,faders[p+1].page,faders[p+1].ctl)
                      lupd.update_ctls = true
                      if macro_edit_mode == true then
                        lupd.update_macroedit = true
                      end
                    else
                      DeleteFader(p+1)
                    end

                  elseif faders[p+1].targettype == 4 then

                    local strip = faders[p+1].strip
                    local page = faders[p+1].page
                    local c = faders[p+1].ctl
                    local dmg = faders[p+1].dm_guid
                    if dmg then
                      if dmg == lvar.dynamicmode_guid then
                        if strips[strip] and strips[strip][page].controls[c] then
                          strips[strip][page].controls[c].oval = strips[strip][page].controls[c].val
                          strips[strip][page].controls[c].val = faders[p+1].val
                          strips[strip][page].controls[c].dirty = true
                          local ctl = strips[strip][page].controls[c]
                          if ctl.ctllock ~= true then
                            A_SetParam(strip,page,c,ctl)
                            SetCtlDirty(c)
                            lupd.update_ctls = true
                          end
                        else
                          DeleteFader(p+1)
                        end
                      else
                        local ctl = lvar.stripstore[dmg].controls[c]
                        if ctl.ctllock ~= true then
                          DM_SetParam3(dmg, c, faders[p+1].val)
                          SetCtlDirty(c)
                          lupd.update_ctls = true
                        end
                      end
                    else
                      if strips[strip] and strips[strip][page].controls[c] then
                        strips[strip][page].controls[c].oval = strips[strip][page].controls[c].val
                        strips[strip][page].controls[c].val = faders[p+1].val
                        strips[strip][page].controls[c].dirty = true
                        local ctl = strips[strip][page].controls[c]
                        if ctl.ctllock ~= true then
                          A_SetParam(strip,page,c,ctl)
                          SetCtlDirty(c)
                          lupd.update_ctls = true
                        end
                      else
                        DeleteFader(p+1)
                      end
                    end
                  elseif faders[p+1].targettype == 3 then

                    if mouse.context == nil and mode == 0 and macro_edit_mode ~= true and macro_lrn_mode ~= true and show_xxy ~= true and show_eqcontrol ~= true and show_settings ~= true then
                      local strip = tracks[track_select].strip
                      local c = GetControlAtXY(strip,page,mouse.mx,mouse.my)

                      if c ~= faders[p+1].to_ctl and lvar.mofader_takeover then
                        lvar.mofader_takeover = nil
                        lupd.update_surface = true
                      end

                      if c and lvar.mousefadermode == 0 then

                        --NON ENCODER MODE

                        local ctl = strips[strip][page].controls[c]
                        if c ~= faders[p+1].to_ctl then

                          faders[p+1].oval = faders[p+1].val
                          faders[p+1].to = false
                          faders[p+1].to_ctl = c
                          if faders[p+1].val > ctl.val then
                            faders[p+1].to_pos = 1
                          elseif faders[p+1].val < ctl.val then
                            faders[p+1].to_pos = 2
                          else
                            faders[p+1].to_pos = 3
                            --faders[p+1].to = true
                          end
                        end

                        if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.trackparam or
                           ctl.ctlcat == ctlcats.tracksend or ctl.ctlcat == ctlcats.macro --[[or ctl.ctlcat == ctlcats.rs5k]] then

                          if faders[p+1].mode == 0 then

                            --absolute
                            if faders[p+1].to == false and faders[p+1].val ~= faders[p+1].oval then
                              if faders[p+1].to_pos == 1 then
                                if faders[p+1].val <= ctl.val then
                                  faders[p+1].to = true
                                  if faders[p+1].val ~= faders[p+1].oval then
                                    lupd.update_surface = true
                                  end
                                end
                              else
                                if faders[p+1].val >= ctl.val then
                                  faders[p+1].to = true
                                  if faders[p+1].val ~= faders[p+1].oval then
                                    lupd.update_surface = true
                                  end
                                end
                              end
                            end

                            if faders[p+1].to == true then

                              if not lvar.mofader_takeover then
                                local w,h = ctl.wsc, ctl.hsc

                                if stripgallery_view == 0 then
                                  x,y = ctl.xsc + obj.sections[10].x - surface_offset.x,
                                        ctl.ysc + obj.sections[10].y - surface_offset.y
                                else
                                  x,y = TranslateGalleryCtlPos(c)
                                end
                                lvar.mofader_takeover = {}
                                lvar.mofader_takeover.xywh = {x=x,y=y,w=w,h=h}
                              end
                              lvar.mofader_takeover.to = true
                              ctl.oval = ctl.val
                              ctl.val = faders[p+1].val
                              if ctl.oval ~= ctl.val and ctl.ctllock ~= true then
                                A_SetParam(strip,page,c,ctl)
                                ctl.dirty = true
                                lupd.update_ctls = true
                              end

                            elseif faders[p+1].val ~= faders[p+1].oval then

                              if not lvar.mofader_takeover or c ~= lvar.mofader_takeover.c then
                                local x,y
                                local w,h = ctl.wsc, ctl.hsc

                                if stripgallery_view == 0 then
                                  x,y = ctl.xsc + obj.sections[10].x - surface_offset.x,
                                        ctl.ysc + obj.sections[10].y - surface_offset.y
                                else
                                  x,y = TranslateGalleryCtlPos(c)
                                end
                                lvar.mofader_takeover = {}
                                lvar.mofader_takeover.xywh = {x=x,y=y,w=w,h=h}
                                lvar.mofader_takeover.c = c
                              end
                              lvar.mofader_takeover.mx = mouse.mx
                              lvar.mofader_takeover.my = mouse.my
                              lvar.mofader_takeover.pos = faders[p+1].val
                              lvar.mofader_takeover.target = ctl.val
                              lvar.mofader_takeover.to_pos = faders[p+1].to_pos

                              lupd.update_surface = true
                            end
                          end
                        end

                      elseif c and lvar.mousefadermode == 1 and lvar.disabletakeover_ctl ~= c then

                        --ENCODER MODE

                        faders[p+1].val = reaper.TrackFX_GetParam(track, fxnum, pf)

                        local ctl = strips[strip][page].controls[c]

                        if ctl.ctlcat == ctlcats.fxparam or ctl.ctlcat == ctlcats.trackparam or
                           ctl.ctlcat == ctlcats.tracksend or ctl.ctlcat == ctlcats.macro or ctl.ctlcat == ctlcats.rs5k then

                          if c ~= faders[p+1].to_ctl then

                            faders[p+1].to = true
                            faders[p+1].to_ctl = c
                            faders[p+1].latch = true
                            break

                          elseif faders[p+1].latch then
                            local vv = math.floor(GetParamValue(ctl.ctlcat,ctl.tracknum or tracks[track_select].tracknum,ctl.fxnum,ctl.param,c)*lvar.maxdim)/lvar.maxdim
                            faders[p+1].val = reaper.TrackFX_GetParam(track, fxnum, pf)
                            if vv and faders[p+1].val == vv then
                              faders[p+1].latch = nil

                            elseif vv then
                              SetFaderBoxVal(p+1,vv)
                              break
                            else
                              faders[p+1].latch = nil
                            end

                            if faders[p+1].latch == nil then
                              faders[p+1].val = round(reaper.TrackFX_GetParam(track, fxnum, pf),7)
                              faders[p+1].oval = faders[p+1].val

                              --if not lvar.mofader_takeover then
                              local w,h = ctl.wsc, ctl.hsc

                              if stripgallery_view == 0 then
                                x,y = ctl.xsc + obj.sections[10].x - surface_offset.x,
                                      ctl.ysc + obj.sections[10].y - surface_offset.y
                              else
                                x,y = TranslateGalleryCtlPos(c)
                              end
                              lvar.mofader_takeover = {}
                              lvar.mofader_takeover.xywh = {x=x,y=y,w=w,h=h}
                              --end
                              lvar.mofader_takeover.to = true
                              lupd.update_surface = true
                            end
                          end

                          if faders[p+1].mode == 0 and faders[p+1].val ~= faders[p+1].oval then
                            --absolute

                            --[[if faders[p+1].to == false and faders[p+1].val ~= faders[p+1].oval then
                              if faders[p+1].to_pos == 1 then
                                if faders[p+1].val <= ctl.val then
                                  faders[p+1].to = true
                                  if faders[p+1].val ~= faders[p+1].oval then
                                    lupd.update_surface = true
                                  end
                                end
                              else
                                if faders[p+1].val >= ctl.val then
                                  faders[p+1].to = true
                                  if faders[p+1].val ~= faders[p+1].oval then
                                    lupd.update_surface = true
                                  end
                                end
                              end
                            end]]

                            if faders[p+1].to == true then
                              --[[if not lvar.mofader_takeover then
                                local w,h = ctl.wsc, ctl.hsc

                                if stripgallery_view == 0 then
                                  x,y = ctl.xsc + obj.sections[10].x - surface_offset.x,
                                        ctl.ysc + obj.sections[10].y - surface_offset.y
                                else
                                  x,y = TranslateGalleryCtlPos(c)
                                end
                                lvar.mofader_takeover = {}
                                lvar.mofader_takeover.xywh = {x=x,y=y,w=w,h=h}
                                lupd.update_surface = true
                              end
                              lvar.mofader_takeover.to = true]]
                              ctl.oval = ctl.val
                              ctl.val = faders[p+1].val
                              if tostring(ctl.oval) ~= tostring(ctl.val) and ctl.ctllock ~= true then
                                A_SetParam(strip,page,c,ctl)
                                SetCtlDirty(c)
                                ctl.dirty = true
                                lupd.update_ctls = true
                              end

                            elseif faders[p+1].val ~= faders[p+1].oval then

                              if not lvar.mofader_takeover or c ~= lvar.mofader_takeover.c then
                                local x,y
                                local w,h = ctl.wsc, ctl.hsc

                                if stripgallery_view == 0 then
                                  x,y = ctl.xsc + obj.sections[10].x - surface_offset.x,
                                        ctl.ysc + obj.sections[10].y - surface_offset.y
                                else
                                  x,y = TranslateGalleryCtlPos(c)
                                end
                                lvar.mofader_takeover = {}
                                lvar.mofader_takeover.xywh = {x=x,y=y,w=w,h=h}
                                lvar.mofader_takeover.c = c
                              end
                              lvar.mofader_takeover.mx = mouse.mx
                              lvar.mofader_takeover.my = mouse.my
                              lvar.mofader_takeover.pos = faders[p+1].val
                              lvar.mofader_takeover.target = ctl.val
                              lvar.mofader_takeover.to_pos = faders[p+1].to_pos

                              lupd.update_surface = true
                            end
                          end
                        end
                      else
                        lvar.disabletakeover_ctl = -1
                        faders[p+1].to_ctl = nil
                        if lvar.mofader_takeover then
                          lvar.mofader_takeover = nil
                          lupd.update_surface = true
                        end
                      end
                    end

                  elseif faders[p+1].targettype == 5 then
                    local ss = round(faders[p+1].val*127)+1
                    local strip = tracks[track_select].strip
                    local fnd = false
                    if sstype_select == 1 then
                      if snapshots[strip] and
                         snapshots[strip][page] and
                         snapshots[strip][page][sstype_select] and
                         snapshots[strip][page][sstype_select][ss] then
                        ss_select = ss
                        fnd = true
                      end
                    else
                      if snapshots[strip] and
                         snapshots[strip][page] and
                         snapshots[strip][page][sstype_select] and
                         snapshots[strip][page][sstype_select].snapshot[ss] then
                        ss_select = ss
                        fnd = true
                      end
                    end
                    if fnd then
                      Snapshot_Set(strip,page,sstype_select,ss_select)
                      lupd.update_snaps = true
                      lupd.update_ctls = true
                      --lupd.update_gfx = true
                      --lupd.update_gfx = true
                    end

                  elseif faders[p+1].targettype == 9 then

                    local ss = round(faders[p+1].val*127)+1
                    if lvar.snapcapture_midi_dt ~= true or (reaper.time_precise() <= (lvar.capturelatchtime or 0) and ss == lvar.capturess) then
                      local strip = tracks[track_select].strip
                      local fnd = false
                      if sstype_select == 1 then
                        if snapshots[strip] and
                           snapshots[strip][page] and
                           snapshots[strip][page][sstype_select] then
                          if snapshots[strip][page][sstype_select][ss] then
                            ss_select = ss
                            fnd = true
                          end
                        end
                      else
                        if snapshots[strip] and
                           snapshots[strip][page] and
                           snapshots[strip][page][sstype_select] then

                          if snapshots[strip][page][sstype_select].snapshot[ss] then
                            ss_select = ss
                            fnd = true
                          end
                        end
                      end
                      if fnd then
                        Snapshots_CREATE(strip, page, sstype_select, ss_select)
                        lupd.update_snaps = true
                        lupd.update_ctls = true --to update snapshot ctls
                      end
                    else
                      lvar.capturelatchtime = reaper.time_precise() + 0.5
                      lvar.capturess = ss
                    end

                  elseif faders[p+1].targettype == 6 then
                    local sel = round(faders[p+1].val*127)+1 - faders[p+1].voffset
                    Switcher_Set2(faders[p+1].ctl ,sel, faders[p+1].strip, faders[p+1].page)

                  elseif faders[p+1].targettype == 7 then

                    if strips[faders[p+1].strip] and strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl] then
                      local ctl = strips[faders[p+1].strip][faders[p+1].page].controls[faders[p+1].ctl]

                      local ss = round(faders[p+1].val*127)+1 - faders[p+1].voffset
                      local fnd = false
                      local sstype = ctl.param
                      if sstype == 1 then
                        if snapshots[faders[p+1].strip] and
                           snapshots[faders[p+1].strip][faders[p+1].page] and
                           snapshots[faders[p+1].strip][faders[p+1].page][sstype] and
                           snapshots[faders[p+1].strip][faders[p+1].page][sstype][ss] then
                          if tracks[track_select].strip == faders[p+1].strip and page == faders[p+1].page then
                            fss_select = ss
                            if sstype_select == sstype then
                              ss_select = ss
                            end
                          end
                          fnd = true
                        end
                      else
                        if snapshots[faders[p+1].strip] and
                           snapshots[faders[p+1].strip][faders[p+1].page] and
                           snapshots[faders[p+1].strip][faders[p+1].page][sstype] and
                           snapshots[faders[p+1].strip][faders[p+1].page][sstype].snapshot[ss] then
                          if tracks[track_select].strip == faders[p+1].strip and page == faders[p+1].page then
                            fss_select = ss
                            if sstype_select == sstype then
                              ss_select = ss
                            end
                          end
                          fnd = true
                        end
                      end
                      if fnd then
                        Snapshot_Set(faders[p+1].strip,faders[p+1].page,sstype,ss)
                        lupd.update_ctls = true
                        lupd.update_snaps = true
                      end
                    end

                  elseif faders[p+1].targettype == 8 then
                    if snapshots[faders[p+1].strip] and
                       snapshots[faders[p+1].strip][faders[p+1].page] and
                       snapshots[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype] then
                      if snapshots[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype].morph_sync == false then
                        snapshots[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype].morph_time = faders[p+1].val
                      else
                        snapshots[faders[p+1].strip][faders[p+1].page][faders[p+1].sstype].morph_syncv = math.min(1+round(faders[p+1].val*127),#lvar.sync_table)
                      end
                      lupd.update_snaps = true
                    end
                  end
                end

              --elseif faders[p+1].val < 0 then
              --  DBG('nil')
              --  faders[p+1].latch = nil
              end
              faders[p+1].oval = faders[p+1].val

              if faders[p+1].targettype == 4 then

                local strip = faders[p+1].strip
                local page = faders[p+1].page
                local c = faders[p+1].ctl
                local dmg = faders[p+1].dm_guid
                local ctl, t

                if dmg then
                  ctl = lvar.stripstore[dmg].controls[c]
                  t = ctl.tracknum or strips[strip].track.tracknum
                  if not t then
                    local dm_strip = lvar.stripstore[dmg]
                    if not dm_strip.trn then
                      dm_strip.trn, track = GetTRNfromGUID(guid)
                    else
                      track = GetTrack(dm_strip.trn)
                      if not dm_strip.trn == GetTrackGUID(track) then
                        dm_strip.trn, track = GetTRNfromGUID(guid)
                      end
                    end
                  end
                else
                  ctl = strips[strip][page].controls[c]
                  if ctl and ctl.ctllock ~= true then
                    t = ctl.tracknum or strips[strip].track.tracknum
                  end
                end
                local vv = GetParamValue_XX(ctl.ctlcat, t, ctl.fxnum, ctl.param, c, strip, page, ctl)
                if vv then
                  if tostring(round(vv,4)) ~= tostring(round(faders[p+1].val,4)) then

                    faders[p+1].val = vv
                    SetFader(p+1, vv)
                  end
                else

                end
              end

            end
          end
          trackfxparam_select = ccc

        end

      elseif lbx_midilrnctl then

        local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)

        for fxnum = 0, LBX_CTL_TRACK_INF.count-1 do
          for pf = 0, lvar.LBX_FB_CNT-1 do
            p = fxnum * lvar.LBX_FB_CNT + pf
            faders[p+1].val = reaper.TrackFX_GetParam(track, fxnum, pf)

            if faders[p+1].val and tostring(round(faders[p+1].val,5)) ~= tostring(round(faders[p+1].oval,5)) then
              lbx_midilrnval = p+1
              faders[p+1].oval = faders[p+1].val
              lupd.update_surface = true

            end
          end
        end

      end

    end

  end

  function AssignFader(f, ftab)

    if faders[f] then
      DeleteFader(f)
    end
    if ftab.targettype == 0 then
      if xxy and xxy[ftab.strip] and xxy[ftab.strip][ftab.page] and xxy[ftab.strip][ftab.page][ftab.sstype] then
        if ftab.xy == 0 then
          DeleteFader(xxy[ftab.strip][ftab.page][ftab.sstype].xfader)
          xxy[ftab.strip][ftab.page][ftab.sstype].xfader = f
        else
          DeleteFader(xxy[ftab.strip][ftab.page][ftab.sstype].yfader)
          xxy[ftab.strip][ftab.page][ftab.sstype].yfader = f
        end
        faders[f] = ftab
      end
    elseif ftab.targettype == 1 then
      if xxy and xxy[ftab.strip] and xxy[ftab.strip][ftab.page] and xxy[ftab.strip][ftab.page][ftab.sstype] then
        DeleteFader(xxy[ftab.strip][ftab.page][ftab.sstype].pathfader)
        xxy[ftab.strip][ftab.page][ftab.sstype].pathfader = f
        faders[f] = ftab
      end
    elseif ftab.targettype == 2 or ftab.targettype == 4 then
      if strips and strips[ftab.strip] and strips[ftab.strip][ftab.page].controls[ftab.ctl] then
        DeleteFader(strips[ftab.strip][ftab.page].controls[ftab.ctl].macrofader)
        strips[ftab.strip][ftab.page].controls[ftab.ctl].macrofader = f
        faders[f] = ftab
        if ftab.targettype == 4 then
          local ctl = strips[ftab.strip][ftab.page].controls[ftab.ctl]
          SetFader(f, ctl.val)
        end
      end
    elseif ftab.targettype == 5 then
      DeleteFader(snapshot_fader)
      snapshot_fader = f
      faders[f] = ftab
    elseif ftab.targettype == 6 then
      if strips and strips[ftab.strip] and strips[ftab.strip][ftab.page].controls[ftab.ctl] then
        DeleteFader(strips[ftab.strip][ftab.page].controls[ftab.ctl].switchfader)
        strips[ftab.strip][ftab.page].controls[ftab.ctl].switchfader = f
        faders[f] = ftab
      end
    elseif ftab.targettype == 7 then
      if strips and strips[ftab.strip] and strips[ftab.strip][ftab.page].controls[ftab.ctl] then
        DeleteFader(strips[ftab.strip][ftab.page].controls[ftab.ctl].macrofader)
        strips[ftab.strip][ftab.page].controls[ftab.ctl].macrofader = f
        faders[f] = ftab
        local ctl = strips[ftab.strip][ftab.page].controls[ftab.ctl]
        SetFader(f, ctl.val)
      end
    elseif ftab.targettype == 8 then
      if snapshots[ftab.strip] and snapshots[ftab.strip][ftab.page][ftab.sstype] then
        DeleteFader(snapshots[ftab.strip][ftab.page][ftab.sstype].morph_time_fader)
        snapshots[ftab.strip][ftab.page][ftab.sstype].morph_time_fader = f
        faders[f] = ftab
      end
    elseif ftab.targettype == 9 then
      DeleteFader(capture_fader)
      capture_fader = f
      faders[f] = ftab

    elseif ftab.targettype == 3 then
      faders[f] = ftab
    end

  end

  function DeleteFader(f)
    if f and faders[f] then
      if faders[f].targettype == 0 then
        if xxy and xxy[faders[f].strip] and xxy[faders[f].strip][faders[f].page] and xxy[faders[f].strip][faders[f].page][faders[f].sstype] then
          if faders[f].xy == 0 then
            xxy[faders[f].strip][faders[f].page][faders[f].sstype].xfader = nil
          else
            xxy[faders[f].strip][faders[f].page][faders[f].sstype].yfader = nil
          end
        end
      elseif faders[f].targettype == 1 then
        if xxy and xxy[faders[f].strip] and xxy[faders[f].strip][faders[f].page] and xxy[faders[f].strip][faders[f].page][faders[f].sstype] then
          xxy[faders[f].strip][faders[f].page][faders[f].sstype].pathfader = nil
        end
      elseif faders[f].targettype == 2 or faders[f].targettype == 4 or faders[f].targettype == 7 then
        if faders[f].dm_guid then
          if lvar.dynamicmode_guid == faders[f].dm_guid then
            if strips and strips[faders[f].strip] and strips[faders[f].strip][faders[f].page].controls[faders[f].ctl] then
              strips[faders[f].strip][faders[f].page].controls[faders[f].ctl].macrofader = nil
            end
          elseif lvar.stripstore and lvar.stripstore[faders[f].dm_guid] and lvar.stripstore[faders[f].dm_guid].controls[faders[f].ctl] then
            lvar.stripstore[faders[f].dm_guid].controls[faders[f].ctl].macrofader = nil
          end
        else
          if strips and strips[faders[f].strip] and strips[faders[f].strip][faders[f].page].controls[faders[f].ctl] then
            strips[faders[f].strip][faders[f].page].controls[faders[f].ctl].macrofader = nil
          end
        end
      elseif faders[f].targettype == 5 then
        snapshot_fader = nil
      elseif faders[f].targettype == 6 then
        if strips and strips[faders[f].strip] and strips[faders[f].strip][faders[f].page].controls[faders[f].ctl] then
          strips[faders[f].strip][faders[f].page].controls[faders[f].ctl].switchfader = nil
        end
      elseif faders[f].targettype == 8 then
        if snapshots[faders[f].strip] and snapshots[faders[f].strip][faders[f].page][faders[f].sstype] then
          snapshots[faders[f].strip][faders[f].page][faders[f].sstype].morph_time_fader = nil
        end
      end
      faders[f] = {}
      lupd.update_gfx = true
    end
  end

  ------------------------------------------------------------

  function SetLiveMode(lm, ots, opg, omixx, omixy)
    local olm = lvar.livemode
    lvar.livemode = lm
    if lvar.livemode >= 1 then
      GUI_DrawCtlBitmap_Mix()
    end
    lvar.glivemode = lvar.livemode
    if obj then
      SetSurfaceSize2(obj)
    end
    lupd.update_bg = true
    lupd.update_gfx = true
    
    if lvar.livemode == 2 then
      settings_localfaders = true
      
      --DM_RestoreStripData()
    elseif olm == 2 then
      --DM_StoreStripData(ots, opg, omixx, omixy)
    end
  end

  function showctlbrowser(v)
    if mode == 1 and submode == 0 and lvar.ctlbrowser_docked then
      show_ctlbrowser = true
    else
      show_ctlbrowser = v
    end
  end

  function setmode(m)
    --1=live,2=fx,3=tr,4=gfx,5=strip

    if navigate then

      UnhideCtls()
      
      backalpha2 = 0
      ctl_select = nil
      gfx2_select = nil
      gfx3_select = nil
      gfx4_select = nil
      gfx4_selectidx = nil
      lvar.selctl = nil

      show_paramlearn = false
      CloseActChooser()
      show_gaugeedit = false

      if m == 1 or lvar.livemode ~= 2 then
        if lvar.analyzer.active then
          DM_ShowAnalyzer(false)
          lupd.update_trbtns = true
          lvar.saveanalactive = true
        end
      end

      if m == 1 then
        if mode == 1 then
          --SaveEditedData()
        end
        mode = 0
        --[[if lvar.dm_editmode_data then
          local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
          ChangeTrack2(ret_trn, lvar.dm_editmode_data.ret_page, true)
        end]]
        reaper.MarkProjectDirty(0)
        PopulateUsedTracksTable()
      else
        g_edstrips = {}
        trackedit_select = track_select
        mode = 1
        PopulateTrackFX()

        if m == 2 then
          --backalpha2 = 0.5
          submode = 0
          fxmode = 0
        elseif m == 3 then
          --backalpha2 = 0.5
          submode = 0
          fxmode = 1
        elseif m == 4 then
          submode = 1
        elseif m == 5 then
          submode = 2
        end
      end

      if (m == 2 or m == 3) and lvar.ctlbrowser_docked then
        show_ctlbrowser = true
      else
        show_ctlbrowser = false
      end

      lvar.o10_x = nil
      lvar.o10_y = nil
      obj = GetObjects(true)

      local slsz = 100
      local slots_x = math.floor((ctl_browser_size.w - 20) / slsz)
      local slots_y = math.max(math.min(math.floor((ctl_browser_size.h/2 - (butt_h+2)*2 -20) / slsz),8),1)
      if not lvar.cbi_loaded or ((m == 2 or m == 3) and lvar.ctlbrowser_docked and (slots_x ~= ctl_browser_size.slots_x or slots_y ~= ctl_browser_size.slots_y)) then
        PopulateCtlBrowser_Cbi()
        GUI_DrawCtlBrowserCtls(obj, gui)
        cbi_select = knob_select
        SetCbiSelect()
        --lupd.update_surface = true
      end

      SetCtlBitmapRedraw()
      lupd.update_bg = true
      lupd.update_gfx = true
      RedrawGUIBitmap()
    end

  end

  function SetSurfaceSize2(obj)

    --if hide_topbar then
    --  topbarheight = 0
    --else
    --  topbarheight = butt_h
    --end
    local y10off = 0

    if settings_showbars then
      obj.sections[10] = {x = plist_w+2 + sb_size + 2,
                          y = topbarheight + sb_size + 2,
                          w = gfx1.main_w-(plist_w+2+(sb_size+2)*2),
                          h = gfx1.main_h-(topbarheight+(sb_size+2)*2)}
      if settings_ssdock == true and show_snapshots and mode == 0 then
        obj.sections[10].w = obj.sections[10].w - math.floor(gui.winsz.snaps*pnl_scale)
      end
      if settings_sbdock == true and show_stripbrowser == true and mode == 0 then
        if lvar.stripbrowser.dockpos == 1 then
          obj.sections[10].y = obj.sections[10].y + math.floor(sbwin.h*pnl_scale)
          obj.sections[10].h = math.floor(obj.sections[10].h - math.floor(sbwin.h*pnl_scale))
        else
          obj.sections[10].w = obj.sections[10].w - math.floor(sbwin.w*pnl_scale)
        end
      end
      if settings_moddock == true and show_lfoedit == true and mode == 0 then
        obj.sections[10].h = math.floor(obj.sections[10].h - (modwinsz.h or 300)*pnl_scale)
      end
      obj.sections[10].h = obj.sections[10].h + 2
      obj.sections[10000] = {x = obj.sections[10].x, y = obj.sections[10].y, w = obj.sections[10].w, h = obj.sections[10].h}
      if show_striplayout == false then
        if lockx and lvar.livemode == 0 then
          obj.sections[10].x = math.max(obj.sections[10].x, obj.sections[10].x+(obj.sections[10].w/2-lockw/2))
          obj.sections[10].w = math.min(lockw,gfx1.main_w-(plist_w+2+(sb_size+4)*2))
        end
        if locky and lvar.livemode == 0 then
          obj.sections[10].y = math.max(obj.sections[10].y, obj.sections[10].y+(obj.sections[10].h/2-lockh/2))
          obj.sections[10].h = math.floor(math.min(lockh,gfx1.main_h-(topbarheight+2+(sb_size+2)*2)))
        end
      end
    else
      local ypad = 2
      if topbarheight == 0 then
        ypad = 0
      end
      obj.sections[10] = {x = plist_w,
                          y = topbarheight+ypad,
                          w = gfx1.main_w-(plist_w+2)+2,
                          h = gfx1.main_h-(topbarheight+1)}
      if settings_ssdock == true and show_snapshots and mode == 0 then
        obj.sections[10].w = obj.sections[10].w - math.floor(gui.winsz.snaps*pnl_scale)
      end
      if settings_sbdock == true and show_stripbrowser == true and mode == 0 and not macro_lrn_mode and not snaplrn_mode then
        if lvar.stripbrowser.dockpos == 1 then
          local sbwh
          if obj.sections[1350] then
            sbwh = obj.sections[1350].h
            y10off = sbwh + topbarheight + ypad
          else
            sbwh = math.floor(sbwin.h*pnl_scale)
          end
          obj.sections[10].y = obj.sections[10].y + sbwh
          obj.sections[10].h = math.floor(obj.sections[10].h - sbwh)
        else
          if obj.sections[1350] then
            sbww = obj.sections[1350].w
          else
            sbww = math.floor(sbwin.w*pnl_scale)
          end
          obj.sections[10].w = obj.sections[10].w - sbww
        end
      end
      if settings_moddock == true and show_lfoedit == true and mode == 0 and not macro_lrn_mode and not snaplrn_mode then
        local msz
        if modwinsz and modwinsz.h then
          msz = modwinsz.h
        else
          msz = 300
          modwinsz = nil
        end
        obj.sections[10].h = math.floor(obj.sections[10].h - msz)
      end
      obj.sections[10].h = obj.sections[10].h + 2
      if mode == 1 and (submode == 0 or submode == 1) then
        obj.sections[10].h = obj.sections[10].h - math.max(tb_butt_h,32)
        if show_ctlbrowser then
          if lvar.ctlbrowser_docked then
            local slsz = 100
            obj.sections[10].w = obj.sections[10].w - lvar.ctlbrowser_docked_w
          end
        end
      end
      if mode == 0 and lvar.livemode == 2 then
        if lvar.trbtns_show and not macro_lrn_mode and not snaplrn_mode then
          obj.sections[10].h = obj.sections[10].h - (lvar.trbtns_size+10)
          if lvar.trmix_show then
            obj.sections[10].h = obj.sections[10].h - lvar.trmix_h
          end
        end
      end
      --DBG(obj.sections[10].w)
      obj.sections[10000] = {x = obj.sections[10].x, y = obj.sections[10].y, w = obj.sections[10].w, h = obj.sections[10].h}
      if show_striplayout == false then
        if lockx and lvar.livemode == 0 then
          obj.sections[10].x = math.max(obj.sections[10].x, obj.sections[10].x+(obj.sections[10].w/2-lockw/2))
          obj.sections[10].w = math.min(lockw,gfx1.main_w-(plist_w+2))
        end
        if locky and lvar.livemode == 0 then
          obj.sections[10].y = math.max(obj.sections[10].y, obj.sections[10].y+(obj.sections[10].h/2-lockh/2))
          obj.sections[10].h = math.floor(math.min(lockh,gfx1.main_h-(topbarheight+2)))
        end
      end
      if lvar.o10_y and obj.sections[10].y ~= lvar.o10_y then
        surface_offset.mixy = (surface_offset.mixy or 0) + (obj.sections[10].y - lvar.o10_y)
        lvar.o10_y = obj.sections[10].y
      end
    end

    obj.sections[10].y = math.max(obj.sections[10].y,y10off)

    obj.sections[10].w = math.max(obj.sections[10].w,0)
    obj.sections[10].h = math.max(obj.sections[10].h,0)

    surface_size.exceed = false
    if obj.sections[10].w > surface_size.w then
      obj.sections[10].w = surface_size.w
      surface_size.exceed = true
    end
    if obj.sections[10].h > surface_size.h then
      obj.sections[10].h = surface_size.h
      surface_size.exceed = true
    end

    if lvar.livemode >= 1 then
      SetCtlBitmapRedraw()
    end
    if not lvar.mixerscroll_time then
      RedrawGUIBitmap()
    end
    
  end

  function SetDefKP()

    lvar.keypress = {}
    lvar.keypress['setmode_1'] = 108
    lvar.keypress['setmode_2'] = 102
    lvar.keypress['setmode_3'] = 116
    lvar.keypress['setmode_4'] = 103
    lvar.keypress['setmode_5'] = 115
    lvar.keypress['topmenu'] = 47
    lvar.keypress['togglesidebar'] = 91
    lvar.keypress['toggletopbar'] = 93
    lvar.keypress['editfx_copy'] = 3
    lvar.keypress['editfx_paste'] = 22
    lvar.keypress['editfx_pastespecial'] = 342
    lvar.keypress['editfx_pastespecialmenu'] = 278
    lvar.keypress['nexttrack'] = 46
    lvar.keypress['prevtrack'] = 44
    lvar.keypress['dock'] = 4
    lvar.keypress['locksurface'] = 12
    lvar.keypress['nextpage'] = 61
    lvar.keypress['prevpage'] = 45
    lvar.keypress['saveproject'] = 19
    lvar.keypress['show_snapshots'] = 83
    lvar.keypress['show_settings'] = 63
    lvar.keypress['bg_trans_dec'] = 53
    lvar.keypress['bg_trans_inc'] = 54
    lvar.keypress['bg_trans_reset'] = 55
    lvar.keypress['show_trackfxorder'] = 49
    lvar.keypress['rb_menu'] = 105
    lvar.keypress['show_ctlbitmap'] = 13
    lvar.keypress['show_striplayout'] = 9
    lvar.keypress['show_trbtns'] = 113
    lvar.keypress['show_trmix'] = 109
    lvar.keypress['show_gallery'] = 92
    lvar.keypress['mixmode_orient'] = 124
    lvar.keypress['gallery_swipeprev'] = 1818584692
    lvar.keypress['gallery_swipenext'] = 1919379572
    lvar.keypress['show_modedit'] = 50
    lvar.keypress['show_morphpopup'] = 51
    lvar.keypress['show_pinmatrix'] = 52
    lvar.keypress['editfx_deleteselectedctls'] = 6579564
    lvar.keypress['show_stripbrowser'] = 48
    lvar.keypress['show_ctlmidiout'] = 77
    lvar.keypress['select_all'] = 1
    lvar.keypress['undo_redo'] = 26
    lvar.keypress['mixmode_down'] = 1685026670
    lvar.keypress['mixmode_up'] = 30064

    lvar.keypress['popout_toggleswitchers'] = -1

    lvar.keypress['surface_zoom_in'] = 43
    lvar.keypress['surface_zoom_out'] = 95

    lvar.keypress['insert_special'] = 329
    lvar.keypress['insert_favstrip_1'] = 33
    lvar.keypress['insert_favstrip_2'] = 34
    lvar.keypress['insert_favstrip_3'] = 163
    lvar.keypress['insert_favstrip_4'] = 36
    lvar.keypress['insert_favstrip_5'] = 37
    lvar.keypress['insert_favstrip_6'] = 94
    lvar.keypress['insert_favstrip_7'] = 38
    lvar.keypress['insert_favstrip_8'] = 42
    lvar.keypress['insert_favstrip_9'] = 40
    lvar.keypress['insert_favstrip_10'] = 41

    lvar.keypress['refresh_dynamicpage'] = 26165
    lvar.keypress['findfxnotfound'] = 6

    lvar.keypress['stripsearch'] = 70

    lvar.keypress['opensk2assign'] = 97
    lvar.keypress['enablesk2assign'] = 65
    lvar.keypress['openhud'] = 104

    lvar.keypress['screenset1'] = 26161
    lvar.keypress['screenset2'] = 26162
    lvar.keypress['screenset3'] = 26163
    lvar.keypress['screenset4'] = 26164

    local fn = paths.resource_path..'keycommands.ini'
    if reaper.file_exists(fn) then
      for line in io.lines(fn) do
        local k, v = string.match(line,'%[(.-)%](.*)')
        lvar.keypress[k] = tonumber(v)
      end
    end

  end

  --[[function SaveDefKP()

    local kptxt = ''
    for k in pairs(lvar.keypress) do
      kptxt = kptxt .. '['..k..']'..lvar.keypress[k]..'\n'
    end
    local file = io.open(paths.resource_path..'keycommands.ini','wb')
    if file then
      file:write(kptxt)
    end
    file:close()

  end]]

  function StripSearch()
  
    lvar.search_files = nil
    OpenEB(7000, 'Strip browser search:', lvar.stripbrowser.searchstr or '', StripSearch2, SearchCancel)
  
  end

  function SearchCancel()
  
    lvar.stripbrowser.search = nil
    lvar.reloadsbimages = true
    lupd.update_stripbrowser = true
    
  end
  
  function StripSearch2(searchstr, instant)

    lvar.stripbrowser.searchstr = searchstr
    
    if searchstr == '' then
      lvar.stripbrowser.search = nil
      lvar.reloadsbimages = true
      lupd.update_stripbrowser = true
      return    
    end
    
    if lvar.search_files == nil then
      local search_files = {}
      local ii = 1
      for folidx = 0, #strip_folders do
        if strip_folders[folidx] then
          local i = 0
          local sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[folidx].fn,i)
          while sf ~= nil do
            if string.match(string.lower(sf),'strip$') then
            --if string.match(string.lower(sf),'(.*'..string.lower(searchstr)..'.*)%.strip') then
              search_files[ii] = {fn = strip_folders[folidx].fn ..'/'.. sf,
                                  sfn = sf}
              ii = ii + 1
            end
            i=i+1
            sf = reaper.EnumerateFiles(paths.strips_path..'/'..strip_folders[folidx].fn,i)
          end
        end
      end
      
      local search_files2 = {}
      search_files = table_slowsort_gen2(search_files, 'sfn', 1, true)
      if search_files then
        for i = 1, #search_files do
          search_files2[i] = search_files[i].fn
        end
      end
      lvar.search_files = search_files2
    end
    
    local search_files = lvar.search_files
    local search_files2 = {}
    local ii = 1
    for i = 1, #search_files do
      if string.match(string.lower(search_files[i]),'(.*'..string.lower(searchstr)..'.*)%.strip') then
        search_files2[ii] = search_files[i]
        ii = ii + 1
      end
    end
    
    strip_search = search_files2
    lvar.stripbrowser.search = true

    if not instant then
      lvar.delayfunction.stripbrowser_reload_delay = reaper.time_precise() + 0.2
    else
      lvar.reloadsbimages = true
      lupd.update_stripbrowser = true
    end
  end
  
  function Mode0_SwipeR(instant)
    if surface_scroll then return end
    
    if lvar.stripdim and lvar.stripdim.dim then
      local nr = (math.floor((surface_offset.x + obj.sections[10].w) / lvar.screensize.x) + 1)*lvar.screensize.x
      local nx = math.min(nr, surface_offset.x + obj.sections[10].w, surface_size.w-obj.sections[10].w, nr-obj.sections[10].w)
      if instant then
        surface_offset.x = nx
        lupd.update_surface = true
      else
        surface_scroll = {srcx = surface_offset.x, dstx = nx, srcy = surface_offset.y, dsty = surface_offset.y, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
      if strips and tracks[track_select] and strips[tracks[track_select].strip] then
        strips[tracks[track_select].strip][page].surface_x = nx
        strips[tracks[track_select].strip][page].surface_y = surface_offset.y
      end
    end

    --[[if lvar.stripdim and lvar.stripdim.dim then
      local nx
      if surface_offset.x + obj.sections[10].w < lvar.stripdim.dim.r then
        if surface_offset.x + obj.sections[10].w + obj.sections[10].w >= lvar.stripdim.dim.r then
          nx = lvar.stripdim.dim.r - obj.sections[10].w
        else
          nx = math.min(surface_size.w-obj.sections[10].w, math.floor((surface_offset.x + obj.sections[10].w)/obj.sections[10].w)*obj.sections[10].w)
        end
      else
        nx = math.min(surface_size.w-obj.sections[10].w, math.floor((surface_offset.x + obj.sections[10].w)/obj.sections[10].w)*obj.sections[10].w)
      end
      if instant then
        surface_offset.x = nx
        lupd.update_surface = true
      else
        surface_scroll = {srcx = surface_offset.x, dstx = nx, srcy = surface_offset.y, dsty = surface_offset.y, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
    end]]
  end

  function Mode0_SwipeL()
    if surface_scroll then return end

    if lvar.stripdim and lvar.stripdim.dim then
      local nl = (math.floor((surface_offset.x - obj.sections[10].w) / lvar.screensize.x)+1)*lvar.screensize.x
      if nl >= surface_offset.x then
        nl = nl - lvar.screensize.x
      end
      local nx = surface_offset.x - obj.sections[10].w
      if nx < nl then
        nx = nl
      end
      if nx >= surface_offset.x then
        nx = nx - obj.sections[10].w
      end
      nx = math.max(nx, 0)
      if instant then
        surface_offset.x = nx
        lupd.update_surface = true
      else
        surface_scroll = {srcx = surface_offset.x, dstx = nx, srcy = surface_offset.y, dsty = surface_offset.y, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
      if strips and tracks[track_select] and strips[tracks[track_select].strip] then
        strips[tracks[track_select].strip][page].surface_x = nx
        strips[tracks[track_select].strip][page].surface_y = surface_offset.y
      end
    end

    --[[if lvar.stripdim and lvar.stripdim.dim then
      local nx
      if surface_offset.x > lvar.stripdim.dim.l then
        if surface_offset.x - obj.sections[10].w <= lvar.stripdim.dim.l then
          --surface_offset.x = lvar.stripdim.dim.l
          nx = math.max(0, math.ceil((surface_offset.x - obj.sections[10].w)/obj.sections[10].w)*obj.sections[10].w)
        else
          nx = math.max(0, math.ceil((surface_offset.x - obj.sections[10].w)/obj.sections[10].w)*obj.sections[10].w)
        end
      else
        nx = math.max(0, math.ceil((surface_offset.x - obj.sections[10].w)/obj.sections[10].w)*obj.sections[10].w)
      end
      if instant then
        surface_offset.x = nx
        lupd.update_surface = true
      else
        surface_scroll = {srcx = surface_offset.x, dstx = nx, srcy = surface_offset.y, dsty = surface_offset.y, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
    end]]
  end

  function Mode0_SwipeD(instant)
    if surface_scroll then return end

    if lvar.stripdim and lvar.stripdim.dim then
      local nb = (math.floor((surface_offset.y + obj.sections[10].h) / lvar.screensize.y) + 1)*lvar.screensize.y
      local ny = math.min(nb, surface_offset.y + obj.sections[10].h, surface_size.h-obj.sections[10].h, nb-obj.sections[10].h)
      if instant then
        surface_offset.y = ny
        lupd.update_surface = true
      else
        surface_scroll = {srcy = surface_offset.y, dsty = ny, srcx = surface_offset.x, dstx = surface_offset.x, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
      if strips and tracks[track_select] and strips[tracks[track_select].strip] then
        strips[tracks[track_select].strip][page].surface_x = surface_offset.x
        strips[tracks[track_select].strip][page].surface_y = ny
      end
    end
    
    --[[if lvar.stripdim and lvar.stripdim.dim then
      local ny
      if surface_offset.y + obj.sections[10].h < lvar.stripdim.dim.b then
        if surface_offset.y + obj.sections[10].h + obj.sections[10].h >= lvar.stripdim.dim.b then
          ny = lvar.stripdim.dim.b - obj.sections[10].h
        else
          ny = math.min(surface_size.h-obj.sections[10].h, math.floor((surface_offset.y + obj.sections[10].h)/obj.sections[10].h)*obj.sections[10].h)
        end
      else
        ny = math.min(surface_size.h-obj.sections[10].h, math.floor((surface_offset.y + obj.sections[10].h)/obj.sections[10].h)*obj.sections[10].h)
      end
      if instant then
        surface_offset.y = ny
        lupd.update_surface = true
      else
        surface_scroll = {srcy = surface_offset.y, dsty = ny, srcx = surface_offset.x, dstx = surface_offset.x, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
    end]]
  end

  function Mode0_SwipeU()
    if surface_scroll then return end

    if lvar.stripdim and lvar.stripdim.dim then
      local nt = (math.floor((surface_offset.y - obj.sections[10].h) / lvar.screensize.y)+1)*lvar.screensize.y
      if nt >= surface_offset.y then
        nt = nt - lvar.screensize.y
      end
      local ny = surface_offset.y - obj.sections[10].h
      if ny < nt then
        ny = nt
      end
      if ny >= surface_offset.y then
        ny = ny - obj.sections[10].h
      end
      ny = math.max(ny, 0)
      
      --[[local nt = (math.floor((surface_offset.y - obj.sections[10].h) / lvar.screensize.y))*lvar.screensize.y
      local ny = math.max(nt, surface_offset.y - obj.sections[10].h, 0, nt+(lvar.screensize.y))
      if ny == surface_offset.y then
        ny = math.max(nt, surface_offset.y - obj.sections[10].h, 0)
      end]]
      if instant then
        surface_offset.y = ny
        lupd.update_surface = true
      else
        surface_scroll = {srcy = surface_offset.y, dsty = ny, srcx = surface_offset.x, dstx = surface_offset.x, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
      if strips and tracks[track_select] and strips[tracks[track_select].strip] then
        strips[tracks[track_select].strip][page].surface_x = surface_offset.x
        strips[tracks[track_select].strip][page].surface_y = ny
      end
    end
    
    --[[if lvar.stripdim and lvar.stripdim.dim then
      local ny
      if surface_offset.y > lvar.stripdim.dim.t then
        if surface_offset.y - obj.sections[10].h <= lvar.stripdim.dim.t then
          --surface_offset.x = lvar.stripdim.dim.l
          ny = math.max(0, math.ceil((surface_offset.y - obj.sections[10].h)/obj.sections[10].h)*obj.sections[10].h)
        else
          ny = math.max(0, math.ceil((surface_offset.y - obj.sections[10].h)/obj.sections[10].h)*obj.sections[10].h)
        end
      else
        ny = math.max(0, math.ceil((surface_offset.y - obj.sections[10].h)/obj.sections[10].h)*obj.sections[10].h)
      end
      if instant then
        surface_offset.y = ny
        lupd.update_surface = true
      else
        surface_scroll = {srcy = surface_offset.y, dsty = ny, srcx = surface_offset.x, dstx = surface_offset.x, st = reaper.time_precise(), et = reaper.time_precise() + lvar.mode0swipetime}
      end
    end]]
  end
  
  function keypress(char)

    --DBG(tostring(mouse.ctrl)..'  '..tostring(mouse.shift)..'  '..tostring(mouse.alt)..'  '..char)

    if settings_disablekeysonlockedsurface and settings_locksurface then return end

    --if not mouse.shift then
      if char == lvar.keypress['stripsearch'] then
        StripSearch()
      elseif char == lvar.keypress['enablesk2assign'] then
        lvar.sk2overlay_active = 1-lvar.sk2overlay_active
        xPnl.SK2.updategui = true
        SendSK2Data_Enable(lvar.sk2overlay_active)
      elseif char == lvar.keypress['opensk2assign'] then
        if xPnl.SK2.visible ~= true then
          ShowXPnl('SK2')
        else
          HideXPnl('SK2')
        end
      elseif char == lvar.keypress['openhud'] then
        if xPnl.HUD.visible ~= true then
          ShowXPnl('HUD')
        else
          HideXPnl('HUD')
        end
      elseif char == lvar.keypress['findfxnotfound'] then
        Find_FXNotFound()      
      elseif char == lvar.keypress['setmode_2'] then
        if lvar.livemode ~= 2 or mode == 1 then
          setmode(2)
        elseif lvar.livemode == 2 then
          DM_OpenEditMode()
        end
      elseif char == lvar.keypress['setmode_3'] then
        if lvar.livemode ~= 2 or mode == 1 then
          setmode(3)
        end
      elseif char == lvar.keypress['setmode_4'] then
        if lvar.livemode ~= 2 or mode == 1 then
          setmode(4)
        end
      elseif char == lvar.keypress['setmode_5'] then
        if lvar.livemode ~= 2 or mode == 1 then
          setmode(5)
        end
      elseif char == lvar.keypress['setmode_1'] then
        setmode(1)

      elseif char == lvar.keypress['topmenu'] then
        TopMenu()
      elseif char == lvar.keypress['togglesidebar'] then
        ToggleSidebar()
      elseif char == lvar.keypress['toggletopbar'] then

        ToggleTopbar()

      elseif char == lvar.keypress['refresh_dynamicpage'] then

        DM_RefreshPage()

      elseif char == lvar.keypress['select_all'] then
        
        SelectAll()

      elseif char == lvar.keypress['undo_redo'] then

        if mode == 0 then
          if not mouse.shift then
            reaper.Main_OnCommand(40029,-1)
          else
            reaper.Main_OnCommand(40030,-1)
          end
        elseif mode == 1 and (submode == 0 or submode == 1 or submode == 2) then

          if mouse.shift then
            if undo.max > 0 and undo[undo_pos+1] then
              undo_pos = Undo_Redo(undo_pos+1)
              lupd.update_cbox = true
            end
          else
            if undo.max > 0 and undo_pos > 0 then
              undo_pos = Undo_Recall(undo_pos)
              lupd.update_cbox = true
            end
          end

        end

      elseif char == lvar.keypress['editfx_copy'] then
        if mode == 1 and submode == 0 then
          Copy_Selected()
        elseif mode == 1 and submode == 1 then
          GFX_Copy()
        end
      elseif char == lvar.keypress['editfx_pastespecial'] then
        PasteSpecial(lvar.pastespecial_sel)

      elseif char == lvar.keypress['editfx_pastespecialmenu'] then
        PasteSpecial_Menu(mouse.mx, mouse.my)
        
      elseif char == lvar.keypress['editfx_paste'] then
        if mode == 1 and submode == 0 then
          local keep_coords
          if mouse.shift then
            keep_coords = true
          end
          Paste_Selected(keep_coords)
          SetCtlBitmapRedraw()
          ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
          lupd.update_gfx = true
        elseif mode == 1 and submode == 1 then
          local keep_coords
          if mouse.shift then
            keep_coords = true
          end
          GFX_Paste(keep_coords)
        end
      elseif char == lvar.keypress['nexttrack'] then
        if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
          local t = track_select + 1
          if gpage == true then
            if gpage_otrackselect then
              t = (gpage_otrackselect) + 1
            end
          end
          if t > #tracks then t = -1 end
          if t == LBX_GTRACK then
            t = t + 1
            if t > #tracks then t = -1 end
          end
  
          if hideunusedtracks == true and tracksused_idx2.count > 0 then
            while tracksused_idx2[t] == nil do
              t = t + 1
              if t > #tracks then t = -1 end
            end
          end
  
          if t == LBX_GTRACK then
            SetGlobalPage()
          else
            ChangeTrack2(t)
          end
        elseif lvar.livemode == 2 and mouse.context == nil then
          local track = reaper.GetSelectedTrack2(0,0,true)
          local trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')
          if trn ~= -1 then
            trn = trn - 1
          end
          local t
          local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
          for i = 1, #dm_trackbtns do
            if trn == dm_trackbtns[i].trn then
              t = i
              break
            end
          end
          t = (t or 0) + 1
          
          if not dm_trackbtns[t] then
            t = 1
          end
          if dm_trackbtns[t] then
            local dtrn = dm_trackbtns[t].trn
            local track = GetTrack(dtrn)
            if track then
              reaper.SetOnlyTrackSelected(track)
              DM_AddStrips()
              
              local cnt = math.min(lvar.trov_maxrows, lvar.dm_maxvistracks+1)-1
              if t < lvar.trbtns_offs+1 or t > lvar.trbtns_offs + cnt then
                
                lvar.trbtns_offs = math.max(F_limit(t-cnt,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-cnt),0)
              end
            end
          end
        end

      elseif char == lvar.keypress['prevtrack'] then
        if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
          local t = track_select - 1
          if gpage == true then
            if gpage_otrackselect then
              t = (gpage_otrackselect) - 1
            end
          end
          if t < -1 then t = #tracks end
          if t == LBX_GTRACK then
            t = t - 1
            if t < -1 then t = #tracks end
          end
  
          if hideunusedtracks == true and tracksused_idx2.count > 0 then
            while tracksused_idx2[t] == nil do
              t = t - 1
              if t < -1 then t = #tracks end
            end
          end
  
          if t == LBX_GTRACK then
            SetGlobalPage()
          else
            ChangeTrack2(t)
          end
        elseif lvar.livemode == 2 and mouse.context == nil then
          local track = reaper.GetSelectedTrack2(0,0,true)
          local trn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')
          if trn ~= -1 then
            trn = trn - 1
          end
          local t
          local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
          for i = 1, #dm_trackbtns do
            if trn == dm_trackbtns[i].trn then
              t = i
              break
            end
          end
          t = (t or 0) - 1
          
          if not dm_trackbtns[t] then
            t = #dm_trackbtns
          end
          if dm_trackbtns[t] then
            local dtrn = dm_trackbtns[t].trn
            local track = GetTrack(dtrn)
            if track then
              reaper.SetOnlyTrackSelected(track)
              DM_AddStrips()

              local cnt = math.min(lvar.trov_maxrows, lvar.dm_maxvistracks+1)-1
              if t < lvar.trbtns_offs+1 or t > lvar.trbtns_offs + cnt then
                lvar.trbtns_offs = math.max(F_limit(t-1,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-cnt),0)
              end
            end
          end
        end
        
      elseif char == lvar.keypress['dock'] then
        local d = gfx.dock(-1)
        if d%256 == 0 then
          if dockstate and dockstate%256 ~= 0 then
            gfx.dock(dockstate)
          else
            gfx.dock(d+1)
          end
        else
          dockstate = d
          gfx.dock(256)
        end
      elseif char == lvar.keypress['locksurface'] then
        settings_locksurface = not settings_locksurface
      elseif char == lvar.keypress['nextpage'] then
        --if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
          if navigate and gpage == true then SetPage(1)
          elseif navigate then SetPage(math.min(page+1,4)) end
        --end
      elseif char == lvar.keypress['prevpage'] then
        --if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
          if navigate then SetPage(math.max(page-1,0)) end
        --end
      elseif char == lvar.keypress['saveproject'] then
        SaveProj(nil, true)
        lastprojdirty = 0
      --elseif char == 19 then
        --ToggleSidebar()
      elseif char == lvar.keypress['show_snapshots'] then
        SetShowSS(not show_snapshots)
      elseif char == lvar.keypress['show_settings'] then
        show_settings = not show_settings
        lupd.update_surface = true
        RedrawGUIBitmap()
      elseif char == lvar.keypress['bg_trans_dec'] then
        if lvar.livemode > 0 then
          lvar.bgbright = math.max(lvar.bgbright-4,-100)
          LoadBGImage(file_bgimage)
          lupd.update_surface = true
          lupd.update_trbtns = true
          lupd.update_trmix = true
        else
          backalpha = math.max(backalpha - 0.05,0)
          lupd.update_bg = true
          lupd.update_gfx = true
        end
      elseif char == lvar.keypress['bg_trans_inc'] then
        if lvar.livemode > 0 then
          lvar.bgbright = math.min(lvar.bgbright+4,200)
          LoadBGImage(file_bgimage)
          lupd.update_surface = true
          lupd.update_trbtns = true
          lupd.update_trmix = true
        else
          backalpha = math.min(backalpha +0.05,2)
          lupd.update_bg = true
          lupd.update_gfx = true
        end
      elseif char == lvar.keypress['bg_trans_reset'] then
        lvar.bgbright = 0
        LoadBGImage(file_bgimage)
        lupd.update_surface = true
        backalpha = 1
        lupd.update_bg = true
        lupd.update_gfx = true
      elseif char == lvar.keypress['show_trackfxorder'] then
        --if lvar.livemode ~= 2 then
          tfxo_listpos = 0
          tfxorder = TrackFXOrder_Read()
          tfxreorder = TrackFXOrder_Read()
          if tfxorder then 
            show_trackfxorder = not show_trackfxorder
            --lupd.update_gfx = true
            lvar.trackfxorder_repos = true
            lupd.update_trackfxorder = true
            lupd.update_trbtns = true
            RedrawGUIBitmap()
          end
        --end
        char = 0
      elseif char == lvar.keypress['rb_menu'] then
        RBMenu(2,nil,nil)
      elseif char == lvar.keypress['show_ctlbitmap'] then
        show_bitmap = not show_bitmap
        lupd.update_surface = true
      elseif char == lvar.keypress['show_striplayout'] then
        if lvar.livemode == 0 then
          if mode == 0 or (mode == 1 and submode == 2) then
            show_striplayout = not show_striplayout
            SetSurfaceSize2(obj)
            if show_striplayout == true then

              striplayout_selstripid = nil
              striplayout_selstrip = nil

              stlay_data = AutoSnap_GetStripLocs(true)
              striplayout_data = StripLayout_GetData()
              if stripgallery_view == 1 then
                StripLayout_DrawImageGallery(stlay_data)
              else
                StripLayout_DrawImage(striplayout_data)
              end

              if show_striplayout == true then
                striplayout_mt = reaper.time_precise()+striplayout_mtime
              end
            else
              if striplayout_selstripid and stlay_data then
                local sel = striplayout_selstripid
                for i = 1, #stlay_data.reordered do
                  if stlay_data.reordered[i].stripid == striplayout_selstrip then
                    sel = i
                    break
                  end
                end
                surface_offset.x = math.floor(F_limit(stlay_data.reordered[sel].l - (obj.sections[10].w/2) + (stlay_data.reordered[sel].w/2),0,surface_size.w-obj.sections[10].w))
                surface_offset.y = math.floor(F_limit(stlay_data.reordered[sel].t - (obj.sections[10].h/2) + (stlay_data.reordered[sel].h/2),0,surface_size.h-obj.sections[10].h))
                local xpos
                for i = 1, #stlay_data.reordered do
                  if stlay_data.reordered[i].stripid == striplayout_selstrip then
                    xpos = math.floor(stlay_data.reordered[i].runx_s - (obj.sections[10].w/2 - stlay_data.reordered[i].w/2))
                    break
                  end
                end
                if xpos then
                  stlay_data.xpos = xpos
                  strip = tracks[track_select].strip
                  strips[strip][page].xpos = xpos
                  GUI_DrawCtlBitmap2()
                end
              end

              striplayout_mt = reaper.time_precise()+striplayout_mtime
            end

            lupd.update_surface = true
          end
        else
          --livemode == 1

          --[[if lvar.mmov_show and lvar.trbtns_show then
            lvar.mmov_show = false
            lvar.trbtns_show = true

          elseif lvar.mmov_show then
            lvar.mmov_show = true
            lvar.trbtns_show = true

          elseif lvar.trbtns_show then
            lvar.mmov_show = false
            lvar.trbtns_show = false

          else
            lvar.mmov_show = true
            lvar.trbtns_show = false

          end]]
            lvar.mmov_show = not lvar.mmov_show

          --if plist_w > 0 then
            local mmov = 0
            if lvar.mmov_show then
              mmov = lvar.mmov_vsize
            end
            --Repos5001()
            Repos5005()
            --obj = PosTrBtns(obj)

          --lvar.mmov_show = not lvar.mmov_show
          if lvar.mmov_show == true then
            lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)
          else
            lvar.mmov_offs = 0
          end
          GUI_DrawCtlBitmap_Mix()
          lupd.update_gfx = true
        end
      elseif char == lvar.keypress['show_trmix'] then
        if lvar.livemode == 2 and lvar.trbtns_show then
          if lvar.trmix_animateshow then
            GUI_DrawMixerScroll(obj, gui, not lvar.trmix_show)
          else
            lvar.trmix_show = not lvar.trmix_show

            SetSurfaceSize2(obj)
            obj = PosTrBtns(obj)

            lupd.update_trbtns = true
            lupd.update_gfx = true
          end
        end

      elseif char == lvar.keypress['show_trbtns'] then
        if lvar.livemode == 2 then
          lvar.trbtns_show = not lvar.trbtns_show

          if not lvar.trbtns_show then
            if lvar.analyzer.active then
              DM_ShowAnalyzer(false)
              lupd.update_trbtns = true
              lvar.saveanalactive = true
            end
          end

          SetSurfaceSize2(obj)
          obj = PosTrBtns(obj)

          local mmov = 0
          if lvar.mmov_show then
            mmov = lvar.mmov_vsize
          end
          --Repos5001()
          Repos5005()

          --MixMode_Swipe_Pop(1, nil, r)

          lupd.update_trbtns = true
          lupd.update_gfx = true
        
        else
          lvar.show_slotnameoninactivesk2ctls = lvar.show_slotnameoninactivesk2ctls + 1
          if lvar.show_slotnameoninactivesk2ctls > 2 then
            lvar.show_slotnameoninactivesk2ctls = 0
          end
          --if lvar.show_slotnameoninactivesk2ctls == false then
            if tracks[track_select].strip and strips[tracks[track_select].strip] then
              local ctls = strips[tracks[track_select].strip][page].controls
              if ctls then
                for c = 1, #ctls do
                  if ctls[c].ctlcat == ctlcats.sk2ctl then
                    local i = tonumber(ctls[c].param_info.paramidx)
                    --if lvar.sk2data_assign[i] and lvar.sk2data_assign[i].active ~= 1 then
                      ctls[c].slot_name = nil
                      SetCtlDirty(c)
                    --end
                  end
                end
              end
            end
          --end
          lupd.update_ctls = true
        end

      elseif char == lvar.keypress['mixmode_orient'] then
        if lvar.livemode >= 1 then
          lvar.mixmodedir = 1 - lvar.mixmodedir
          --[[if lvar.mixmodedir == 0 then
            lvar.mmov_vsize = lvar.mmov_vsize*2
          else
            lvar.mmov_vsize = lvar.mmov_vsize/2
          end
          lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)]]

          lvar.mmov_pos = 0
          --Repos5001()
          --obj = PosTrBtns(obj)
          Repos5005()
          if lvar.stripdim and lvar.stripdim.swdata and lvar.stripdim.swdata.extid then
            local extid = lvar.stripdim.swdata.extid
            Strip_ReposSwitcher_Ext(extid, 1)
          else
            GUI_DrawCtlBitmap_Mix()
          end
          lupd.update_gfx = true
          RedrawGUIBitmap()
        end

      elseif char == lvar.keypress['show_gallery'] then
        if lvar.livemode >= 1 then
          if lvar.popout_autoarrange and lvar.showpop and (lvar.showpoponly or mouse.ctrl) then
            lvar.popout_autoarrange_hideswitchers = not lvar.popout_autoarrange_hideswitchers
            GUI_DrawCtlBitmap_Mix()
            if lvar.prsr then
              MixMode_Swipe_Pop(nil, true, lvar.prsr)
            else
              MixMode_Swipe_Pop(0, true)
            end
            GUI_DrawCtlBitmap_Mix()
          else
            ShowPop(not lvar.showpop)
          end
        else
          show_striplayout = false
          if mode == 0 then
            stripgallery_view = 0--stripgallery_view +1
            if stripgallery_view == 2 then

              stripgallery_view = 0
            end
            if stripgallery_view == 1 then
              if settings_usectlbitmap then
                local xpos = 0
                stlay_data = AutoSnap_GetStripLocs(true)
                GUI_DrawCtlBitmap2()
              else
                stripgallery_view = 0
                OpenMsgBox(1, 'You must enable \'use bitmap mask control detection\' setting to use this viewing mode.', 1)
              end
            end

            lupd.update_surface = true
          end


        end

      elseif char == lvar.keypress['mixmode_down'] then

        if lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view ~= 1 then
          Mode0_SwipeD()
        elseif lvar.livemode >= 1 and mode == 0 then
          if lvar.showpop and lvar.popout_autoarrange then
            MixMode_Swipe_Pop(0)
            
          elseif not lvar.showpoponly then
            MixMode_Swipe((lvar.centrepos or 0), (lvar.centrepos or 0)+1)
          end
        end
        
      elseif char == lvar.keypress['mixmode_up'] then

        if lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view ~= 1 then
          Mode0_SwipeU()
        elseif lvar.livemode >= 1 and mode == 0 then
          if lvar.showpop and lvar.popout_autoarrange then
            MixMode_Swipe_Pop(1)
            
          elseif not lvar.showpoponly then
            MixMode_Swipe((lvar.centrepos or 0), math.max((lvar.centrepos or 0)-1,0))
          end
        end
        
      elseif char == lvar.keypress['surface_zoom_in'] then

        if lvar.zoominfo == nil --[[or reaper.time_precise() > lvar.zoominfo.et-0.01]] then
          local zoomv = lvar.zoomv + 1

          --surface_offset.x = 0
          --surface_offset.y = 0

          if zoomv <= #lvar.zoomtab then
            lvar.zoomv = zoomv
            local rt = reaper.time_precise()
            local xoff, xcentre, yoff, ycentre, mixp, mixpt
            if lvar.zoominfo then
              xoff = lvar.zoominfo.xoff
              yoff = lvar.zoominfo.yoff
              --[[xcentre = lvar.zoominfo.xcentre
              ycentre = lvar.zoominfo.ycentre
              mixp = lvar.zoominfo.mixp
              mixpt = lvar.zoominfo.mixpt]]
              xcentre = (obj.sections[10].w/2)/lvar.zoom --tab[lvar.zoomv]
              ycentre = (obj.sections[10].h/2)/lvar.zoom --/lvar.zoomtab[lvar.zoomv]
            else
              xoff = surface_offset.x
              yoff = surface_offset.y
              xcentre = (obj.sections[10].w/2)/lvar.zoom --tab[lvar.zoomv]
              ycentre = (obj.sections[10].h/2)/lvar.zoom --/lvar.zoomtab[lvar.zoomv]

            end

            if lvar.livemode >= 1 then
              if lvar.mixmodedir == 0 then
                mixp = surface_offset.mixy
                local m = 1
                if lvar.zoom < 1 then
                  m = lvar.zoom
                end
                mixpt = ycentre*m
              else
                mixp = surface_offset.mixx
                local m = 1
                if lvar.zoom < 1 then
                  m = lvar.zoom
                end
                mixpt = xcentre*m
              end
            end

            lvar.zoominfo = {src = lvar.zoom,
                             tgt = lvar.zoomtab[lvar.zoomv],
                             st = rt, et = rt+0.06, xoff = xoff, yoff = yoff, xcentre = xcentre, ycentre = ycentre, mixp = mixp, mixpt = mixpt}
            
            local strip = tracks[track_select].strip
            local pop = strips[strip][page].pop
            if pop and #pop > 0 then
              for i = 1, #pop do
                pop[i].startx = pop[i].x
                pop[i].starty = pop[i].y
              end
            end
            StripZoom()
          end

        end
        --lupd.update_surface = true
        --lupd.update_surfaceedge = true
        --if lvar.livemode == 1 then
        --  GUI_DrawCtlBitmap_Mix()
        --end

      elseif char == lvar.keypress['surface_zoom_out'] then

        if lvar.zoominfo == nil --[[or reaper.time_precise() > lvar.zoominfo.et-0.01]] then
          zoomv = lvar.zoomv - 1

          --surface_offset.x = 0
          --surface_offset.y = 0

          if zoomv >= 1 then
            lvar.zoomv = zoomv
            local rt = reaper.time_precise()
            local xoff, xcentre, yoff, ycentre
            if lvar.zoominfo then
              xoff = lvar.zoominfo.xoff
              yoff = lvar.zoominfo.yoff
              --[[xcentre = lvar.zoominfo.xcentre
              ycentre = lvar.zoominfo.ycentre
              mixp = lvar.zoominfo.mixp
              mixpt = lvar.zoominfo.mixpt]]
              xcentre = (obj.sections[10].w/2)/lvar.zoom--tab[lvar.zoomv]
              ycentre = (obj.sections[10].h/2)/lvar.zoom--tab[lvar.zoomv]

            else
              xoff = surface_offset.x
              yoff = surface_offset.y
              xcentre = (obj.sections[10].w/2)/lvar.zoom--tab[lvar.zoomv]
              ycentre = (obj.sections[10].h/2)/lvar.zoom--tab[lvar.zoomv]

            end

            if lvar.livemode >= 1 then
              if lvar.mixmodedir == 0 then
                mixp = surface_offset.mixy
                local m = 1
                if lvar.zoom <=1 then
                  m = lvar.zoom/2
                end
                mixpt = -ycentre*m
              else
                mixp = surface_offset.mixx
                local m = 1
                if lvar.zoom <=1 then
                  m = lvar.zoom/2
                end
                mixpt = -xcentre*m
              end
            end

            lvar.zoominfo = {src = lvar.zoom,
                             tgt = lvar.zoomtab[lvar.zoomv],
                             st = rt, et = rt+0.06, xoff = xoff, yoff = yoff, xcentre = xcentre, ycentre = ycentre, mixp = mixp, mixpt = mixpt}
            local strip = tracks[track_select].strip
            local pop = strips[strip][page].pop
            if pop and #pop > 0 then
              for i = 1, #pop do
                pop[i].startx = pop[i].x
                pop[i].starty = pop[i].y
              end
            end
            StripZoom()
          end
        end
        --lupd.update_surface = true
        --lupd.update_surfaceedge = true
        --if lvar.livemode == 1 then
        --  GUI_DrawCtlBitmap_Mix()
        --end

      elseif char == lvar.keypress['gallery_swipeprev'] then

        if lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view ~= 1 then
          Mode0_SwipeL()
        elseif lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view == 1 then
          GallerySwipe(0)
        elseif lvar.livemode >= 1 and mode == 0 then
          if mouse.shift and lvar.active_switcher and lvar.showpop and lvar.popout_autoarrange then
            local srcswid = lvar.active_switcher.switchid
            if srcswid and switchers[srcswid] then
              local src_extid = switchers[srcswid].extendid
              local oldpos = switchers[srcswid].extendpos
              local newpos = oldpos - 1
              Switchers_Ext_MovePos(src_extid, oldpos, newpos, true, true, nil, true)
              local swdata = lvar.stripdim.swdata
              if lvar.popout_autoarrange and swdata[srcswid] then
                local rn = swdata[srcswid].rownum
                if rn then
                  MixMode_Swipe_Pop(0,true,rn-1)
                end
              end
              if lvar.mmtouch then
                TouchFX_Switcher(srcswid)
              end
            end
          elseif not lvar.showpoponly then
            MixMode_Swipe(lvar.centrepos, math.max(lvar.centrepos-1,0))
          end
        end

      elseif char == lvar.keypress['gallery_swipenext'] then

        if lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view ~= 1 then
          Mode0_SwipeR()
        elseif lvar.livemode == 0 and mode == 0 and show_striplayout == false and stripgallery_view == 1 then
          GallerySwipe(1)
        elseif lvar.livemode >= 1 and mode == 0 then
          if mouse.shift and lvar.active_switcher and lvar.showpop and lvar.popout_autoarrange then
            local srcswid = lvar.active_switcher.switchid
            if srcswid and switchers[srcswid] then
              local src_extid = switchers[srcswid].extendid
              local oldpos = switchers[srcswid].extendpos
              local newpos = oldpos + 1
              Switchers_Ext_MovePos(src_extid, oldpos, newpos, false, true, nil, true)
              local swdata = lvar.stripdim.swdata
              if lvar.popout_autoarrange and swdata[srcswid] then
                local rn = swdata[srcswid].rownum
                if rn then
                  MixMode_Swipe_Pop(0,true,rn-1)
                end
              end
              if lvar.mmtouch then
                TouchFX_Switcher(srcswid)
              end
            end
          elseif not lvar.showpoponly then
            MixMode_Swipe(lvar.centrepos, lvar.centrepos+1)
          end
        end

      elseif char == lvar.keypress['show_modedit'] then
        SetShowLFO(not show_lfoedit)
      elseif char == lvar.keypress['show_morphpopup'] then
        settings_showmorphpop = not settings_showmorphpop
        lupd.update_gfx = true
      elseif char == lvar.keypress['show_pinmatrix'] then
        show_pinmatrix = not show_pinmatrix
        local w, h = PinMatrix_CalcDim()
        local x = math.max(obj.sections[1200].w/2 - w/2,40)
        local y = math.max(obj.sections[1200].h/2 - h/2,20)

        if settings_lockpinmatrix == false then
          pinmatrix_scrollpos = {x = x, y = y}
        else
          pinmatrix_scrollpos = {x = 30, y = 10}
        end
        lupd.update_surface = true
        RedrawGUIBitmap()
        
      --[[elseif char == 30064 then
        if mode == 0 then
          --tlist_offset = F_limit(tlist_offset - 1, 0, #tracks+1)
          --lupd.update_sidebar = true
        end
      elseif char == 1685026670 then
        if mode == 0 then
          --tlist_offset = F_limit(tlist_offset + 1, 0, #tracks+1)
          --lupd.update_sidebar = true
        end
      ]]
      elseif char == lvar.keypress['editfx_deleteselectedctls'] then
        if mode == 1 and submode == 0 then
          --delete selected controls
          if reaper.MB('Delete selected controls?\n\nThis operation cannot be undone','LBX Stripper',4) == 6 then
            DeleteSelectedCtls()
            lupd.update_gfx = true
          end
        elseif mode == 1 and submode == 1 then
          GFX_Delete()
        end

      elseif char == lvar.keypress['show_stripbrowser'] then
        SetShowSB(not show_stripbrowser)
        lupd.update_stripbrowser = true
        lupd.update_surface = true
      elseif char == lvar.keypress['show_ctlmidiout'] then
        local strip = tracks[track_select].strip
        if strips and strips[strip] then
          local c = GetControlAtXY(strip,page,mouse.mx,mouse.my)
          if c then
            local ctl = strips[strip][page].controls[c]

            if ctl and (ctl.ctlcat == ctlcats.fxparam or
                        ctl.ctlcat == ctlcats.trackparam or
                        ctl.ctlcat == ctlcats.tracksend or
                        ctl.ctlcat == ctlcats.fxoffline or
                        ctl.ctlcat == ctlcats.macro or
                        ctl.ctlcat == ctlcats.takeswitcher or
                        ctl.ctlcat == ctlcats.rs5k) then

              midioutedit_select = c
              midioutedit_ctlselect = true
              midiout_select = ctl.midiout
              if midiout_select == nil then
                midiout_select = {output = nil,
                                  msgtype = 4,
                                  mchan = 1,
                                  msg3 = 1,
                                  msg4 = 0,
                                  osc = nil,
                                  vmin = 0,
                                  vmax = 127,
                                  focus = 1,
                                  focus_wintit = nil,
                                  focus_winexact = false,
                                  updategfx = false}
              end
              show_midiout = true
              lupd.update_gfx = true
            end
          end
        end
      elseif char == lvar.keypress['insert_special'] then
        if mode == 1 and submode == 0 then
          Menu_InsertSpecial()
        end
      elseif char == lvar.keypress['insert_favstrip_1'] then
        InsertFavStrip(1)
      elseif char == lvar.keypress['insert_favstrip_2'] then
        InsertFavStrip(2)
      elseif char == lvar.keypress['insert_favstrip_3'] then
        InsertFavStrip(3)
      elseif char == lvar.keypress['insert_favstrip_4'] then
        InsertFavStrip(4)
      elseif char == lvar.keypress['insert_favstrip_5'] then
        InsertFavStrip(5)
      elseif char == lvar.keypress['insert_favstrip_6'] then
        InsertFavStrip(6)
      elseif char == lvar.keypress['insert_favstrip_7'] then
        InsertFavStrip(7)
      elseif char == lvar.keypress['insert_favstrip_8'] then
        InsertFavStrip(8)
      elseif char == lvar.keypress['insert_favstrip_9'] then
        InsertFavStrip(9)
      elseif char == lvar.keypress['insert_favstrip_10'] then
        InsertFavStrip(10)
      elseif char == lvar.keypress['screenset1'] then
        if mouse.shift then
          Store_ScreenSet(1)
        else
          Recall_ScreenSet(1)
        end
      elseif char == lvar.keypress['screenset2'] then
        if mouse.shift then
          Store_ScreenSet(2)
        else
          Recall_ScreenSet(2)
        end
      elseif char == lvar.keypress['screenset3'] then
        if mouse.shift then
          Store_ScreenSet(3)
        else
          Recall_ScreenSet(3)
        end
      elseif char == lvar.keypress['screenset4'] then
        if mouse.shift then
          Store_ScreenSet(4)
        else
          Recall_ScreenSet(4)
        end
      end

    --[[else -- shift
      if char == 19 then
        ToggleSidebar()
      elseif char == 83 then
        show_snapshots = not show_snapshots
        lupd.update_gfx = true
      elseif char == 63 then
        show_settings = not show_settings
        lupd.update_surface = true
      end
    end   ]]
    return char
  end

  function Find_FXNotFound()
  
    local t_tab = {}
    for t = 0, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      t_tab[GetTrackGUID(tr)] = t
      --DBG(t..'  '..GetTrackGUID(tr))
    end
  
    local strip = tracks[track_select].strip
    if strips[strip] then
      local ctls = strips[strip][page].controls
      for c = 1, #ctls do
        local ctl = ctls[c]
        if ctl.fxfound == false then
          --DBG('searching '..c..'  '..tostring(ctl.trackguid))
          if ctl.ctlcat == ctlcats.trackparam then
            if ctl.trackguid and t_tab[ctl.trackguid] then 
              ctl.tracknum = t_tab[ctl.trackguid]
              ctl.fxfound = true
            end
          elseif ctl.ctlcat == ctlcats.fxparam then
          
          end
        end
      end
    end
    
  end

  function StripZoom()

    local zi = lvar.zoominfo

    if reaper.time_precise() >= zi.et then
      lvar.zoom = zi.tgt
      surface_offset.x = math.min(surface_offset.x, lvar.maxdim-(obj.sections[10].w/lvar.zoom))
      surface_offset.y = math.min(surface_offset.y, lvar.maxdim-(obj.sections[10].h/lvar.zoom))
      surface_offset.x = math.max(surface_offset.x, 0)
      surface_offset.y = math.max(surface_offset.y, 0)
      if lvar.livemode >= 1 then
        if lvar.mixmodedir == 0 then
          surface_offset.mixy = zi.mixp + (zi.mixpt/zi.tgt)
        else
          surface_offset.mixx = zi.mixp + (zi.mixpt/zi.tgt)
        end
      end

      if lvar.livemode >= 1 then
        local zz = zi.tgt/zi.src
        local strip = tracks[track_select].strip
        local pop = strips[strip][page].pop
        if pop and #pop > 0 then
          for i = 1, #pop do
            if pop[i].startx then
              pop[i].x = pop[i].startx*zz
            end
            if pop[i].starty then
              pop[i].y = pop[i].starty*zz
            end
          end
        end
        GUI_DrawCtlBitmap_Mix()
      end
      lvar.zoominfo = nil
    else
      local zz = (reaper.time_precise() - zi.st)/(zi.et-zi.st)
      lvar.zoom = zi.src + zz*(zi.tgt - zi.src)
      surface_offset.x = math.min(surface_offset.x, lvar.maxdim-(obj.sections[10].w/lvar.zoom))
      surface_offset.y = math.min(surface_offset.y, lvar.maxdim-(obj.sections[10].h/lvar.zoom))
      surface_offset.x = math.max(surface_offset.x, 0)
      surface_offset.y = math.max(surface_offset.y, 0)

      if lvar.livemode >= 1 then
        if lvar.mixmodedir == 0 then
          surface_offset.mixy = (zi.mixp or 0) + ((zi.mixpt/zi.tgt)*zz)
        else
          surface_offset.mixx = (zi.mixp or 0) + ((zi.mixpt/zi.tgt)*zz)
        end

        --[[local strip = tracks[track_select].strip
        local pop = strips[strip][page].pop
        if pop and #pop > 0 then
          for i = 1, #pop do
            if pop[i].startx then
              pop[i].x = pop[i].startx*lvar.zoom
            end
            if pop[i].starty then
              pop[i].y = pop[i].starty*lvar.zoom
            end
          end
          Pop_SetPos()
        end]]

      end
      --if (lvar.zoom * (2048-surface_offset.x)) < obj.sections[10].w then
      --  surface_offset.x = 0
      --end
      --if (lvar.zoom * (2048-surface_offset.y)) < obj.sections[10].h then
      --  surface_offset.y = 0
      --end
    end

    lupd.update_surface = true
    lupd.update_surfaceedge = true

  end


  function InsertFavStrip(n)
    if mode == 0 and show_striplayout ~= true and show_pinmatrix ~= true and macro_lrn_mode ~= true and show_xxy ~= true and strip_favs and strip_favs[n] then
      local fn = strip_favs[n]
      InsStrip(fn)
    end
  end

  function Menu_InsertSpecial()

    local mstr = '#Insert Special Control||Midi editor page switcher'
    gfx.x = mouse.mx
    gfx.y = mouse.my
    local res = gfx.showmenu(mstr)
    if res > 0 then
      if res == 2 then
        knob_select = def_boxctl
        dragparam = {x = mouse.mx, y = mouse.my, type = 'midieditor_pageswitch'}
        Strip_AddParam()
        lupd.update_gfx = true
      end
    end

  end

  function SetShowLFO(show)
    show_lfoedit = show
    if settings_moddock == true then
      obj = GetObjects()
    end
    lupd.update_gfx = true
    RedrawGUIBitmap()
  end

  function SetShowSS(show)
    show_snapshots = show
    if settings_ssdock == true then
      force_resize = true
      --obj = GetObjects()
    end
    lupd.update_gfx = true
    RedrawGUIBitmap()
  end

  function SetShowSB(show)
    show_stripbrowser = show
    if settings_sbdock == true then
      force_resize = true
      --obj = GetObjects()
    end
    lupd.update_surface = true
    RedrawGUIBitmap()
    if not show then
      --prevent processing click in sidebar when sb fullscreen
      lvar.closesb = true
    end
  end

  function SetShowSampleManager(show, c)
    show_samplemanager = show
    rs5k_select = c
    smlist_offset = 0
    local ctl = strips[tracks[track_select].strip][page].controls[c]
    if ctl then
      sample_select = math.floor(ctl.val * lvar.maxsamples)+1
      if lvar.followsample then
        FollowSample(sample_select,#ctl.rsdata.samples)
      end
    end
    if show == true then

      local trn = ctl.tracknum or strips[tracks[track_select].strip].track.tracknum
      local track = GetTrack(trn)
      local fxnum = ctl.fxnum
      local pstart = 3
      local pend = 4
      local s = reaper.TrackFX_GetParam(track,fxnum,pstart)
      local e = reaper.TrackFX_GetParam(track,fxnum,pend)

      lvar.kb.kstart = s*128
      lvar.kb.kend = e*128

      --out pin map
      lvar.rs = {}
      local _,_,outLo,outHi = GetPinMap(track, fxnum)
      local oLo0, oHi0 = ConvertPinMap(outLo[0],outHi[0])
      local oLo1, oHi1 = ConvertPinMap(outLo[1],outHi[1])
      local o0, o1
      for i = 0, 63 do
        if o0 == nil and oLo0[i] then
          o0 = i+1
        end
        if o1 == nil and oLo1[i] then
          o1 = i+1
        end
        if o0 and o1 then
          break
        end
      end
      if o0 or o1 then
        lvar.rs.out = 'OUT '..(o0 or '')..'+'..(o1 or '')
      else
        lvar.rs.out = 'No output'
      end

      --READ PITCH PARAM
      local pit = reaper.TrackFX_GetParam(track,fxnum,15)
      local single = 1/160
      local diff = 0.5-pit

      lvar.rs.pitch = round(diff/single)

      GUI_DrawKeyboardOverlay(obj, gui)
      PopSampleFavIdx()

    end
    lupd.update_gfx = true
    RedrawGUIBitmap()
  end

  function GallerySwipe(dir)

    if stripgallery_swipemt then return end

    stlay_data = AutoSnap_GetStripLocs(true)
    if stlay_data then
      StripLayout_DrawImageGallery(stlay_data)
      local pos = stlay_data.xpos + math.floor(obj.sections[10].w/2)
      local idx,inc
      if dir == 0 then
        for i = 1,#stlay_data.reordered do
          if stlay_data.reordered[i].runx_e > pos then
            idx = i
            break
          end
        end
        inc = -1
        if idx == 1 then return end
      else
        for i = 1,#stlay_data.reordered do
          if stlay_data.reordered[i].runx_e > pos then
            idx = i
            break
          end
        end
        inc = 1
        if idx == #stlay_data.reordered then return end
      end

      if idx then
        local t = reaper.time_precise()
        stripgallery_swipe = {xstart = stlay_data.xpos,
                              xend = stlay_data.reordered[idx+inc].runx_s - math.floor((obj.sections[10].w - stlay_data.reordered[idx+inc].w)/2),
                              mp = 0,
                              swipe_start = t,
                              swipe_end = t+striplayout_mtime}
        stripgallery_swipemt = t+striplayout_mtime
      end
    end

  end

  function TrackFXOrder_Read()

    local tfxorder = nil
    if tracks and tracks[track_select] then
      tfxorder = {}

      if lvar.livemode == 2 then
        local extid = lvar.stripdim.swdata.extid
        local maxpos = Switcher_Ext_GetMaxPos(extid)
        for p = 1, maxpos do
          local swid = lvar.stripdim.extposidx[extid][p]
          local swctl = switchers[swid]
          local swctl2 = swctl.grpids[1]
          if swctl2 then
            tfxorder[p] = {name = swctl2.name,
                           }
          else
            tfxorder[p] = {name = 'unknown',
                           }
          end
        end
      else
        local track = GetTrack(tracks[track_select].tracknum)
        local fxc = reaper.TrackFX_GetCount(track)
        local chunk = GetTrackChunk(track, settings_usetrackchunkfix)
        local s,e = 0,0

        for i = 1, fxc do
          local _, name = reaper.TrackFX_GetFXName(track,i-1,'')

          tfxorder[i] = {name = name,
                         guid = reaper.TrackFX_GetFXGUID(track,i-1),
                         fxnum = i-1,
                         found = true}

         s, e = string.find(chunk,'BYPASS %d %d %d',s)
         if s and e then
           local bypstr = string.sub(chunk,s,e)
           tfxorder[i].bypass = string.match(bypstr,'(%d) %d %d')
           tfxorder[i].offline = string.match(bypstr,'%d (%d) %d')
           s=e+1
         end

        end
      end
    end
    return tfxorder

  end

  function ArrowKey_Shift(char, ctl_select, gfx3_select, gfx4_select)

    if mouse.context then return end
    if char ~= 0 and char ~= 0x6C656674 and char ~= 0x72676874 and char ~= 0x7570 and char ~= 0x646F776E then return end
    
    local shifted
    local shiftsize = settings_gridsize
    if mouse.shift then
      shiftsize = 1
    end

    if char == 0 then 
      lvar.charcount = (lvar.charcount or 0) + 1
      if lvar.charcount < 8 then
        return 
      end
    else
      lvar.charcount = 0
    end
    local ctls = strips[tracks[track_select].strip][page].controls

    if gfx4_select then
      if --[[not mouse.ctrl and]] not keycontext then
        Undo_Set({'x','y','stretchw','stretchh'})
        keycontext = contexts.draggfx2
  
        --dragoff = {mx = mouse.mx, my = mouse.my, x = {}, y = {}}
        dragoff = {mx = 0, my = 0, x = {}, y = {}, relx = {}, rely = {}}
        lvar.dg2 = nil
  
        local l, t = lvar.maxdim, lvar.maxdim
        
        for g = 1, #gfx4_select do
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
          dragoff.x[g] = gfxx.x
          dragoff.y[g] = gfxx.y
          dragoff.relx[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].x - gfxx.x
          dragoff.rely[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].y - gfxx.y
          l = math.min(l, gfxx.x)
          t = math.min(t, gfxx.y)
          --gfxx.hide = true
        end
        A_HideSelectedCtls(true, nil, nil, gfx4_select)
        draggfx2 = 'draggfxA'
        GenGFX4DragPreview(gui)

        dragoff.left = l
        dragoff.top = t
        local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]]
        
        dragoff.mx = gfxx.x
        dragoff.my = gfxx.y
        lupd.update_gfx = true
      end
  
      if keycontext and char == 0 then
  
        keycontext = nil
        UnhideCtls()
        --SetCtlBitmapRedraw()
        lupd.update_gfx = true
        
      elseif keycontext and not mouse.ctrl then
        if char == 0x6C656674 then -- left arrow
          if gfx4_select and #gfx4_select > 0 then
            lvar.ctlsmoved = true
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x - shiftsize
              end
            end
          end
        elseif char == 0x72676874 then -- right arrow
          if gfx4_select and #gfx4_select > 0 then
            lvar.ctlsmoved = true
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x + shiftsize
              end
            end
          end
          
        elseif char == 0x7570 then -- up arrow
          if gfx4_select and #gfx4_select > 0 then
            lvar.ctlsmoved = true
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y - shiftsize
              end
            end
          end
        elseif char == 0x646F776E then -- down arrow
          if gfx4_select and #gfx4_select > 0 then
            lvar.ctlsmoved = true
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y + shiftsize
              end
            end
          end
        end
        shifted = true
        lupd.update_surface = true    
      end
    
      if mouse.ctrl and submode == 1 and --[[not]] keycontext then
        if char == 0x6C656674 then -- left arrow
          if gfx4_select and #gfx4_select > 0 then
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw - shiftsize
              end
            end
            GenGFX4DragPreview(gui)
            lupd.update_surface = true
            --lupd.update_gfx = true
            --SetCtlBitmapRedraw()
          end
        elseif char == 0x72676874 then -- right arrow
          if gfx4_select and #gfx4_select > 0 then
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw + shiftsize
              end
            end
            GenGFX4DragPreview(gui)
            lupd.update_surface = true
            --lupd.update_gfx = true
            --SetCtlBitmapRedraw()
          end
        elseif char == 0x7570 then -- up arrow
          if gfx4_select and #gfx4_select > 0 then
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh - shiftsize
              end
            end
            GenGFX4DragPreview(gui)
            lupd.update_surface = true
            --lupd.update_gfx = true
            --SetCtlBitmapRedraw()
          end
        elseif char == 0x646F776E then -- down arrow
          if gfx4_select and #gfx4_select > 0 then
            for i = 1, #gfx4_select do
              local gfx2_select = gfx4_select[i]
              if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh + shiftsize
              end
            end
            GenGFX4DragPreview(gui)
            lupd.update_surface = true
            --lupd.update_gfx = true
            --SetCtlBitmapRedraw()
          end
        end
        --lvar.ctlsmoved = nil
        shifted = true
      end
      
    elseif ctl_select or gfx3_select then
      if not mouse.ctrl and not keycontext then
        Undo_Set({'x','xsc','y','ysc','grpid'})

        dragctl = 'dragctl'
        keycontext = contexts.dragctl
        dragoff = {x = 0, y = 0}
        
        GenCtlDragPreview(gui)
        A_HideSelectedCtls(true, ctl_select, gfx3_select)
        lupd.update_gfx = true
      end
      
      if keycontext and char == 0 then
  
        keycontext = nil
        UnhideCtls()
        --SetCtlBitmapRedraw()
        lupd.update_gfx = true
        
      elseif keycontext then
        if char == 0x6C656674 then -- left arrow
          movex = -shiftsize
          if ctl_select and #ctl_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#ctl_select do
              local ctl = ctls[ctl_select[i].ctl]
              if ctl.poslock == false then
                local scale = ctl.scale
                ctl.x = ctl.x - shiftsize
                ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
              end
            end
          end
          if gfx3_select and #gfx3_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#gfx3_select do
              strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x - shiftsize
            end
          end
        elseif char == 0x72676874 then -- right arrow
          if ctl_select and #ctl_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#ctl_select do
              local ctl = ctls[ctl_select[i].ctl]
              if ctl.poslock == false then
                local scale = ctl.scale
                ctl.x = ctl.x + shiftsize
                ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
              end
            end
          end
          if gfx3_select and #gfx3_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#gfx3_select do
              strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x + shiftsize
            end
          end
        elseif char == 0x7570 then -- up arrow
          if ctl_select and #ctl_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#ctl_select do
              local ctl = ctls[ctl_select[i].ctl]
              if ctl.poslock == false then
                local scale = ctl.scale
                ctl.y = ctl.y - shiftsize
                ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              end
            end
          end
          if gfx3_select and #gfx3_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#gfx3_select do
              strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y - shiftsize
            end
          end
        elseif char == 0x646F776E then -- down arrow
          if ctl_select and #ctl_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#ctl_select do
              local ctl = ctls[ctl_select[i].ctl]
              if ctl.poslock == false then
                local scale = ctl.scale
                ctl.y = ctl.y + shiftsize
                ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              end
            end
          end
          if gfx3_select and #gfx3_select > 0 then
            lvar.ctlsmoved = true
            for i = 1,#gfx3_select do
              strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y + shiftsize
            end
          end
        end        

        shifted = true
        lupd.update_surface = true
      end
      
    else
      keycontext = nil
      UnhideCtls()
      --SetCtlBitmapRedraw()
      dragctl = nil
      dragoff = nil
      --lupd.update_surface = true
    end
    
    --[[if char == 0x6C656674 then -- left arrow
      if (mode == 0 or submode == 2) or (lvar.lockx or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.x = ctl.x - shiftsize
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x - shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw - shiftsize
              else 
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x - shiftsize
              end
            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x72676874 then -- right arrow
      if (mode == 0 or submode == 2) or (lvar.lockx or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.x = ctl.x + shiftsize
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x + shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw + shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x + shiftsize
              end
            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x7570 then -- up arrow
      if (mode == 0 or submode == 2) or (lvar.locky or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.y = ctl.y - shiftsize
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y - shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh - shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y - shiftsize
              end

            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x646F776E then -- down arrow
      if (mode == 0 or submode == 2) or (lvar.locky or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.y = ctl.y + shiftsize
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y + shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh + shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y + shiftsize
              end

            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    end]]
    movefrom_sc = nil

    return shifted
  end

  --[[function ArrowKey_Shifto(char, ctl_select, gfx3_select, gfx4_select)

    local shifted
    local shiftsize = settings_gridsize
    if mouse.shift then
      shiftsize = 1
    end

    local ctls = strips[tracks[track_select].strip][page].controls
    if char == 0x6C656674 then -- left arrow
      if (mode == 0 or submode == 2) or (lvar.lockx or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.x = ctl.x - shiftsize
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x - shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw - shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x - shiftsize
              end
            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x72676874 then -- right arrow
      if (mode == 0 or submode == 2) or (lvar.lockx or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.x = ctl.x + shiftsize
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x + shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchw + shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].x =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].x + shiftsize
              end
            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x7570 then -- up arrow
      if (mode == 0 or submode == 2) or (lvar.locky or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.y = ctl.y - shiftsize
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y - shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh - shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y - shiftsize
              end

            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    elseif char == 0x646F776E then -- down arrow
      if (mode == 0 or submode == 2) or (lvar.locky or false) == false then
        Undo_Set({'x','xsc','y','ysc','wsc','hsc','stretchw','stretchh'})
        shifted = true
        if ctl_select and #ctl_select > 0 then
          for i = 1,#ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            if ctl.poslock == false then
              local scale = ctl.scale
              ctl.y = ctl.y + shiftsize
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
            end
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for i = 1,#gfx3_select do
            strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y =
                          strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y + shiftsize
          end
        end
        if gfx4_select and #gfx4_select > 0 then
          for i = 1, #gfx4_select do
            local gfx2_select = gfx4_select[i]
            if strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock == false then

              if submode == 1 and mouse.ctrl then
                strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].stretchh + shiftsize
              else
                strips[tracks[track_select].strip][page].graphics[gfx2_select].y =
                              strips[tracks[track_select].strip][page].graphics[gfx2_select].y + shiftsize
              end

            end
          end
        end
        lupd.update_gfx = true
        SetCtlBitmapRedraw()
      end
    end
    movefrom_sc = nil

    return shifted
  end]]
  
  function Copy_Selected()

    if submode == 0 then
      if (ctl_select and #ctl_select > 0) or (gfx3_select and #gfx3_select > 0) then

        copy_ctls = {strip = tracks[track_select].strip,
                     page = page,
                     tracknum = tracks[track_select].tracknum,
                     trackguid = tracks[track_select].guid,
                     ctls = {},
                     gfx = {}}
        if ctl_select and #ctl_select > 0 then
          for c = 1, #ctl_select do
            copy_ctls.ctls[c] = ctl_select[c].ctl
          end
        end
        if gfx3_select and #gfx3_select > 0 then
          for c = 1, #gfx3_select do
            copy_ctls.gfx[c] = gfx3_select[c].ctl
          end
        end

        lupd.update_cbox = true
      end
    else
      if (gfx4_select and #gfx4_select > 0) then

        copy_ctls = {strip = tracks[track_select].strip,
                     page = page,
                     tracknum = tracks[track_select].tracknum,
                     trackguid = tracks[track_select].guid,
                     ctls = {},
                     gfx = {}}
        if gfx4_select and #gfx4_select > 0 then
          for c = 1, #gfx4_select do
            copy_ctls.gfx[c] = gfx4_select[c]
          end
        end

        lupd.update_cbox = true
      end

    end
  end

  function PasteSpecial_Menu(x,y)
    local ps = ''
    local psc = #lvar.pastespecial
    if copy_ctls ~= nil then
      for i = 1, psc do
        local tick = ''
        if i == lvar.pastespecial_sel then
          tick = '!'
        end
        ps = ps..'|'..tick..lvar.pastespecial[i][1]
      end
    else
      for i = 1, psc do
        local tick = ''
        if i == lvar.pastespecial_sel then
          tick = '!'
        end
        ps = ps..'|#'..tick..lvar.pastespecial[i][1]
      end
    end
    gfx.x = x
    gfx.y = y
    local res = gfx.showmenu(ps)
    if res > 0 then
      PasteSpecial(res)
    end
  end
  
  function PasteSpecial(ps)
  
    lvar.pastespecial_sel = ps
    
    if copy_ctls and ((copy_ctls.ctls and #copy_ctls.ctls > 0)) then
      local ctbl = GetControlTable(copy_ctls.strip, copy_ctls.page, copy_ctls.ctls[1])
      if ctbl then
        if tracks[track_select] then
          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls
          
          local pastespecial = lvar.pastespecial[ps]
          
          if ctl_select and #ctl_select > 0 then

            local tab = table.copy(pastespecial)
            tab[#tab+1] = 'x'
            tab[#tab+1] = 'y'
            tab[#tab+1] = 'xsc'
            tab[#tab+1] = 'ysc'
            tab[#tab+1] = 'wsc'
            tab[#tab+1] = 'hsc'
            Undo_Set(tab)
            
            for c = 1, #ctl_select do
              local ctl = ctls[ctl_select[c].ctl]
              if ctl then
                local xc = ctl.xsc + ctl.wsc/2
                local yc = ctl.ysc + ctl.hsc/2
                for p = 2, #pastespecial do    
                
                  if type(pastespecial[p]) == 'table' then
                    ctl[pastespecial[p]] = table.copy(ctbl[pastespecial[p]])
                  else
                    ctl[pastespecial[p]] = ctbl[pastespecial[p]]
                  end
                  
                  --Special cases
                  if pastespecial[1] == 'Paste Image Scale|' then
                    ctl.wsc = ctl.w*ctl.scale
                    ctl.hsc = ctl.ctl_info.cellh*ctl.scale
                    ctl.x = math.floor(xc - ctl.w/2)
                    ctl.y = math.floor(yc - ctl.ctl_info.cellh/2)
                    ctl.xsc = math.floor(xc - ctl.wsc/2)
                    ctl.ysc = math.floor(yc - ctl.hsc/2)
                    
                  elseif pastespecial[p] == 'wsc' then
                    ctl.xsc = math.floor(xc - ctl.wsc/2)
                  elseif pastespecial[p] == 'w' then
                    ctl.x = math.floor(xc - ctl.w/2)
                  elseif pastespecial[p] == 'hsc' then
                    ctl.ysc = math.floor(yc - ctl.hsc/2)
                  elseif pastespecial[p] == 'ctl_info' then
                    ctl.y = math.floor(yc - ctl.ctl_info.cellh/2)
                  end
                  SetCtlDirty(ctl_select[c].ctl)
                end
              end
            end
            movefrom_sc = nil
            lupd.update_gfx = true
            lupd.update_ctls = true
            lupd.update_ctlopts = true
            ReselectSelection()
            selrect, selrect_sc = CalcSelRect()
            SetCtlSelectVals()
            SetCtlBitmapRedraw()
          end
        end
      end
    end
  
  end

  function Paste_Selected(keep_coords)

    if copy_ctls and ((copy_ctls.ctls and #copy_ctls.ctls > 0) or (copy_ctls.gfx and #copy_ctls.gfx > 0)) then
      if tracks[track_select] then

        movefrom_sc = nil

        local strip = Strip_INIT()
        local dx, dy
        local grids = {}
        local swids = {}
        local ctls = strips[strip][page].controls
        local gfxx = strips[strip][page].graphics

        local cids = {}
        local cstart, gstart
        local copyflag

        if #copy_ctls.ctls > 0 then

          cstart = #ctls + 1

          for c = 1, #copy_ctls.ctls do
            local nc = #ctls+1
            local ctbl = GetControlTable(copy_ctls.strip, copy_ctls.page, copy_ctls.ctls[c])
            if ctbl then
              ctbl.poslock = false
              if (ctbl.ctlcat ~= ctlcats.snapshot and ctbl.ctlcat ~= ctlcats.xy and ctbl.ctlcat ~= ctlcats.eqcontrol and ctbl.ctlcat ~= ctlcats.snapshotrand) or
                 (copy_ctls.strip == strip and copy_ctls.page == page) then

                copyflag = true
                ctls[nc] = ctbl
                cids[strips[copy_ctls.strip][copy_ctls.page].controls[copy_ctls.ctls[c]].c_id] = {cid = ctls[nc].c_id,
                                                                                                  ctl = nc}
                if ctls[nc].tracknum == nil and tracks[track_select].trackguid ~= copy_ctls.trackguid then
                  ctls[nc].tracknum = copy_ctls.tracknum
                  ctls[nc].trackguid = copy_ctls.trackguid
                end

                if ctls[nc].grpid then
                  if grids[ctls[nc].grpid] then
                    ctls[nc].grpid = grids[ctls[nc].grpid]
                  else
                    local grpid = GenID()
                    grids[ctls[nc].grpid] = grpid
                    ctls[nc].grpid = grpid
                  end
                end

              end
            end
          end

          if copyflag then
            dx = strips[tracks[track_select].strip][page].controls[cstart].x - (mouse.mx+surface_offset.x-obj.sections[10].x)
            dy = strips[tracks[track_select].strip][page].controls[cstart].y - (mouse.my+surface_offset.y-obj.sections[10].y)

            ctl_select = nil

            for c = cstart, #ctls do

              if not keep_coords then
                strips[tracks[track_select].strip][page].controls[c].x = strips[tracks[track_select].strip][page].controls[c].x - dx
                strips[tracks[track_select].strip][page].controls[c].y = strips[tracks[track_select].strip][page].controls[c].y - dy
                strips[tracks[track_select].strip][page].controls[c].xsc = strips[tracks[track_select].strip][page].controls[c].xsc - dx
                strips[tracks[track_select].strip][page].controls[c].ysc = strips[tracks[track_select].strip][page].controls[c].ysc - dy
              end
              strips[tracks[track_select].strip][page].controls[c].id = nil
              --strips[tracks[track_select].strip][page].controls[c].switcher = nil

              if ctl_select == nil then
                ctl_select = {}
                ctl_select[1] = {ctl = c}
              else
                local cs = #ctl_select+1
                ctl_select[cs] = {}
                ctl_select[cs].ctl = c
                ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[c].x
                ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[c].y
              end

              if ctls[c].ctlcat == ctlcats.macro then

                local macro = ctls[c].macroctl
                if macro and #macro > 0 then

                  local mcnt = #macro
                  local nils = false
                  for m = 1, mcnt do

                    local mcid = macro[m].c_id
                    if cids[mcid] then
                      macro[m].ctl = cids[mcid].ctl
                      macro[m].c_id = cids[mcid].cid
                    else
                      macro[m] = nil
                      nils = true
                    end

                  end

                  if nils then
                    local mtbl = Table_RemoveNils(macro, mcnt)
                    strips[strip][page].controls[c].macroctl = mtbl
                  end
                end

              --[[elseif ctls[c].ctlcat == ctlcats.switcher then
                local oldsw = ctls[c].switcherid

                local swcnt = #switchers+1
                switchers[swcnt] = {grpids ={},
                                    current = -1}
                switchers[swcnt].switchmode = switchers[oldsw].switchmode
                if switchers[swcnt].switchmode == 1 then
                  switchers[swcnt].dropx = switchers[oldsw].dropx
                  switchers[swcnt].dropy = switchers[oldsw].dropy
                  switchers[swcnt].copypinmap = switchers[oldsw].copypinmap
                  switchers[swcnt].stripfolder = switchers[oldsw].stripfolder

                  Switchers_AddInsertFX(swcnt, tracks[track_select].strip, page, c)
                end

                ctls[c].switcherid = swcnt
                ctls[c].switcher = nil
                ctls[c].grpid = nil]]
              end
            end
          end
        end

        if #copy_ctls.gfx > 0 then

          gstart = #gfxx + 1

          for c = 1, #copy_ctls.gfx do
            local nc = #gfxx+1
            local ctbl = GetGraphicsTable(copy_ctls.strip, copy_ctls.page, copy_ctls.gfx[c])
            ctbl.poslock = false

            gfxx[nc] = ctbl

            if gfxx[nc].grpid then
              if grids[gfxx[nc].grpid] then
                gfxx[nc].grpid = grids[gfxx[nc].grpid]
              else
                local grpid = GenID()
                grids[gfxx[nc].grpid] = grpid
                gfxx[nc].grpid = grpid
              end
            end
          end

          if dx == nil or dy == nil then
            dx = strips[tracks[track_select].strip][page].graphics[gstart].x - (mouse.mx+surface_offset.x-obj.sections[10].x)
            dy = strips[tracks[track_select].strip][page].graphics[gstart].y - (mouse.my+surface_offset.y-obj.sections[10].y)
          end

          gfx3_select = nil

          for c = gstart, #gfxx do

            if not keep_coords then
              strips[tracks[track_select].strip][page].graphics[c].x = strips[tracks[track_select].strip][page].graphics[c].x - dx
              strips[tracks[track_select].strip][page].graphics[c].y = strips[tracks[track_select].strip][page].graphics[c].y - dy
            end
            --strips[tracks[track_select].strip][page].graphics[c].switcher = nil

            if gfx3_select == nil then
              gfx3_select = {}
            end
            local cs = #gfx3_select+1
            gfx3_select[cs] = {}
            gfx3_select[cs].ctl = c
            if ctl_select and ctl_select[1] then
              gfx3_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[c].x
              gfx3_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[c].y
            elseif gfx3_select and gfx3_select[1] then
              gfx3_select[cs].relx = strips[tracks[track_select].strip][page].graphics[gfx3_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[c].x
              gfx3_select[cs].rely = strips[tracks[track_select].strip][page].graphics[gfx3_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[c].y
            end
          end
        end

        local nsflag
        if copyflag then
          --switchers
          local swstart = #switchers+1
          nsflag = false
          for c = cstart, #ctls do
            if ctls[c].ctlcat == ctlcats.switcher then
              local oldsw = ctls[c].switcherid
              local stab = GetSwitcherTable(ctls[c].switcherid)
              --table.insert(stab, switchers[ctls[c].switcherid])
              ns = #switchers+1
              nsflag = true
              switchers[ns] = stab

              switchers[ns].switchmode = switchers[oldsw].switchmode
              if switchers[ns].switchmode == 1 then
                switchers[ns].dropx = switchers[oldsw].dropx
                switchers[ns].dropy = switchers[oldsw].dropy
                switchers[ns].copypinmap = switchers[oldsw].copypinmap
                switchers[ns].stripfolder = switchers[oldsw].stripfolder

                Switchers_AddInsertFX(ns, tracks[track_select].strip, page, c)
              end
              swids[ctls[c].switcherid] = ns
            end
          end

          if nsflag then
            for s = swstart, #switchers do
              --[[if switchers[s].parent and swids[switchers[s].parent.switcherid] then
                switchers[s].parent.switcherid = swids[switchers[s].parent.switcherid]
                switchers[s].parent.grpid = grids[switchers[s].parent.grpid]
              else
                switchers[s].parent = nil
              end]]
              switchers[s].parent = nil

              if switchers[s].grpids and #switchers[s].grpids > 0 then
                for g = 1, #switchers[s].grpids do
                  if grids[switchers[s].grpids[g].id] then
                    switchers[s].grpids[g].id = grids[switchers[s].grpids[g].id]
                  else
                    grids[switchers[s].grpids[g].id] = GenID()
                    switchers[s].grpids[g].id = grids[switchers[s].grpids[g].id]
                  end
                end
              end
              if switchers[s].current and grids[switchers[s].current] then
                switchers[s].current = grids[switchers[s].current]
              else
                if switchers[s].grpids and switchers[s].grpids[1] then
                  switchers[s].current = switchers[s].grpids[1].id
                else
                  switchers[s].current = -1
                end
              end
            end
          end

          for c = cstart, #ctls do
            if ctls[c].ctlcat == ctlcats.switcher_pagesel then
              if grids[ctls[c].param] then
                ctls[c].param = grids[ctls[c].param]
              end
            end
            if ctls[c].switcherid then
              if swids[ctls[c].switcherid] then
                ctls[c].switcherid = swids[ctls[c].switcherid]
              else
                --ctls[c].switcherid = nil
              end
            end
            if ctls[c].switcher then
              if swids[ctls[c].switcher] then
                ctls[c].switcher = swids[ctls[c].switcher]
              else
                ctls[c].switcher = nil
              end
            end
          end
        end

        if gstart then
          for c = gstart, #gfxx do
            if gfxx[c].switcher then
              if swids[gfxx[c].switcher] then
                gfxx[c].switcher = swids[gfxx[c].switcher]
              else
                gfxx[c].switcher = nil
              end
            end
          end
        end

      end
    end
  end

  function GetStripAtXY(strip,page,x,y)

    if stlay_data == nil then
      stlay_data = AutoSnap_GetStripLocs(true)
    end
    if stlay_data then
      for i = 1, #stlay_data.loc do
        local xywh = {x = stlay_data.reordered[i].l,
                      y = stlay_data.reordered[i].t,
                      w = stlay_data.reordered[i].w,
                      h = stlay_data.reordered[i].h}
        if MOUSE_over(xywh,x,y) then

          return stlay_data.reordered[i].stripid, i

        end
      end
    end
  end

  function GetStripAtXYGallery(strip,page,x,y)

    if stlay_data == nil then
      stlay_data = AutoSnap_GetStripLocs(true)
    end
    if stlay_data then

      local d = stlay_data
      local dh = 0
      local dw = d.loc[#d.loc].runx_e

      local ww,hh = gfx.getimgdim(993)
      local sc = math.min(ww / dw,.4)
      for i = 1, #d.loc do
        local xywh = {x = d.loc[i].runx_s*sc,
                      y = 0,
                      w = d.loc[i].w*sc,
                      h = hh}
        if MOUSE_over(xywh,x,y) then

          return d.loc[i].stripid, i

        end
      end
    end
  end

  function GetControlAtXY(strip,page,x,y,absolute)
    if strips and strips[strip] then
      local ctls = strips[strip][page].controls
      local ret, retstripidx, retstripid
      if settings_usectlbitmap then
        local coffset = 8388608
        local guiobject
        if (lvar.livemode == 0 or mode == 1 or macro_lrn_mode) and (stripgallery_view == 0 or show_striplayout == true or (mode == 1 and submode == 0)) then
          gfx.dest = guibitmap
          if not absolute then
            gfx.x = x
            gfx.y = y
          else
            gfx.x = x+obj.sections[10].x
            gfx.y = y+obj.sections[10].y
          end
          local r2,g2,b2 = gfx.getpixel()
          guiobject = (r2*255) + ((g2*255) << 8) + ((b2*255) << 16)
          --if guiobject == 10 then --surface
            gfx.dest = ctl_bitmap
            if absolute then
              gfx.x = math.floor(x/lvar.zoom)
              gfx.y = math.floor(y/lvar.zoom)
            else
              gfx.x = math.floor((x  -obj.sections[10].x)/lvar.zoom) + surface_offset.x
              gfx.y = math.floor((y  -obj.sections[10].y)/lvar.zoom) + surface_offset.y
            end
          --end
        else
          gfx.dest = guibitmap
          if not absolute then
            gfx.x = x
            gfx.y = y
          else
            gfx.x = x+obj.sections[10].x
            gfx.y = y+obj.sections[10].y
          end
          local r2,g2,b2 = gfx.getpixel()
          guiobject = (r2*255) + ((g2*255) << 8) + ((b2*255) << 16)
          --if guiobject == 10 then --surface
            gfx.dest = ctl_bitmap2
            gfx.x = math.floor(x) - obj.sections[10000].x
            gfx.y = math.floor(y) - obj.sections[10000].y
          --end
        end
        if guiobject >= lvar.xPnlOffset and guiobject <= lvar.xPnlOffset + #xPnlIdx then
          
        elseif guiobject == 10 or guiobject == 300 or mode ~= 0 then
          local r,g,b = gfx.getpixel()
          gfx.dest = 1
          --local cc = r*255 + ((g*255) << 8) + ((b*255) << 16)
          local cc = math.floor(((r*255) + ((g*255) << 8) + ((b*255) << 16))+0.5)
          --DBG(cc)
          if cc > 0 and ctls[cc] then
            local ctl = strips[strip][page].controls[cc]
            if Switcher_CtlsHidden(ctl.switcher, ctl.grpid) == false then
              ret = cc
              retstripid = ctl.id
              retstripidx = lvar.stripdim.idx[retstripid]
            end
          elseif cc > coffset then
            retstripidx = cc % coffset
            if lvar.stripdim and lvar.stripdim.data[retstripidx] then
              retstripid = lvar.stripdim.data[retstripidx].id
            end
          end
        end
      else
        for ii = 1, #strips[strip][page].controls do

          local ctl = strips[strip][page].controls[ii]
          if absolute then
            ctlxywh = {x = ctl.xsc,
                       y = ctl.ysc,
                       w = ctl.wsc,
                       h = ctl.hsc}
          else
            ctlxywh = {x = ctl.xsc - surface_offset.x +obj.sections[10].x,
                       y = ctl.ysc - surface_offset.y +obj.sections[10].y,
                       w = ctl.wsc,
                       h = ctl.hsc}
          end
          if MOUSE_over(ctlxywh, x, y) then

            if Switcher_CtlsHidden(ctl.switcher, ctl.grpid) == false and ctl.clickthrough ~= true then
              ret = ii
              break
            end
          end

        end
      end
      --DBG(tostring(ret)..'  '..strip..'  '..page)
      return ret, retstripidx, retstripid
    end
  end


  function ZeroProjectFlags()
    reaper.SetProjExtState(0,'LBXFLAGS','LBX_SAVE_PROJECT','')
  end

  function ReadProjectFlags()

    local _, lbxsaveflag = reaper.GetProjExtState(0,'LBXFLAGS','LBX_SAVE_PROJECT')
    if lbxsaveflag ~= '' then
      if lbxsaveflag == 'N' then
        --reaper.Main_OnCommand(41895,0)
        SaveProj(nil,true)
        reaper.SetProjExtState(0,'LBXFLAGS','LBX_SAVE_PROJECT','')
        DBGOut('*** Save Project (increment filename) via external script ***')
      else
        SaveProj(nil,true)
        reaper.SetProjExtState(0,'LBXFLAGS','LBX_SAVE_PROJECT','')
        DBGOut('*** Save Project via external script ***')
      end
    end

  end

  function FindSaveFile(fn)

    local f = string.match(fn, '(.*)%.lbxstripper')
    if f then fn = f end

    local load_path
    local sf = ''

    if save_subfolder and save_subfolder ~= '' then
      sf = save_subfolder
      if sf == '#' then
        local projname = GetProjectName()
        sf = projname
      end
      sf = sf ..'/'
    end

    fn = sf..fn


    if settings_savedatainprojectfolder == true then
      load_path=reaper.GetProjectPath('')..'/'

      if reaper.file_exists(load_path..fn..'.lbxstripper') ~= true and reaper.file_exists(load_path..fn..'.lbxstripper__') ~= true then
        load_path=paths.projsave_path
      end
    else
      load_path=paths.projsave_path

      if reaper.file_exists(load_path..fn..'.lbxstripper') ~= true and reaper.file_exists(load_path..fn..'.lbxstripper__') ~= true then
        load_path=reaper.GetProjectPath('')..'/'
      end
    end

    local ffn=load_path..fn

    local fndffn, fndfn
    if reaper.file_exists(ffn..'.lbxstripper') then
      fndffn = ffn..'.lbxstripper'
      fndfn = fn..'.lbxstripper'
    elseif reaper.file_exists(ffn..'.lbxstripper__') then
      fndffn = ffn..'.lbxstripper__'
      fndfn = fn..'.lbxstripper__'
    end

    if fndfn then
      return true, fndfn, fndffn, nil
    else

      local xfn = GPES('lbxstripper_datafile', true)
      if xfn and reaper.file_exists(load_path..xfn) == true then
        return false, nil, nil, true
      else
        return false, nil, nil, nil
      end
    end

  end

  function TrackLabelCheck()

    local trcnt = reaper.CountTracks(0)
    local otrack = track_select
    local poptr = false
    local movetracks = {}

    for t = -1, trcnt-1 do
      local tr = GetTrack(t)
      local trg = GetTrackGUID(tr)
      local _, trlbl = reaper.GetTrackName(tr, '')
      if trlbl then
        local tracknm, stripnm = string.match(trlbl, '(.-)LBXSTRIP%[(.-)%]')
        if stripnm then
        
          local olm = lvar.livemode
        
          lvar.livemode = 0
          if string.match(stripnm,'.+(%..*)') ~= '.strip' then
            stripnm = stripnm..'.strip'
          end

          local fol = FindStripFolder(stripnm)
          if fol then
            loadstrip = LoadStrip(nil, fol, stripnm)
            if loadstrip then
              if gui == nil then
                GetGUI_vars()
              end
              GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)

              track_select = t
              loadstrip.autoload_lbxstrip = true
              local _, strip = Strip_AddStrip(loadstrip,0,0,nil,t,trg,-1)
              track_select = otrack
              poptr = true

              --image_count = image_count_add
              loadstrip = nil
              reaper.MarkProjectDirty(0)
            end

            --rename track
            reaper.GetSetMediaTrackInfo_String(tr, "P_NAME", tracknm, true)

          end

          lvar.livemode = olm
          
        else
          tracknm, stripnm = string.match(trlbl, '(.-)LBXSET%[(.-)%]')
          if stripnm then
            if string.match(stripnm,'.+(%..*)') ~= '.stripset' then
              stripnm = stripnm..'.stripset'
            end
            local load_path=paths.sets_path
            local ffn=load_path..stripnm
            if reaper.file_exists(ffn) then

              local ft, lt = LoadSet2(ffn, true)
              --Move tracks
              movetracks[#movetracks+1] = {target = t, ft = ft, lt = lt}
            else
              DBG('Auto load stripset failed (not found): '..ffn)
            end
            --rename track
            reaper.GetSetMediaTrackInfo_String(tr, "P_NAME", tracknm, true)

            poptr = true
          else
            --check trackstrips table
            if lvar.trackstrips[trlbl] then
          
              local opage = page
              local olm = lvar.livemode
              
              local strip = tracks[t].strip or -1
                      
              lvar.livemode = 0
              
              for p = 1, lvar.maxpage do
                local stripnm = lvar.trackstrips[trlbl][p]
                if stripnm and (strip == -1 or not strips[strip] or #strips[strip][p].controls == 0) then
                  
                  if string.match(stripnm,'.+(%..*)') ~= '.strip' then
                    stripnm = stripnm..'.strip'
                  end
                  local fol = FindStripFolder(stripnm)
                  if fol then
                    loadstrip = LoadStrip(nil, fol, stripnm)
                    if loadstrip then
                      if gui == nil then
                        GetGUI_vars()
                      end
                      GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
        
                      track_select = t
                      page = p
                      loadstrip.autoload_lbxstrip = true
                      local _, strip = Strip_AddStrip(loadstrip,0,0,nil,t,trg,-1)
                      poptr = true
        
                      --image_count = image_count_add
                      loadstrip = nil
                      reaper.MarkProjectDirty(0)
                    end
                  end
                end
              end
              track_select = otrack
              page = opage
              lvar.livemode = olm
          
            end
          end
        end
      end
    end
    if movetracks then
      local offset = 0
      local deltr = {}
      for mm = #movetracks, 1, -1 do
        local ft, lt = movetracks[mm].ft, movetracks[mm].lt
        local tr2 = GetTrack(ft+offset)
        reaper.SetOnlyTrackSelected(tr2)
        if lt > ft then
          for tt = ft+1, lt do
            local tr2 = GetTrack(tt+offset)
            if tr2 then
              reaper.SetTrackSelected(tr2, true)
              --reaper.SetMediaTrackInfo_Value(tr2, 'I_SELECTED', 1)
            end
          end
        end
        local dtr = GetTrack(movetracks[mm].target)
        deltr[GetTrackGUID(dtr)] = 1
        reaper.ReorderSelectedTracks(movetracks[mm].target+1, 0)
        --reaper.DeleteTrack(dtr)
        offset = offset + (lt-ft)+1
      end
      PopulateTracks()
      --if #deltr > 0 then
        for t = reaper.CountTracks(0)-1, 0, -1 do
          local dtr = GetTrack(t)
          if deltr[GetTrackGUID(dtr)] == 1 then
            reaper.DeleteTrack(dtr)
          end
        end
      --end
    end
    if poptr then
      PopulateTracks()
    end

  end

  function GetStripDim(trn)

    local l, t, r, b = lvar.maxdim, lvar.maxdim, 0, 0
    local strip = tracks[trn].strip
    if strips[strip] then
      local ctls = strips[strip][page].controls
      if ctls then

        for i = 1, #ctls do
          if not ctls[i].hidden then
            l = math.min(l, ctls[i].xsc)
            t = math.min(t, ctls[i].ysc)
            r = math.max(r, ctls[i].xsc+ctls[i].wsc)
            b = math.max(b, ctls[i].ysc+ctls[i].hsc)
          end
        end

      end
      local gfxx = strips[strip][page].graphics
      if gfxx then

        for i = 1, #gfxx do
          if not gfxx[i].hidden then
            l = math.min(l, gfxx[i].x)
            t = math.min(t, gfxx[i].y)
            r = math.max(r, gfxx[i].x+gfxx[i].stretchw)
            b = math.max(b, gfxx[i].y+gfxx[i].stretchh)
          end
        end

      end
      local w, h = r-l, b-t

      return l, t, r, b, w, h
    end

  end

  function CentreAllControls(trn)

    local strip = tracks[trn].strip
    if strips[strip] then

      local l, t, r, b, w, h = GetStripDim(trn)
      if w then

        local gs = settings_gridsize

        local nx = math.floor(math.floor(1024-w/2)/gs)*gs
        local ny = math.floor(math.floor(1024-h/2)/gs)*gs

        local dx = nx - l
        local dy = ny - t

        local ctls = strips[strip][page].controls
        if ctls then
          for i = 1, #ctls do
            local scale = ctls[i].scale
            ctls[i].x = ctls[i].x + dx
            ctls[i].xsc = ctls[i].x + math.floor(ctls[i].w/2 - (ctls[i].w*scale)/2)
            ctls[i].y = ctls[i].y + dy
            ctls[i].ysc = ctls[i].y + math.floor(ctls[i].ctl_info.cellh/2 - (ctls[i].ctl_info.cellh*scale)/2)
          end
        end

        local gfxx = strips[strip][page].graphics
        if gfxx then
          for i = 1, #gfxx do
            gfxx[i].x = gfxx[i].x + dx
            gfxx[i].y = gfxx[i].y + dy
          end
        end

        lupd.update_gfx = true
        lupd.update_bg = true

        surface_offset.x = math.floor(1024-(obj.sections[10].w/2))
        surface_offset.y = math.floor(1024-(obj.sections[10].h/2))
      end
      
      SetCtlBitmapRedraw()
    end

  end

  function DM_SaveStrip(quick)

    if quick then
      SaveStrip3(lvar.dm_editmode_data.stripfn, nil, lvar.dm_editmode_data.sfn, true)
      --[[local ret_page = lvar.dm_editmode_data.ret_page
      local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
      navigate = true

      if lvar.dm_editmode_data.plist_w == 0 then
        plist_w = lvar.dm_editmode_data.plist_w
        show_editbar = false
        resize_display = true
      end
      lvar.dm_editmode_data = nil

      setmode(1)
      ChangeTrack2(ret_trn, ret_page, true)
      obj = PosTrBtns(obj)]]

    elseif lvar.dm_editmode_data.stripfn ~= 'dynamic_placeholder' then
      if not mouse.ctrl or not lvar.dm_editmode_data.stripfn then
        local fxident = lvar.dm_editmode_data.stripfn
        --if not fxident then
          local track = GetTrackByName('__LBXEDIT')
          if track then
            local fxnum = 0
            local _, plug = reaper.TrackFX_GetFXName(track, fxnum, '')
            if plug then
              if not fxident then
                fxident = TrimStr(CropFXName(plug))
              end
            end
          end
        --end
        lvar.dm_save_plug = fxident
        OpenEB(5020, 'Please enter strip name (plug id: '..fxident..') :', fxident)
      else
        SaveStrip3(lvar.dm_editmode_data.stripfn, nil, lvar.dm_editmode_data.sfn)
        if reaper.JS_LICE_WritePNG then
          lvar.dm_return_set = true
        else
          local ret_page = lvar.dm_editmode_data.ret_page
          local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
          navigate = true

          if lvar.dm_editmode_data.plist_w == 0 then
            plist_w = lvar.dm_editmode_data.plist_w
            show_editbar = false
            resize_display = true
          end
          lvar.dm_editmode_data = nil

          setmode(1)
          ChangeTrack2(ret_trn, ret_page, true)
          obj = PosTrBtns(obj)
        end
      end
    else
      local fxident = string.lower(lvar.dm_editmode_data.plugname)
      if not mouse.ctrl then
        local track = GetTrackByName('__LBXEDIT')
        if track then
          local fxnum = 0
          local _, plug = reaper.TrackFX_GetFXName(track, fxnum, '')
          if plug then
            fxident = string.lower(TrimStr(CropFXName(plug)))
          end
        end
        local fxi = string.match(fxident,'.+[\\/](.*)')
        fxident = fxi or fxident
        lvar.dm_save_plug = fxident
        OpenEB(5021, 'Please enter strip name (plug id: '..fxident..') :', fxident)
      else
        if fxident then
          local ffn = paths.strips_path..'/'..paths.dmstrip_folder..'/'..fxident..'.strip'
          SaveStrip3(fxident, nil, ffn)

          local sfn = lvar.dm_editmode_data.sfn
          if not plugdefstrips then
            plugdefstrips = {}
            plugdefstrips_idx = {}
          end
          local idx = #plugdefstrips+1

          --get plug name
          local track = GetTrackByName('__LBXEDIT')
          if track and reaper.TrackFX_GetCount(track) == 1 then
            if plugdefstrips_idx[fxident] then
              idx = plugdefstrips_idx[fxident]
            end

            plugdefstrips[idx] = {plug = fxident, stripfile = fxident..'.strip', stripfol = paths.dmstrip_folder}
            plugdefstrips_idx[fxident] = idx
            Save_PlugDefs()
          end

          if reaper.JS_LICE_WritePNG then
            lvar.dm_return_set = true
          else
            local ret_page = lvar.dm_editmode_data.ret_page
            local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
            navigate = true

            if lvar.dm_editmode_data.plist_w == 0 then
              plist_w = lvar.dm_editmode_data.plist_w
              show_editbar = false
              resize_display = true
            end
            lvar.dm_editmode_data = nil

            setmode(1)
            ChangeTrack2(ret_trn, ret_page, true)
            obj = PosTrBtns(obj)
          end
        end
      end
    end

  end

  
  function A_Run_StripAssoc(char)

    if gfx.mouse_wheel ~= 0 then
      local mx, my = mouse.mx - obj.sections[4500].x, mouse.my - obj.sections[4500].y
      local v = mousewheel_val() --(gfx.mouse_wheel/lvar.mousewheel_div)
      if MOUSE_over(obj.sections[4501],mx,my) then
        local rows = math.floor((obj.sections[4501].h) / tb_butt_h) - 1
        lvar.sapd.offset = F_limit(lvar.sapd.offset - rows*v,0,#lvar.sapd)
        lupd.update_stripass = true
        gfx.mouse_wheel = 0
      end
    end

    if MOUSE_click(obj.sections[4500]) or MOUSE_click_RB(obj.sections[4500]) then
      local mx, my = mouse.mx, mouse.my
      mouse.mx, mouse.my = mx - obj.sections[4500].x, my - obj.sections[4500].y
      local butt_h = tb_butt_h

      if MOUSE_click(obj.sections[4501]) then
        local n = math.floor((mouse.my - obj.sections[4501].y) / butt_h) + 1
        local idx = n + lvar.sapd.offset
        if lvar.sapd[idx] then
          lvar.sapd.assoffset = 0
          lvar.sapd.selected = idx
          lvar.sapd.assselected = nil
          lupd.update_stripass = true

          local ffn = paths.strips_path..lvar.sapd[idx].fol..'/'..lvar.sapd[idx].fil
          local fn = string.gsub(ffn,'%.strip$','.png')
          if fn and reaper.file_exists(fn) then

            local ret = gfx.loadimg(976, fn)
            if ret ~= -1 then
              lvar.sapd.preview = 976
            else
              lvar.sapd.preview = nil
            end

          else

            lvar.sapd.preview = nil

          end

          lvar.sapd.stripdata = LoadStripFN_ContentOnly(nil, ffn)

        else
          lvar.sapd.preview = nil
          lvar.sapd.assoffset = 0
          lvar.sapd.selected = nil
          lvar.sapd.assselected = nil
          lvar.sapd.stripdata = nil
          lupd.update_stripass = true
        end


      elseif MOUSE_click(obj.sections[4502]) then
        local n = math.floor((mouse.my - obj.sections[4502].y) / butt_h) + 1
        local idx = n + lvar.sapd.assoffset
        if lvar.sapd[lvar.sapd.selected].assoc[idx] then
          lvar.sapd.assselected = n
          lupd.update_stripass = true
        else
          lvar.sapd.assselected = nil
          lupd.update_stripass = true
        end

      elseif MOUSE_click_RB(obj.sections[4502]) then

        if lvar.sapd.selected and lvar.sapd.assselected and lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected] then
          local mstr = 'Remove Association'
          gfx.x = mx
          gfx.y = my
          local res = gfx.showmenu(mstr)
          if res > 0 then
            if res == 1 then

              PlugDef_RemoveX(lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected], lvar.sapd[lvar.sapd.selected].fil, lvar.sapd[lvar.sapd.selected].fol)
              StripAssoc_RefreshAssData()
              lupd.update_stripass = true

            end
          end
        end

      elseif MOUSE_click(obj.sections[4505]) then

        if lvar.sapd.stripdata and #lvar.sapd.stripdata.fx == 1 and lvar.sapd.selected then
          local fxident = GetPlugIdentifierFromChunk(lvar.sapd.stripdata.fx[1].fxchunk)
          fxident = string.lower(fxident)
          local fnd
          local cnt = #lvar.sapd[lvar.sapd.selected].assoc
          for i = 1, cnt do
            if lvar.sapd[lvar.sapd.selected].assoc[i] == fxident then
              fnd = i
              break
            end
          end
          if not fnd then
            PlugDef_AddX(fxident, lvar.sapd[lvar.sapd.selected].fil, lvar.sapd[lvar.sapd.selected].fol)
            StripAssoc_RefreshAssData()
            lupd.update_stripass = true
          end
        end

      elseif MOUSE_click(obj.sections[4506]) then

        if lvar.sapd.stripdata and #lvar.sapd.stripdata.fx == 1 and lvar.sapd.selected then
          local fxident = GetPlugNameFromChunk3(lvar.sapd.stripdata.fx[1].fxchunk)
          if fxident then
            fxident = TrimStr(CropFXName(fxident))
            fxident = string.lower(fxident)
            PlugDef_AddX(fxident, lvar.sapd[lvar.sapd.selected].fil, lvar.sapd[lvar.sapd.selected].fol, true)
            StripAssoc_RefreshAssData()
            lupd.update_stripass = true
          end
        end

      elseif MOUSE_click(obj.sections[4507]) then

        if lvar.sapd.stripdata and #lvar.sapd.stripdata.fx == 1 and lvar.sapd.selected then
          OpenEB(4507, 'Please enter plugin name to associate with this strip:','')
        end

      elseif MOUSE_click(obj.sections[4508]) then

        if lvar.sapd.selected and lvar.sapd.assselected and lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected] then
          local plug = lvar.sapd[lvar.sapd.selected].assoc[lvar.sapd.assselected]
          PlugDef_SetDefaultX(string.lower(plug), lvar.sapd[lvar.sapd.selected].fil, lvar.sapd[lvar.sapd.selected].fol)
          StripAssoc_RefreshAssData()
          lupd.update_stripass = true
        end

      elseif MOUSE_click(obj.sections[4509]) then
        if lvar.sapd.selected then
          local sfn = lvar.sapd[lvar.sapd.selected].fol..'/'..lvar.sapd[lvar.sapd.selected].fil
          lvar.sapd.stripdata.quickload = not (lvar.sapd.stripdata.quickload or false)
          if not SetStripQuickLoadSetting(sfn,lvar.sapd.stripdata.quickload) then
            lvar.sapd.stripdata.quickload = false
          end
          lupd.update_stripass = true
        end
      end

      mouse.mx = mx
      mouse.my = my
    elseif mouse.LB and not mouse.last_LB then

      Save_PlugDefs()
      lvar.show_stripassoc = false
      lupd.update_gfx = true

    end


  end

  local function ExternalControl()
  
    local extmsg = reaper.GetExtState(lvar.EXTMSG, lvar.EXTMSGKEY)
    --extmsg = '[TEST 1];[TEST 2]0.75;'
    if extmsg ~= '' then
      local eids = lvar.extidentifiers
      for key, val in string.gmatch(extmsg,'%[(.-)%](.-);') do
        if eids[key] then
          local eid = eids[key]
          local ctl = eid.ctl
          if ctl then
            --DBG(key .. '  '..tostring(tonumber(val)))
            ctl.oval = ctl.val
            ctl.val = tonumber(val) or ctl.val
            A_SetParam(eid.strip, eid.page, eid.c, eid.ctl, true)
          end
        end
      end
      reaper.SetExtState(lvar.EXTMSG, lvar.EXTMSGKEY, '', false)
    end
    
  end
  
  function run()
    --DBG(reaper.Audio_IsRunning())
    --DBG()

    local contexts = contexts
    local ctlcats = ctlcats
    local lvar = lvar
    --local lupd = lupd

    local preservecontext
    local rt = reaper.time_precise()

    if lvar.rendersnaps then
    
      if reaper.time_precise() > lvar.rendersnaps.timer then
        RenderSnap2(lvar.rendersnaps.ss, lvar.rendersnaps.fol)
        lvar.rendersnaps.timer = reaper.time_precise() + 1
        lvar.rendersnaps.ss = lvar.rendersnaps.ss +1
        
        local strip = tracks[track_select].strip
        local ss = lvar.rendersnaps.ss
        if ss <= lvar.rendersnaps.snapcnt then
          Snapshot_Set(strip, page, sstype_select, ss, true)
          ss_select = ss
        end
        lupd.update_snaps = true
      else
        --Progress('Press Q to cancel',1)
      end
        
      if lvar.rendersnaps.ss > lvar.rendersnaps.snapcnt then
        lvar.rendersnaps = nil
        Progress('Render Complete',1)
      else
        if reaper.GetExtState(lvar.SCRIPT, 'cancelrender') == '1' then
          lvar.rendersnaps = nil
          reaper.MB('Render cancelled','Snapshot render',0)
        end
        if reaper.JS_Window_Find then
          local hwnd = reaper.JS_Window_Find('- LBX Stripper -', true)
          if hwnd then
            reaper.JS_Window_SetFocus(hwnd)
          end
        end
        local c = gfx.getchar()
        if c == 27 or c == 113 then
          lvar.rendersnaps = nil
          reaper.MB('Render cancelled','Snapshot render',0)
        end
      end
      
      --reaper.defer(run)
      --return
    end

    ReadProjectFlags()

    ------------------------------------------------
    -- PROJECT DATA MONITORING AND SAVING
    ------------------------------------------------

    local PROJNAME = GetProjectName()
    projdirty = reaper.IsProjectDirty()

    if not lvar.striploadoverride_active and ((PROJECTID ~= tonumber(GPES('projectid'))) or newloc) then

      if newloc then
        --SaveData()
        newloc = nil
        DBGOut('*** INIT NEW PROJECT ***')

        INIT(lvar.newloc_preserveid)
        lvar.newloc_preserveid = nil
      else
        DBGOut('*** INIT ***')
        INIT()
      end
      LoadData()

    elseif loadset_fn then

      --SaveData()
      if lsmerge == true then
        LoadSet2(loadset_fn, true)
      else
        INIT(true)
        LoadSet2(loadset_fn)
      end
      loadset_fn = nil

    elseif not lvar.striploadoverride_active and (lastprojdirty ~= projdirty or PROJNAME ~= lastprojname) then

      --local fn = GPES('lbxstripper_datafile', true)
      local pfname = string.sub(PROJNAME,0,string.len(PROJNAME)-4)
      local fn = pfname

      if projdirty == 0 and PROJNAME == lastprojname then
        --project saved
        SaveProj()

      elseif PROJNAME ~= lastprojname then

        DBGOut('*** PROJECT NAME MISMATCH ***')

        local pr_pfx = string.match(PROJNAME,'(.*%_)%d+.*')
        local pr_n = string.match(PROJNAME,'%_(%d+).*')
        local ls_pfx = string.match(lastprojname ,'(.*%_)%d+.*')
        local ls_n = string.match(lastprojname ,'%_(%d+).*')

        local found, fn, ffn, storeddata = FindSaveFile(fn)

        if found == true then
          --load

          INIT()
          LoadData()
          lupd.update_gfx = true
          lastprojdirty = projdirty

        elseif storeddata == true then

          --if lastprojname == nil or lastprojname == '' then
          if (lastprojname or '') == '' then
            SaveProj()
          else
            --[[DBG('still confused')
            DBG('lpn: '..lastprojname)
            DBG(PROJECTID)
            DBG(PROJNAME)]]
          end

        elseif pr_pfx ~= ls_pfx then

          SaveProj()

        elseif (pr_n and ls_n) and pr_n > ls_n then

          SaveProj()

        elseif (pr_n and ls_n) and pr_n < ls_n then

          INIT()
          LoadData()
          lupd.update_gfx = true
          lastprojdirty = projdirty

        else

          if nz(PROJNAME,'') ~= '' then
            SaveProj()
          else
            INIT()
            LoadData()
          end

        end

        lastprojname = PROJNAME
        lupd.update_gfx = true

      end
      lastprojdirty = projdirty

    end

    --[[if not lvar.runonce then
      CheckOversizeImage()
    end]]
    
    if lvar.externalcontrol == true then
      ExternalControl()
    end
    
    ------------------------------------------------
    -- GFX RESIZE
    ------------------------------------------------

    if gfx.w ~= last_gfx_w or gfx.h ~= last_gfx_h or force_resize then
      local r = false
      if not r or gfx.dock(-1) > 0 then
        if not lvar.resizetimer then
          lvar.slotsx = -1
          lvar.slotsy = -1
          if ctl_browser_size then
            lvar.slotsx = ctl_browser_size.slots_x
            lvar.slotsy = ctl_browser_size.slots_y
          end
        end
        gfx1.main_w = gfx.w
        gfx1.main_h = gfx.h
        win_w = gfx.w
        win_h = gfx.h

        last_gfx_w = gfx.w
        last_gfx_h = gfx.h

        if obj then
          if show_editbar == true then
            plist_w = oplist_w
          end
          local ww = gfx1.main_w-obj.sections[19].w-obj.sections[14].w-obj.sections[18].w-obj.sections[1000].w
          if show_snapshots == true and settings_ssdock == true then
            ww = ww - obj.sections[160].w
          end

          plist_w = math.min(plist_w, ww)
          plist_w = math.min(math.max(plist_w,0),lvar.maxdim)

        end

        gui = GetGUI_vars()
        obj = GetObjects()

        show_fsnapshots = false
        show_xysnapshots = false
        resize_display = true
        lupd.update_surface = true
        force_resize = false
        
        mouse.context = contexts.dummy
        lvar.preservecontext = true

        if surface_size.w < obj.sections[10].w then
          surface_offset.x = -math.floor((obj.sections[10].w - surface_size.w)/2)
        end
        if show_striplayout == true then
          if stripgallery_view == 0 then
            striplayout_data = StripLayout_GetData()
            StripLayout_DrawImage(striplayout_data)
          else
            StripLayout_DrawImageGallery(stlay_data)
          end
        end
        if stripgallery_view ~= 0 then
          GUI_DrawCtlBitmap2()
        end

        lvar.resizetimer = rt+0.25
        lvar.resize_check = true
      end

    end
    if lvar.resize_check and not (reaper.JS_Mouse_GetState(1)==1) then
      --if gfx.dock(-1)&1~=1 then
        if (gfx1.main_w > lvar.maxdim or gfx1.main_h > lvar.maxdim) and reaper.JS_Window_Find then
          local hwnd = reaper.JS_Window_Find('- LBX Stripper -', true)
          if hwnd then
            local retval, wleft, wtop, wright, wbottom = reaper.JS_Window_GetRect(hwnd)
            local w, h = math.abs(wright-wleft), math.abs(wbottom-wtop)
            local retval, cwidth, cheight = reaper.JS_Window_GetClientSize(hwnd)
            local dw, dh = w-cwidth, h-cheight
            reaper.JS_Window_Resize(hwnd, math.min(gfx1.main_w,lvar.maxdim)+dw, math.min(gfx1.main_h,lvar.maxdim)+dh)
          end
        end
      --end
      mouse.context = nil
      lvar.preservecontext = nil
      RedrawGUIBitmap()
      lvar.resize_check = nil
    end

    if not lvar.runonce then
      lvar.runonce = true
      
      --[[if lvar.missingTI and lvar.enablelargegui then       
        OpenMsgBox(1,'Transparent_4096.png missing from the resources folder',1,'GUI size limited to 2048 pixels')
        lupd.update_gfx = true
      end]]
      
      if lvar.livemode == 2 then
        local seltr = reaper.GetSelectedTrack2(0,0, true)
        if seltr and (lvar.dynamicmode_trn == nil or seltr ~= GetTrack(math.max(lvar.dynamicmode_trn,-1))) then
          DM_AddStrips()
        end
      end

    end

    if rt >= (lvar.resizetimer or 9999999) then
      --local slsz = 100
      --local slots_x = 2 --math.max(math.min(math.floor((ctl_browser_size.w - 20) / slsz),2),2)
      --local slots_y = math.max(math.min(math.floor((ctl_browser_size.h/2 - (butt_h+2)*2 -20) / slsz),8),1)
      --check size
      if lvar.ctlbrowser_docked and (lvar.slotsx ~= ctl_browser_size.slots_x or lvar.slotsx ~= ctl_browser_size.slots_y) then
        lvar.cbi_loaded = nil
        lupd.update_surface = true
      end
      lvar.resizetimer = nil
    end

    if rt >= time_nextupdate_pkmeter then
      --[[for tr = -1, reaper.CountTracks(0)-1 do
        get_peak_info(tr)
      end]]
      local rp = lvar.readpeaks
      if #rp > 0 then
        for i = 1, #rp do
          get_peak_info(rp[i])
        end
      end

      if lvar.readpeaks_sel == 1 or lvar.livemode == 2 then
        local tr = reaper.GetSelectedTrack2(0,0,true)
        if tr then
          trn = reaper.GetMediaTrackInfo_Value(tr,'IP_TRACKNUMBER')
          if rp.idx and not rp.idx[trn-1] then
            get_peak_info(trn-1)
          end
        end
      end
    end

    local ct = reaper.CountTracks(0)
    if ct ~= otrkcnt then
      PopulateTracks()
      lupd.update_gfx = true

      if ct > otrkcnt then
        TrackLabelCheck()
      end

      otrkcnt = ct
      local st = reaper.GetSelectedTrack(0,0)
      if st == nil then
        track_select = -1
      end
      CheckGlobalTrackSel()
      CheckStripSends()
      PopulateTrackSendsInfo()
    else
      if LBX_GTRACK and gpage == true then
        CheckGlobalTrackSel()
      end
    end

    if lvar.livemode == 2 and lvar.autoswipe then
      lupd.update_surface = true
    end
    
    lupd = GUI_draw(obj, gui)

    local noscroll = false
    --[[if lvar.dm_editmode_data and mode == 0 then
      navigate = false
    end]]
    if lvar.livemode == 2 and lvar.autoswipe then
      local spos = lvar.spos[lvar.autoswipe.swid]
      if spos then
        local pos
        local rp = spos.rp*lvar.zoom
        if lvar.mixmodedir == 0 then
          local o10h = obj.sections[10].h
          pos = (surface_offset.mixy or 0)*lvar.zoom
          if pos > rp --[[ (spos.h+spos.sh)*lvar.zoom]] then
            surface_offset.mixy = math.floor(rp/lvar.zoom) --+ (spos.h+lvar.mmgap+spos.sh))
            lupd.update_gfx = true
          elseif pos+o10h < rp + (spos.h+spos.sh)*lvar.zoom then
            surface_offset.mixy = math.floor((rp - o10h)/lvar.zoom + spos.h+spos.sh)
            lupd.update_gfx = true
          end          
        else
          local o10w = obj.sections[10].w
          pos = (surface_offset.mixx or 0)*lvar.zoom
          if pos > rp --[[ math.max(spos.w, spos.sw)*lvar.zoom]] then
            surface_offset.mixx = math.floor((rp)/lvar.zoom)
            lupd.update_surface = true
          elseif pos+o10w < rp + math.max(spos.w, spos.sw)*lvar.zoom then
            surface_offset.mixx = math.floor((rp - o10w)/lvar.zoom + math.max(spos.w, spos.sw))
            lupd.update_surface = true
          end
        end
      end
      lvar.autoswipe = nil
    end

    mouse.mx, mouse.my = gfx.mouse_x, gfx.mouse_y
    mouse.smx, mouse.smy = reaper.GetMousePosition()
    if lvar.mac_coord_hack and (OS == "OSX64" or OS == "OSX32") then
      mouse.smx, mouse.smy = mouse.mx, mouse.my
    end
    if gfx.mouse_cap == 0 then
      mouse.release = nil
    end
    if not mouse.release then
    mouse.LB = gfx.mouse_cap&1==1
    mouse.RB = gfx.mouse_cap&2==2
    mouse.MB = gfx.mouse_cap&64==64
    end
    if mouse.altlatch and not mouse.alt then
      mouse.altlatch = nil
    end
    mouse.ctrl = gfx.mouse_cap&4==4
    mouse.shift = gfx.mouse_cap&8==8
    mouse.alt = gfx.mouse_cap&16==16

    if lvar.openmenu then
      lvar.openmenu.func()
      lvar.openmenu = nil
    end

    local char
    if EB_Open == 0 and MS_Open == 0 then
      char = gfx.getchar()
      if char ~= 0 then
        --need to check if xxy/trackfxorder open?
        if show_midiout == false and show_trackfxorder == false and show_xxy == false and show_dd == false then
          char = keypress(char)
        end
      end

    elseif MS_Open > 0 then

      Process_MB()

    elseif EB_Open > 0 then

      mouse.context = Process_EB(mouse.context)

      noscroll = true
      if mouse.LB == true and mouse.context ~= nil then
        preservecontext = true
      end
      mouse.LB = nil
      mouse.RB = nil
    end

    ----------------
    
      --[[if MC() or gfx.mouse_wheel ~= 0 then
        gfx.dest = guibitmap
        gfx.x = mouse.mx
        gfx.y = mouse.my
        local r,g,b = gfx.getpixel()
        local rgb = (r*255) + ((g*255) << 8) + ((b*255) << 16)
        if not lvar.guibmp then
          RedrawGUIBitmap2()
        end
        local guibmp = lvar.guibmp[lvar.guibmp.idx[rgb] ]        
        if guibmp then
          if guibmp.funcRun then
            noscroll = guibmp.funcRun(rt, noscroll)
          end
        end
      end]]
    
    ----------------
    if tonumber(mouse.context) and mouse.context >= 5000 then
      A_Run_XPnlContext()
    elseif mouse.xpnlcontext then
      A_Run_XPnlContext_End()
    end
    
    if show_dd and mouse.context == nil then
      A_Run_DropDown()
    end

    if show_trackfxorder then

      UpdateControlValues3(rt, ctls_upd, ctls_orr)
      char = A_Run_TFXOrder(char, rt)
      if mode == 0 and show_pinmatrix == true then
        noscroll = A_Run_PinMatrix(noscroll, rt, char)
      end

    elseif show_midiout then

      UpdateControlValues3(rt, ctls_upd, ctls_orr)
      A_Run_MidiOut(char)

    elseif lbx_midilrnctl then

      UpdateControlValues3(rt, ctls_upd, ctls_orr)
      A_Run_MidiLrn(char)

    elseif show_xxy == false then

      if settings_followselectedtrack and navigate and gpage == false then

        FollowTrack(ct)

      end

      local checksends = false
      if settings_disablesendchecks == false and rt >= time_checksend then
        time_checksend = rt + 2
        checksends = true
      end

      UpdateControlValues3(rt, ctls_upd, ctls_orr)

      if show_settings then

        Process_Settings()

      elseif lvar.show_stripassoc then

        A_Run_StripAssoc(char)

      else

        local sb_fullscreen = (show_stripbrowser and lvar.stripbrowser.fullscreen)
        if not sb_fullscreen and (mouse.LB and not mouse.lastLB) or (mouse.RB and not mouse.lastRB) then
          if show_eqcontrol ~= true and macro_edit_mode ~= true and MOUSE_clickXY(obj.sections[21],plist_w,0 ) and (hide_topbar == false or settings_showminimaltopbar) then

            TopMenu()
            mouse.context = contexts.dummy

          elseif MOUSE_clickXY(obj.sections[14],plist_w,0) and navigate then
            --page
            if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
              if track_select ~= LBX_GTRACK then
                local page = F_limit(math.ceil((mouse.mx-(obj.sections[14].x+plist_w))/(obj.sections[14].w/lvar.maxpage)),1,lvar.maxpage)
                SetPage(page)
              end
            end

          elseif MOUSE_clickXY(obj.sections[1000],plist_w,0) and navigate then
            --page
            SetGlobalPage()

          elseif MOUSE_click_RB(obj.sections[11]) then

            --if mouse.shift and mouse.ctrl then
            --  lvar.livemode = 2
            --else
              if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
                SetLiveMode(math.max(1 - (lvar.livemode or 0),0), track_select, page, surface_offset.mixx, surface_offset.mixy)
              end
              --[[lvar.livemode = math.max(1 - (lvar.livemode or 0),0)
              if lvar.livemode >= 1 then
                GUI_DrawCtlBitmap_Mix()
              end
            --end
            lvar.glivemode = lvar.livemode
            lupd.update_gfx = true]]

          elseif MOUSE_click(obj.sections[11]) then

            if mouse.mx > obj.sections[11].w-6 then
              mouse.context = contexts.dragsidebar
              offx = 0
            else
              if lvar.livemode == 2 then
                if lvar.dm_editmode_data then

                end
              else
                if mode == 0 then
                  if submode == 0 then
                    if fxmode == 0 then
                      setmode(2)
                    else
                      setmode(3)
                    end
                  elseif submode == 1 then
                    setmode(4)
                  else
                    setmode(5)
                  end
                else
                  setmode(1)
                end
              end
            end

          elseif MOUSE_click(obj.sections[13]) and plist_w >= 160 then

            if mode == 0 then
              local w = math.floor(obj.sections[13].w / 3)
              local xp = math.floor((mouse.mx - obj.sections[11].x) / w)
              if xp == 0 then
                mode0_submode = 0
                lupd.update_gfx = true
              elseif xp == 1 then
                mode0_submode = 1
                lupd.update_gfx = true
              else
                mode0_submode = 2
                lupd.update_gfx = true
              end
            else
              local w = math.floor(obj.sections[13].w / 4)
              local xp = math.floor((mouse.mx - obj.sections[13].x) / w)
              if xp == 0 then
                setmode(4)
              elseif xp == 1 then
                setmode(2)
              elseif xp == 2 then
                setmode(3)
              elseif xp == 3 then
                setmode(5)
              end

            end

          elseif MOUSE_click(obj.sections[13]) and plist_w < 160 then

            if mode == 0 then
              mode0_submode = mode0_submode+1
              if mode0_submode > #lvar.mode0_submode_table-1 then
                mode0_submode = 0
              end
              lupd.update_gfx = true
            end


          elseif MOUSE_click_RB(obj.sections[13]) and plist_w < 160 then

            if mode == 0 then
              mode0_submode = mode0_submode-1
              if mode0_submode < 0 then
                mode0_submode = #lvar.mode0_submode_table-1
              end
              lupd.update_gfx = true
            end

          elseif MOUSE_clickXY(obj.sections[18],plist_w,0) and (hide_topbar == false or settings_showminimaltopbar) then
            if mode == 1 then
              mouse.context = contexts.dragsidebar
              offx = mouse.mx-plist_w
            else
              ToggleSidebar()
            end

          elseif (obj.sections[17].x > obj.sections[20].x+obj.sections[20].w) and MOUSE_clickXY(obj.sections[17],plist_w,0) then
            SaveProj(true, true)
            OpenMsgBox(1,'Data Saved.',1)
            lupd.update_surface = true

          elseif MOUSE_clickXY(obj.sections[20],plist_w,0) then
            local butt = F_limit(math.ceil((mouse.mx-(obj.sections[20].x+plist_w))/(obj.sections[20].w/4)),1,4)
            if butt == 1 then
              LockX()

            elseif butt == 2 then
              LockY()

            elseif butt == 3 then
              ScrollUp()

            elseif butt == 4 then
              ScrollDown()

            end
            lupd.update_gfx = true
          end

        elseif not sb_fullscreen and (mouse.MB and not mouse.last_MB) then

          if snap_edit_mode ~= true and macro_edit_mode ~= true and show_pinmatrix ~= true and show_eqcontrol ~= true and MOUSE_over(obj.sections[10]) then
            local o = 2000
            if stripgallery_view == 1 or settings_pagescrolldir == 1 then
              o = 2001
            end

            obj.sections[o].x = mouse.mx-obj.sections[o].w/2
            obj.sections[o].y = mouse.my-obj.sections[o].h/2
            show_arrowupdn = not show_arrowupdn
            moupdn_img = 0
            omoupdn_img = 0
            lupd.update_surface = true
          end

        end

        if mouse.context and mouse.context == contexts.dragsidebar then

          plist_w = math.max(mouse.mx-offx,0)
          plist_w = math.min(plist_w, gfx1.main_w-obj.sections[19].w-obj.sections[14].w-obj.sections[18].w)
          oplist_w = math.max(plist_w,100)
          if plist_w <= 4 then
            show_editbar = false
          else
            show_editbar = true
          end
          obj = GetObjects()
          resize_display = true
          lupd.update_surface = true

        end

        local moupdn = false
        local o = 2000
        if stripgallery_view == 1 or settings_pagescrolldir == 1 then
          o = 2001
        end
        if show_arrowupdn and MOUSE_over(obj.sections[o]) then
          if moupdn_timer and reaper.time_precise() > moupdn_timer then
            moupdn_img = 0
            lupd.update_surface = true
            moupdn_timer = nil
          end
          moupdn = true
        end

        if show_arrowupdn and not moupdn then

          show_arrowupdn = false
          lupd.update_surface = true

        elseif show_arrowupdn and moupdn then

          noscroll = true

          if lvar.popswipe then
            MixMode_Swiping_Pop()
          end

          if gfx.mouse_wheel ~= 0 then
            local v = mousewheel_val() --gfx.mouse_wheel/lvar.mousewheel_div
            if v > 0 then
              moupdn_img = 1
            else
              moupdn_img = 2
            end
            
            moupdn_timer = reaper.time_precise() + 0.2
            omoupdn_img = moupdn_img
            if lvar.livemode == 2 then
              if lvar.showpop and lvar.popout_autoarrange and mode == 0 then
                MixMode_Swipe_Pop(1-(moupdn_img-1), false)
              end
            else
              if stripgallery_view == 0 then
                if settings_pagescrolldir == 0 then
                  surface_offset.y = F_limit(surface_offset.y - v*50,0,surface_size.h-obj.sections[10].h)
                else
                  surface_offset.x = F_limit(surface_offset.x - v*50,0,surface_size.w-obj.sections[10].w)
                end
              else
                local min = math.floor(0-(obj.sections[10].w/2 - stlay_data.loc[1].w/2))
                local max = math.floor(stlay_data.loc[#stlay_data.loc].runx_e-obj.sections[10].w + (obj.sections[10].w/2 - stlay_data.loc[#stlay_data.loc].w/2))
                stlay_data.xpos = F_limit(stlay_data.xpos - v*50,min,max)
                if strips and tracks[track_select] and strips[tracks[track_select].strip] then
                  strips[tracks[track_select].strip][page].xpos = stlay_data.xpos
                end
                GUI_DrawCtlBitmap2()
                --stlay_data.xpos = stlay_data.xpos - v*50
              end
            end
            lupd.update_surface = true
            gfx.mouse_wheel = 0

          elseif mouse.LB and not mouse.last_LB then

            if lvar.livemode == 2 or stripgallery_view == 0 or mode == 1 then
              if lvar.livemode == 2 then
                if lvar.showpop and lvar.popout_autoarrange and mode == 0 then
                  local dir = 0
                  local my = mouse.my-obj.sections[2000].y
                  moupdn_img = 2
                  if my < obj.sections[2000].h/2 then
                    dir = 1
                    moupdn_img = 1
                  end
                  MixMode_Swipe_Pop(dir, false)
                end
              else
                if settings_pagescrolldir == 0 then
                  local my = mouse.my-obj.sections[2000].y
                  if my < obj.sections[2000].h/2 then
                    moupdn_img = 1
                    surface_offset.y = F_limit(surface_offset.y - obj.sections[10].h,0,surface_size.h-obj.sections[10].h)
                  else
                    moupdn_img = 2
                    surface_offset.y = F_limit(surface_offset.y + obj.sections[10].h,0,surface_size.h-obj.sections[10].h)
                  end
                else
                  local mx = mouse.mx-obj.sections[2001].x
                  if mx < obj.sections[2001].w/2 then
                    moupdn_img = 1
                    surface_offset.x = F_limit(surface_offset.x - obj.sections[10].w,0,surface_size.w-obj.sections[10].w)
                  else
                    moupdn_img = 2
                    surface_offset.x = F_limit(surface_offset.x + obj.sections[10].w,0,surface_size.w-obj.sections[10].w)
                  end
                end
              end
            else
              local mx = mouse.mx-obj.sections[2001].x
              if mx < obj.sections[2001].w/2 then
                if mode == 0 and show_striplayout == false and stripgallery_view == 1 then
                  moupdn_img = 1
                  GallerySwipe(0)
                  lupd.update_gfx = true
                end
              else
                if mode == 0 and show_striplayout == false and stripgallery_view == 1 then
                  moupdn_img = 2
                  GallerySwipe(1)
                  lupd.update_gfx = true
                end
              end
            end
            omoupdn_img = moupdn_img
            moupdn_timer = reaper.time_precise() + 0.2
            lupd.update_surface = true

          end

          if mode == 0 then

            if striplayout_mt then
              striplayout_mp = 1-(((striplayout_mt-reaper.time_precise()))/striplayout_mtime)
              if striplayout_mp >= 1 then
                striplayout_mp = 1
                striplayout_mt = nil
              else
                striplayout_mp = macScale(4,striplayout_mp)
              end
              lupd.update_surface = true

            elseif stripgallery_swipemt then
              stripgallery_swipe.mp = 1-(((stripgallery_swipemt-reaper.time_precise()))/striplayout_mtime)
              if stripgallery_swipe.mp >= 1 then
                stripgallery_swipe.mp = 1
                stripgallery_swipemt = nil
                stlay_data.xpos = stripgallery_swipe.xend
                strips[tracks[track_select].strip][page].xpos = stripgallery_swipe.xend
                GUI_DrawCtlBitmap2()
              else
                stripgallery_swipe.mp = macScale(3,stripgallery_swipe.mp)
              end
              lupd.update_surface = true
            end

          end

        elseif mode == 0 then

          if lvar.dm_editmode_data and (MOUSE_click(obj.sections[5020]) or MOUSE_click(obj.sections[5021]) or MOUSE_click(obj.sections[5022])) and
             not show_pinmatrix and not show_xxy and not show_eqcontrol and not macro_edit_mode then

            if MOUSE_click(obj.sections[5022]) then

              CentreAllControls(track_select)

            elseif MOUSE_click(obj.sections[5021]) then
              --discard
              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                
                local ret_page = lvar.dm_editmode_data.ret_page
                local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
                navigate = true

                if lvar.dm_editmode_data.plist_w == 0 then
                  plist_w = lvar.dm_editmode_data.plist_w
                  show_editbar = false
                  resize_display = true
                end
                lvar.dm_editmode_data = nil

                setmode(1)
                ChangeTrack2(ret_trn, ret_page, true)
                obj = PosTrBtns(obj)
              end

            elseif MOUSE_click(obj.sections[5020]) then
              --save
              DM_SaveStrip()

            end

          else

            noscroll = A_Run_Mode0(noscroll, rt)

          end

          if lvar.ss3_bmp and not lvar.ss3_bmp.pause and reaper.time_precise() > lvar.ss3_bmp.delay then
            SaveStrip_CreateThumb2(lvar.ss3_bmp)
            lvar.ss3_bmp = nil
          end

        elseif mode == 1 then

          reaper.MarkProjectDirty(0)
          show_fsnapshots = false

          if ct == 0 and track_select ~= -1 then
            --track_select = -1
            ChangeTrack(-1)
            lupd.update_gfx = true
          end

          local tr = GetTrack(trackedit_select)
          if tr then
            local fxc = TrackFX_GetCount(tr)
            if fxc ~= ofxcnt then
              PopulateTrackFX()
              lupd.update_gfx = true
            end
          end

          --DBG(ogrid..'  '..settings_gridsize..'  '..tostring(lvar.grid))

          if mouse.shift and not mouse.ctrl then
            if settings_gridsize ~= 1 then
              settings_gridsize = 1
              lupd.update_gfx = true
            end
          elseif lvar.grid ~= false then
            if settings_gridsize ~= ogrid then
              settings_gridsize = ogrid
              lupd.update_gfx = true
            end
          end

          if strips and tracks[track_select] and strips[tracks[track_select].strip] and #strips[tracks[track_select].strip][page].controls > 0 then
            CheckTrack(strips[tracks[track_select].strip].track, tracks[track_select].strip)
          end

          g_edstrips[track_select] = true

          if lvar.dm_editmode_data and (MOUSE_click(obj.sections[5020]) or MOUSE_click(obj.sections[5021]) or MOUSE_click(obj.sections[5022])) then

            if MOUSE_click(obj.sections[5022]) then

              CentreAllControls(track_select)

            elseif MOUSE_click(obj.sections[5021]) then
              --discard
              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
              
                local ret_page = lvar.dm_editmode_data.ret_page
                local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
                navigate = true
  
                if lvar.dm_editmode_data.plist_w == 0 then
                  plist_w = lvar.dm_editmode_data.plist_w
                  show_editbar = false
                  resize_display = true
                end
                lvar.dm_editmode_data = nil
  
                setmode(1)
                ChangeTrack2(ret_trn, ret_page, true)
                obj = PosTrBtns(obj)
              end
              
            elseif MOUSE_click(obj.sections[5020]) then
              --save
              DM_SaveStrip()

            end

          elseif submode == 0 then

            noscroll = A_Run_Submode0(noscroll, rt, char)

          elseif submode == 1 then

            --if lvar.grid ~= false then
            --  settings_gridsize = ogrid or settings_gridsize
            --end
            noscroll = A_Run_Submode1(noscroll, rt, char)

          elseif submode == 2 then

            noscroll = A_Run_Submode2(noscroll, rt, char)

          end

          if lvar.ss3_bmp and not lvar.ss3_bmp.pause and reaper.time_precise() > lvar.ss3_bmp.delay then
            SaveStrip_CreateThumb2(lvar.ss3_bmp)
            lvar.ss3_bmp = nil
          end

          if MOUSE_click(obj.sections[13]) then
            if plist_w < 160 then
              if submode ~= 0 or (submode == 0 and mouse.mx < obj.sections[13].x + obj.sections[13].w - 30) then
                if submode == 0 then
                  setmode(4)
                elseif submode == 1 then
                  setmode(5)
                elseif submode == 2 then
                  if fxmode == 0 then
                    setmode(2)
                  else
                    setmode(3)
                  end
                end
              elseif submode == 0 and mouse.mx > obj.sections[13].x + obj.sections[13].w - 30 then
                if fxmode == 0 then
                  setmode(3)
                else
                  setmode(2)
                end

              end
            else

              local x = math.floor((mouse.mx - obj.sections[13].x) / (plist_w/4))
              if x == 0 then
                setmode(5)
              elseif x == 1 then
                setmode(2)
              elseif x == 2 then
                setmode(3)
              elseif x == 3 then
                setmode(4)
              end
            end
          elseif MOUSE_click_RB(obj.sections[13]) and plist_w < 160 then
            if submode == 2 then
              setmode(4)
            elseif submode == 0 then
              setmode(5)
            elseif submode == 1 then
              if fxmode == 0 then
                setmode(2)
              else
                setmode(3)
              end
            end

          end
        end

        if surface_scroll then
        
          local t = reaper.time_precise()
          local dt = math.min((t - surface_scroll.st)/(surface_scroll.et - surface_scroll.st),1)
          if surface_scroll.srcx ~= surface_scroll.dstx then
            surface_offset.x = surface_scroll.srcx + (surface_scroll.dstx - surface_scroll.srcx)*dt
          end
          if surface_scroll.srcy ~= surface_scroll.dsty then
            surface_offset.y = surface_scroll.srcy + (surface_scroll.dsty - surface_scroll.srcy)*dt
          end
          lupd.update_surface = true
          if dt >= 1 then
            surface_scroll = nil
          end

        elseif mouse.context == nil and keycontext == nil then
          if ((submode == 0 and ctl_select ~= nil) and (MOUSE_click(obj.sections[45]) or (MOUSE_click(obj.sections[100]) and show_cycleoptions)
              or (MOUSE_click(obj.sections[200]) and show_ctlbrowser)) or (MOUSE_click(obj.sections[800]) and show_gaugeedit)) or
             ((submode == 1 and gfx4_select ~= nil) and (MOUSE_over(obj.sections[49]) and (show_lbloptions == true or show_gfxoptions == true))) then

          elseif mouse.mx > obj.sections[10].x and show_actionchooser == false then
            if MOUSE_click(obj.sections[10]) then
              if noscroll == false then
                mouse.context = "dragsurface"
                local strip = tracks[track_select].strip
                local pop
                if strip and strips[strip] then
                  pop = strips[strip][page].pop
                end
                if lvar.livemode == 0 or mode ~= 0 or macro_lrn_mode or snaplrn_mode then
                  surx = surface_offset.x
                  sury = surface_offset.y
                else
                  if lvar.showpop == true and pop and #pop > 0--[[and lvar.popout_autoarrange]] then
                    surx = lvar.pop_xoff
                    sury = lvar.pop_yoff
                  else
                    surx = surface_offset.mixx or 0
                    sury = surface_offset.mixy or 0
                  end
                end
                if stlay_data then
                  gsurx = stlay_data.xpos or 0
                end
                mmx = mouse.mx
                mmy = mouse.my
                lupd.update_surface = true

                lvar.mixupdate = nil
              end

              if show_gaugeedit ~= true and cb_clicked ~= true then
                ClearSelected(ctl_select, gfx3_select, gfx4_select)
              
                ctl_select = nil
                show_cycleoptions = false
                showctlbrowser(false)
                --[[if not lvar.ctlbrowser_docked then
                  show_ctlbrowser = false
                end]]
                gfx2_select = nil
                gfx3_select = nil
                gfx4_select = nil
                gfx4_selectidx = nil
              else
                show_gaugeedit = false
                cb_clicked = nil
              end

              if mode ~= 0 then
                lupd.update_surface = true
              end
            end

          end
        end


        if mouse.context and mouse.context == "dragsurface" then
          if noscroll == false and settings_locksurface == false then

            if (lvar.livemode == 0 and stripgallery_view == 0) or mode ~= 0 or macro_lrn_mode == true or snaplrn_mode == true then
              local offx, offy
              if lockx == false or lvar.livemode ~= 0 then
                offx = MOUSE_surfaceX(obj.sections[10])
                if offx then
                  offx = math.floor(offx/lvar.zoom)
                end
              end
              if locky == false or lvar.livemode ~= 0 then
                offy = MOUSE_surfaceY(obj.sections[10])
                if offy then
                  offy = math.floor(offy/lvar.zoom)
                end
              end
              --DBG(tostring(offx)..'  '..tostring(offy))
              if surface_size.w < obj.sections[10].w/lvar.zoom then
                surface_offset.x = 0 --math.floor(((obj.sections[10].w/lvar.zoom) - surface_size.w)/2)
              elseif offx ~= nil then
                surface_offset.x = F_limit(surx + offx,0,surface_size.w - math.floor(obj.sections[10].w/lvar.zoom))
              end

              if surface_size.h < obj.sections[10].h/lvar.zoom then
                surface_offset.y = 0
              elseif offy ~= nil then
                surface_offset.y = F_limit(sury + offy,0,surface_size.h - math.floor(obj.sections[10].h/lvar.zoom))
              end

              if surface_offset.oldx ~= surface_offset.x or surface_offset.oldy ~= surface_offset.y or (ctls and not ctl_select) then
                surface_offset.oldx = surface_offset.x
                surface_offset.oldy = surface_offset.y

                if strips and tracks[track_select] and strips[tracks[track_select].strip] then
                  strips[tracks[track_select].strip][page].surface_x = surface_offset.x
                  strips[tracks[track_select].strip][page].surface_y = surface_offset.y
                end
                if surface_offset.x < 0 or surface_offset.y < 0
                    or surface_offset.x > surface_size.w-obj.sections[10].w
                    or surface_offset.y > surface_size.h-obj.sections[10].h then
                  lupd.update_surfaceedge = true
                end
                lupd.update_surfaceedge = true
                lupd.update_surface = true
              end

            elseif lvar.livemode >= 1 then
              local strip = tracks[track_select].strip
              local pop
              if strip and strips[strip] then
                pop = strips[strip][page].pop
              end
              if lvar.showpop == true and pop and #pop >0--[[and lvar.popout_autoarrange]] then
              
                local setposx, setposy
                local offx, offy
                offy = MOUSE_surfaceY(obj.sections[10])
                offx = MOUSE_surfaceX(obj.sections[10])
                if offy then
                  offy = math.floor(offy/lvar.zoom)
                  if offy ~= lvar.ds_offy then
                    lvar.ds_offy = offy
                    setposy = (sury or 0) - offy*lvar.zoom
                    lupd.update_surface = true
                    dragsurf = true
                  end
                end
                if offx then
                  offx = math.floor(offx/lvar.zoom)
                  if offx ~= lvar.ds_offx then
                    lvar.ds_offx = offx
                    setposx = (surx or 0) - offx*lvar.zoom
                    lupd.update_surface = true
                    dragsurf = true
                  end
                end
                if setposx or setposy then
                  Pop_SetPos(setposx, setposy)
                end
              
              else
                if lvar.mixmodedir == 0 then
                  local offy
                  offy = MOUSE_surfaceY(obj.sections[10])
                  if offy then
                    offy = math.floor(offy/lvar.zoom)
                    if offy ~= lvar.ds_offy then
                      lvar.ds_offy = offy
                      surface_offset.mixy = (sury or 0) + offy --F_limit(sury + offy,0,surface_size.h - obj.sections[10].h)
                      lupd.update_surface = true
                      dragsurf = true
                    end
                  end
                else
                  local offx
                  offx = MOUSE_surfaceX(obj.sections[10])
                  if offx then
                    offx = math.floor(offx/lvar.zoom)
                    if offx ~= lvar.ds_offx then
                      lvar.ds_offx = offx
                      surface_offset.mixx = (surx or 0) + offx --F_limit(sury + offy,0,surface_size.h - obj.sections[10].h)
                      lupd.update_surface = true
                      dragsurf = true
                    end
                  end
                end
              end
            else

              local offx = MOUSE_surfaceX2(obj.sections[10])
              if offx and stlay_data and #stlay_data.loc > 0 then
                local min = math.floor(0-(obj.sections[10].w/2 - stlay_data.loc[1].w/2))
                local max = math.floor(stlay_data.loc[#stlay_data.loc].runx_e-obj.sections[10].w + (obj.sections[10].w/2 - stlay_data.loc[#stlay_data.loc].w/2))
                stlay_data.xpos = F_limit(gsurx + offx,min,max)
                if strips and tracks[track_select] and strips[tracks[track_select].strip] then
                  strips[tracks[track_select].strip][page].xpos = stlay_data.xpos
                end
                lupd.update_surface = true
                dragsurf = true
              end
            end
          end
        elseif mouse.context == nil and dragsurf then
          dragsurf = nil
          GUI_DrawCtlBitmap2()
          if lvar.livemode >= 1 then
            GUI_DrawCtlBitmap_Mix()
          end
        end

        if (settings_mousewheelknob == false or mouse.ctrl and not mouse.shift) and gfx.mouse_wheel ~= 0 and show_ctlbrowser == false and show_cycleoptions == false and show_ctloptions == false then
          if noscroll == false then
            if (lvar.livemode ~= 0 or lockx == false or locky == false) then
              local v = mousewheel_val() --gfx.mouse_wheel/lvar.mousewheel_div
              if mouse.mx > obj.sections[10].x and MOUSE_over(obj.sections[10]) then
                if ctl_select then
                  ClearSelected(ctl_select)
                  
                  ctl_select = nil
                  lupd.update_gfx = true
                end
                if lvar.livemode ~= 0 then
                  if lvar.mixmodedir == 0 then
                    --surface_offset.mixy = F_limit((surface_offset.mixy or 0) - v * 50, 0-math.floor(obj.sections[10].h/(2*lvar.zoom)), lvar.mixpos_max-math.floor(obj.sections[10].h/(2*lvar.zoom)))
                    if v > 0 then v = 1 else v = -1 end
                    MixMode_Swipe((lvar.centrepos or 0), (lvar.centrepos or 0)-v, true)
                  else
                    --surface_offset.mixx = F_limit((surface_offset.mixx or 0) + v * 50, 0-math.floor(obj.sections[10].w/(2*lvar.zoom)), lvar.mixpos_max-math.floor(obj.sections[10].w/(2*lvar.zoom)))
                    if v > 0 then v = 1 else v = -1 end
                    MixMode_Swipe((lvar.centrepos or 0), (lvar.centrepos or 0)-v, true)
                  end
                  SetCtlBitmapRedraw()
                else
                  if locky then
                    surface_offset.x = F_limit(surface_offset.x - v * 50,0,surface_size.w - obj.sections[10].w)
                  elseif lockx then
                    surface_offset.y = F_limit(surface_offset.y - v * 50,0,surface_size.h - obj.sections[10].h)
                  else
                    surface_offset.y = F_limit(surface_offset.y - v * 50,0,surface_size.h - obj.sections[10].h)
                  end
                end
                if strips and tracks[track_select] and strips[tracks[track_select].strip] then
                  strips[tracks[track_select].strip][page].surface_x = surface_offset.x
                  strips[tracks[track_select].strip][page].surface_y = surface_offset.y
                end
                if surface_offset.x < 0 or surface_offset.y < 0
                    or surface_offset.x > surface_size.w-obj.sections[10].w
                    or surface_offset.y > surface_size.h-obj.sections[10].h then
                  lupd.update_surfaceedge = true
                end
                lupd.update_surface = true
              end
            end
          else
            if ctl_select then
              ClearSelected(ctl_select)
              
              ctl_select = nil
              lupd.update_gfx = true
            end

          end
          gfx.mouse_wheel = 0
        end

      end

    else --XXY MODE

      A_Run_XXYMode(rt)

    end
    if not mouse.LB and not mouse.RB and not preservecontext and not lvar.preservecontext --[[and not reaper.JS_Mouse_GetState(1)==1]] then mouse.context = nil end

    if mouse.context == nil then
      if lvar.scrollbar_clear then
        lvar.scrollbar_clear = nil
        lupd.update_sidebar = true
        lupd.update_snaps = true
        lupd.update_samplemanager = true
      end

      if (lvar.TSM_MOver == true) then

        --if lvar.TSM_MOver then
          if lvar.TSM_FocusHwnd then
            reaper.JS_Window_SetFocus(lvar.TSM_FocusHwnd)
          end
          if lvar.TSM_LegalMP then
            reaper.JS_Mouse_SetPosition(lvar.TSM_LegalMP.x, lvar.TSM_LegalMP.y)
          end
          lvar.TSM_MOver = nil
        --end
      end
    end
    --[[if mouse.context == nil and undotxt then
      reaper.Undo_OnStateChange2(0, undotxt)
      reaper.Undo_EndBlock2(0,undotxt, -1)
      undotxt = nil
    end]]
    if show_cycleoptions == false then cycle_editmode = false end

    if settings_disablefaderautomationineditmode == false or mode == 0 then

      ReadAutomationFaders()

    end

    if #morph_data > 0 then
      A_RunMorph()
    end
    if #snapstage_data > 0 then
      A_RunSnapStage()
    end

    A_RunMod()

    if rcmrefreshtimercount > 0 then
      RCMRefresh()
    end

    if char then
      if char == 32 then reaper.Main_OnCommandEx(40044, 0,0) end
      if char>=0 and not (char==27 and not mouse.ctrl) then reaper.defer(run) end
    else
      reaper.defer(run)
    end

    gfx.update()
    mouse.last_LB = mouse.LB
    mouse.last_MB = mouse.MB
    mouse.last_RB = mouse.RB
    mouse.last_x = mouse.mx
    mouse.last_y = mouse.my
    if mouse.LB then
      mouse.lastLBclicktime = rt
    end
    gfx.mouse_wheel = 0
    if ctl_select then ctls = true else ctls = false end
    
    if next(lvar.delayfunction) then
      local reaper = reaper
      local df = lvar.delayfunction
      if lvar.delayfunction.ebopen and reaper.time_precise() >= lvar.delayfunction.ebopen then
        lvar.delayfunction.ebopen = nil
      end
      --if lvar.delayfunction.closectlbrowser then lvar.delayfunction.closectlbrowser = nil showctlbrowser(false) end
      if df.closegaugeedit then df.closegaugeedit = nil show_gaugeedit = false end
      if df.redraw_ctlbitmap and reaper.time_precise() >= df.redraw_ctlbitmap then
        df.redraw_ctlbitmap = nil
        GUI_DrawCtlBitmap()
      elseif df.redraw_ctlbitmapmix and reaper.time_precise() >= df.redraw_ctlbitmapmix then
        df.redraw_ctlbitmapmix = nil
        GUI_DrawCtlBitmap_Mix()     
      end
      if df.midimsg == true and reaper.time_precise() >= midimsgto then
        df.midimsg = false
        lupd.update_surface = true
      end
      if df.touch_timer and df.touch_timer <= reaper.time_precise() then
        df.touch_timer = nil
        lupd.update_surface = true
      end
      if df.exit_macro_edit then
        
        navigate = true
        macro_edit_mode = false
        macroctl_select = nil
        lupd.update_surface = true
        df.exit_macro_edit = nil
        if lvar.macro_returnedit then
          setmode(lvar.macro_returnedit)
          lupd.update_gfx = true
          lvar.macro_returnedit = nil
        end
        RedrawGUIBitmap()
      end
      if df.stripbrowser_reload_delay and reaper.time_precise() >= df.stripbrowser_reload_delay then
        df.stripbrowser_reload_delay = nil
        PopulateStrips()
        lvar.reloadsbimages = true
        lupd.update_stripbrowser = true
      end
      if df.trbtnsglobalset_delay and reaper.time_precise() >= df.trbtnsglobalset_delay then
        df.trbtnsglobalset_delay = nil
      end
    end
    if lvar.zoominfo then
      StripZoom()
    end
    
    if lvar.closesb then
      lvar.closesb = nil
    end
    
    --DBG(reaper.time_precise()-rt)
    
    --if setpage_wait then
    --  SetPage(setpage_wait)
    --  setpage_wait = nil
    --end
  end

  function Pop_SetPos(x, y)
 
    if not x then
      x = lvar.pop_xoff or 0
    end
    if not y then
      y = lvar.pop_yoff or 0
    end
    local strip = tracks[track_select].strip
    local poprows = strips[strip][page].poprows
    if poprows then
      if poprows.type == 1 then
        local offy = 0
        if lvar.mixmodedir == 1 then
          if lvar.mmov_show then
            offy = lvar.mmov_vsize+lvar.mmov_pad*2
          end
        end
        local vh = poprows.vish
        local th = poprows.toth
        if th > vh then
          local min = math.floor((obj.sections[10].h-offy)/2 - poprows[1].rowh/2)
          local max = math.floor((obj.sections[10].h-offy)/2 - poprows[#poprows].rowh/2)
          lvar.pop_yoff = math.floor(F_limit(y, vh-th-max, 0+min))
        else
          lvar.pop_yoff = 0
        end
        --DBG(lvar.pop_yoff..'  '..vh..'  '..th)
        local vw = poprows.visw
        local tw = poprows.totw
        if tw > vw then
          local dx = tw-vw
          lvar.pop_xoff = math.floor(F_limit(x, -dx/2, dx/2))
        else
          lvar.pop_xoff = 0
        end
      else
        if poprows.maxx-poprows.minx > poprows.visw then
          if x < (lvar.pop_xoff or 0) then
            if -x < poprows.maxx - poprows.visw then
              lvar.pop_xoff = x
            else
              lvar.pop_xoff = -(poprows.maxx - poprows.visw)
            end
          elseif x > (lvar.pop_xoff or 0) then 
            if -x > poprows.minx-50 then
              lvar.pop_xoff = x
            else
              lvar.pop_xoff = -(poprows.minx-50)
            end
          end
          
          --lvar.pop_xoff = x   
          --math.floor(F_limit(x, poprows.minx, poprows.maxx-poprows.visw))
        else
          lvar.pop_xoff = 0
        end
        if poprows.maxy-poprows.miny > poprows.vish then
          if y < (lvar.pop_yoff or 0) then
            if -y < poprows.maxy - poprows.vish then
              lvar.pop_yoff = y
            else
              lvar.pop_yoff = -(poprows.maxy - poprows.vish)
            end
          elseif y > (lvar.pop_yoff or 0) then 
            if -y > poprows.miny-150 then
              lvar.pop_yoff = y
            else
              lvar.pop_yoff = -(poprows.miny-150)
            end
          end
          --lvar.pop_yoff = y --math.floor(F_limit(y, math.min(poprows.miny), math.max(poprows.maxy-poprows.vish),0))
        else
          lvar.pop_yoff = 0
        end
      end
    else
      lvar.pop_xoff = 0
      lvar.pop_yoff = 0
    end
  
  end

  function A_RunMod()

    local lvar = lvar
    local lupd = lupd

    local pp, tsm
    if reaper.GetPlayState() > 0 or settings_alwaysrunmods == false then
      pp = reaper.GetPlayPosition()
      tsm = reaper.FindTempoTimeSigMarker(0,pp)
      if tsm then
        local retval, timepos = reaper.GetTempoTimeSigMarker(0, tsm)
        pp = pp - timepos
      end
      stop_pp = nil
    else
      if stop_pp == nil then
        stop_pp = reaper.time_precise()
      end
      pp = reaper.GetCursorPosition()
      pp = reaper.time_precise() - stop_pp
    end

    local bt = CalcBeatTime()
    local ms = modulators
    local offset = 0

    for i = 1, #ms do
      if ms[i].active == true then

        local m = ms[i]
        local time = CalcSyncTime(m.syncv)
        if m.offset ~= 0.5 then
          offset = -((0.5-m.offset)*2) * bt
        end
        m.dpos = ((pp+offset) % time) / time
        m.pos = math.floor(m.dpos * m.steps)+1
        if #m.targets > 0 and (m.pos ~= m.opos or m.interpolate == true) then
          local val = m.data[m.pos]
          if m.interpolate then
            local dv
            local dp = (m.dpos * m.steps + 1) - m.pos
            if m.pos < m.steps then
              dv = (m.data[m.pos + 1] - m.data[m.pos]) * dp
            else
              dv = (m.data[1] - m.data[m.pos]) * dp
            end
            val = val + dv
          end

          --if m.targets then
            for t = 1, #m.targets do

              if val then
                if m.mode == 1 then
                  val = m.min + (m.max-m.min)*val
                end
                if m.targets[t].targettype == 1 then
                  if lvar.livemode == 2 then
                    if lvar.dynamicmode_guid == m.targets[t].dm_guid then
                      local ctl = strips[m.targets[t].strip][m.targets[t].page].controls[m.targets[t].ctl]
                      if ctl.ctllock ~= true and val ~= ctl.val then
                        SetParam3(m.targets[t].strip,m.targets[t].page,m.targets[t].ctl,ctl,val)
                        lupd.update_ctls = true
                      end
                    else
                      DM_SetParam3(m.targets[t].dm_guid,m.targets[t].ctl,val)
                    end
                  else
                    local ctl = strips[m.targets[t].strip][m.targets[t].page].controls[m.targets[t].ctl]
                    if ctl.ctllock ~= true and val ~= ctl.val then
                      --DBG(val..'  '..ctl.val)
                      SetParam3(m.targets[t].strip,m.targets[t].page,m.targets[t].ctl,ctl,val)
                      lupd.update_ctls = true

                      --ctl.val = val
                    end
                  end
                end
              end
            end
          --end
        end
        if m.pos ~= m.opos then
          if show_lfoedit == true then --??
            lupd.update_lfopos = true
          end
          --if show_lfoedit ~= true then
            m.oopos = m.opos
            m.opos = m.pos
          --end
        end
      end
    end

  end

  function A_RunSnapStage()

    local stage_data = snapstage_data
    local t = reaper.time_precise()
    local cnt = #stage_data
    local actcnt = 0

    for i = 1, cnt do

      if stage_data[i] and stage_data[i].active == true then

        actcnt = actcnt + 1

        if t >= stage_data[i].trigtime then
          local ostage = stage_data[i].stage

          Snapshot_Set(stage_data[i].strip,
                       stage_data[i].page,
                       stage_data[i].sstype_sel,
                       stage_data[i].ss_sel,
                       stage_data[i].nomorph,
                       stage_data[i].stage,
                       i,
                       stage_data[i].retain,
                       stage_data[i].trigtime)
          if ostage == stage_data[i].stage then
            stage_data[i] = {}
          end
        end
      end

    end

    if actcnt == 0 then
      snapstage_data = {}
    end

  end

  function A_RunMorph()

    local lmorph_data = morph_data
    local runcnt = 0
    local t = reaper.time_precise()
    local lvar = lvar
    local lupd = lupd


    for i = 1, #lmorph_data do

      if lmorph_data[i].active then
        runcnt = runcnt + 1
        local p, man

        if not lmorph_data[i].paused then
          p = math.min((t-lmorph_data[i].start_time) / lmorph_data[i].morph_time,1)
          Snapshot_Morph(lmorph_data[i].strip, lmorph_data[i].page, lmorph_data[i].sstype, lmorph_data[i].targetss, i, p)
        elseif lmorph_data[i].manual then

          p = lmorph_data[i].p
          Snapshot_Morph(lmorph_data[i].strip, lmorph_data[i].page, lmorph_data[i].sstype, lmorph_data[i].targetss, i, p)
          lmorph_data[i].manual = nil
          man = true
        end

        lupd.update_ctls = true

        if p == 1 and man == nil then

          local snaps = snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype]

          if lmorph_data[i].morph_loop == 2 and lmorph_data[i].stage >= (snaps.stages or 1) then
            --RETRIGGER
            lmorph_data[i].stage = 1

            local mt = lmorph_data[i].morph_time
            if (snaps.stages or 1) > 1 then
              mt = Morph_GetStageTime(snaps,lmorph_data[i].stage)
            end
            lmorph_data[i].start_time = lmorph_data[i].end_time
            lmorph_data[i].morph_time = mt
            lmorph_data[i].end_time = lmorph_data[i].start_time + mt
            lupd.update_snaps = true

          elseif lmorph_data[i].morph_loop == 3 and lmorph_data[i].stage >= (snaps.stages or 1) then
            --REVERSE

            lmorph_data[i].start_time = lmorph_data[i].end_time
            lmorph_data[i].end_time = lmorph_data[i].start_time + lmorph_data[i].morph_time
            lmorph_data[i].dir = 1-(lmorph_data[i].dir or 0)
            lmorph_data[i].stage = 1
            lupd.update_snaps = true

          elseif lmorph_data[i].morph_loop == 4 and lmorph_data[i].stage >= (snaps.stages or 1) then

            lmorph_data[i].stage = 1
            if lmorph_data[i].dir == 1 then
              lmorph_data[i].dir = 0
            else
              lmorph_data[i].data = {}
              lmorph_data[i].targetss = lmorph_data[i].targetss + 1
              lmorph_data[i].p = 0
              if lmorph_data[i].sstype == 1 then
                if lmorph_data[i].targetss > #snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype] then
                  lmorph_data[i].targetss = 1
                end
              else
                if lmorph_data[i].targetss > #snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype].snapshot then
                  lmorph_data[i].targetss = 1
                end
              end
            end
            snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype].selected = lmorph_data[i].targetss
            if lmorph_data[i].strip == tracks[track_select].strip and
               lmorph_data[i].page == page and
               lmorph_data[i].sstype == sstype_select then
              ss_select = lmorph_data[i].targetss
            end

            local mt = lmorph_data[i].morph_time
            if (snaps.stages or 1) > 1 then
              mt = Morph_GetStageTime(snaps,lmorph_data[i].stage)
            end
            lmorph_data[i].start_time = lmorph_data[i].end_time
            lmorph_data[i].morph_time = mt
            lmorph_data[i].end_time = lmorph_data[i].start_time + mt
            lupd.update_snaps = true

          elseif lmorph_data[i].morph_loop == 5 and lmorph_data[i].stage >= (snaps.stages or 1) then
            lmorph_data[i].stage = 1
            if lmorph_data[i].dir == 1 then
              lmorph_data[i].dir = 0
            else
              lmorph_data[i].data = {}
              local sscnt
              if lmorph_data[i].sstype == 1 then
                sscnt = #snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype]
              else
                sscnt = #snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype].snapshot
              end
              local oss = lmorph_data[i].targetss
              lmorph_data[i].p = 0

              lmorph_data[i].targetss = math.min(math.floor(math.random() * (sscnt))+1,sscnt)
              if sscnt > 1 then
                while oss == lmorph_data[i].targetss do
                  lmorph_data[i].targetss = math.min(math.floor(math.random() * (sscnt))+1,sscnt)
                end
              end
            end
            snapshots[lmorph_data[i].strip][lmorph_data[i].page][lmorph_data[i].sstype].selected = lmorph_data[i].targetss
            if lmorph_data[i].strip == tracks[track_select].strip and
               lmorph_data[i].page == page and
               lmorph_data[i].sstype == sstype_select then
              ss_select = lmorph_data[i].targetss
            end

            local mt = lmorph_data[i].morph_time
            if (snaps.stages or 1) > 1 then
              mt = Morph_GetStageTime(snaps,lmorph_data[i].stage)
            end
            lmorph_data[i].start_time = lmorph_data[i].end_time
            lmorph_data[i].morph_time = mt
            lmorph_data[i].end_time = lmorph_data[i].start_time + mt
            lupd.update_snaps = true

          elseif lmorph_data[i].stage < (snaps.stages or 1) and (snaps.deltype ~= 1 or snaps.delay[lmorph_data[i].stage+1] == 0) then

            --DBG('NEXT STAGE')

            local retain = false
            if lmorph_data[i].morph_loop == 2 or lmorph_data[i].morph_loop == 3 then
              retain = true
            end
            Snapshot_Set(lmorph_data[i].strip,
                         lmorph_data[i].page,
                         lmorph_data[i].sstype,
                         lmorph_data[i].targetss,
                         lmorph_data[i].nomorph,
                         lmorph_data[i].stage+1,
                         nil,
                         retain,
                         lmorph_data[i].end_time)


          elseif lmorph_data[i].morph_loop == 1 then

            --DBG('EXIT MORPH')
            lmorph_data[i].active = false

            runcnt = runcnt - 1
            lupd.update_snaps = true
            lupd.update_gfx = true
            if mode0_submode == 1 then
              lupd.update_sidebar = true
            end
          end
        end
      end
    end
    if runcnt == 0 then
      morph_data = {}
      morph_puw = nil
    end

  end

  function RCMRefresh()

    if rcmrefreshtimer then
      local cnt = 0
      for r = 1, rcmrefreshtimercount do
        if rcmrefreshtimer[r] then
          cnt = cnt + 1
          if rcmrefreshtimer[r].tracknum == tracks[track_select].tracknum then
            if reaper.time_precise() >= rcmrefreshtimer[r].time then
              RefreshControlsByGUID(rcmrefreshtimer[r].guid)

              if rcmrefreshtimer[r].setvals == true then
                local cvs = rcmrefreshtimer[r].ctlvals
                if cvs and #cvs > 0 then
                  for i = 1, #cvs do
                    local ctl = strips[cvs[i].strip][cvs[i].page].controls[cvs[i].ctl]
                    ctl.oval = ctl.val
                    ctl.val = cvs[i].val
                    A_SetParam(cvs[i].strip,cvs[i].page,cvs[i].ctl,ctl)
                  end
                end

              end

              rcmrefreshtimer[r] = nil
              rcmrefreshtimercount = math.max(rcmrefreshtimercount -1,0)
            end
          else
            if rcmrefreshtimer[r].setvals == true then
              if reaper.time_precise() >= rcmrefreshtimer[r].time then
                local cvs = rcmrefreshtimer[r].ctlvals
                if cvs and #cvs > 0 then
                  for i = 1, #cvs do
                    local ctl = strips[cvs[i].strip][cvs[i].page].controls[cvs[i].ctl]
                    ctl.oval = ctl.val
                    ctl.val = cvs[i].val
                    A_SetParam(cvs[i].strip,cvs[i].page,cvs[i].ctl,ctl)
                  end
                end
              end
            else
              rcmrefreshtimer[r] = nil
              rcmrefreshtimercount = math.max(rcmrefreshtimercount -1,0)
            end
          end
        end
      end
      if cnt == 0 then
        rcmrefreshtimer = nil
        rcmrefreshtimercount = 0
      else
        if rcmrefreshtimercount == 0 then
          rcmrefreshtimer = nil
        end
      end
    else
      rcmrefreshtimercount = 0
    end

  end

  function GetFXNum(guid)
    local track = GetTrack(tracks[track_select].tracknum)
    if track then
      local fxcnt = reaper.TrackFX_GetCount(track)
      for f = 0, fxcnt do
        if reaper.TrackFX_GetFXGUID(track,f) == guid then
          return f
        end
      end
    end
  end

  function RefreshControlsByGUID(guid)

    --local fxnum = GetFXNum(guid)
    --if fxnum then
    local strip = tracks[track_select].strip
    for c = 1, #strips[strip][page].controls do
      local ctl = strips[strip][page].controls[c]
      if ctl and ctl.fxguid and ctl.fxguid == guid then

        ctl.dirty = true
      end
    end
  --end
    lupd.update_ctls = true
  end

  function A_Run_MidiLrn(char)

    if mouse.context == nil and MOUSE_click(obj.sections[982]) then

      local ctl = strips[tracks[track_select].strip][page].controls[lbx_midilrnctl]
      if lbx_midilrnval then

        if faders[lbx_midilrnval] and faders[lbx_midilrnval].targettype then
          if reaper.MB('Replace assignment?','Faderbox learn',4) ~= 6 then
            return
          end
        end

        local tt
        if ctl.ctlcat == ctlcats.snapshot then
          tt = 7
        else
          tt = 4
        end

        local f = {targettype = tt,
                   strip = tracks[track_select].strip,
                   page = page,
                   ctl = lbx_midilrnctl,
                   c_id = ctl.c_id,
                   voffset = lbx_midilrnoff}
        for i = 1, #faders do
          if faders[i].targettype == f.targettype and
             faders[i].strip == f.strip and
             faders[i].page == f.page and
             faders[i].ctl == f.ctl and
             faders[i].c_id == f.c_id then
            faders[i] = {}
          end
        end
        AssignFader(lbx_midilrnval, f)

      else
        local fad = ctl.macrofader
        if fad then
          DeleteFader(fad)
        end
      end
      lbx_midilrnctl = nil
      lbx_midilrnval = nil
      lupd.update_surface = true

    elseif MOUSE_click(obj.sections[981]) then

      local ctl = strips[tracks[track_select].strip][page].controls[lbx_midilrnctl]

      local f = {targettype = 4,
                 strip = tracks[track_select].strip,
                 page = page,
                 ctl = lbx_midilrnctl,
                 c_id = ctl.c_id,
                 voffset = 0}

      local fad = SetAutomationFader(f, ctl.macrofader, true)
      if fad > 0 then
        lbx_midilrnval = fad
      elseif fad == -2 then
        lbx_midilrnval = nil
      end
      lupd.update_surface = true

    elseif mouse.context == nil and mouse.LB and not MOUSE_over(obj.sections[980]) then
      lbx_midilrnctl = nil
      lbx_midilrnval = nil
      lupd.update_surface = true

    elseif MOUSE_click(obj.sections[983]) then
      local ctl = strips[tracks[track_select].strip][page].controls[lbx_midilrnctl]
      if ctl.ctlcat == ctlcats.snapshot then
        NoteValueOffsetMenu(lbx_midilrnoff)
        lupd.update_gfx = true
      end
    end

  end

  function A_Run_MidiOut(char)

    if mouse.context == nil then
      
      if MC() then
      
        if MOUSE_click(obj.sections[951]) then
          local res = MenuMidiOuts()
          if res and res > 1 then
            midiout_select.output = midiouts[res-1].name
          else
            midiout_select.output = nil
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[954]) then
          local res = MenuMidiMsgType()
          if res then
            midiout_select.msgtype = res
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[955]) then
    
          local retval, msg = reaper.GetUserInputs('Osc Message',1,'OSC:,extrawidth=220',nz(midiout_select.osc,''))
          if retval == true then
            midiout_select.osc = msg
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[956]) then
    
          local retval, msg = reaper.GetUserInputs('Value Range',1,'Value Min:',nz(midiout_select.vmin,0))
          if retval == true then
            local msgv = tonumber(msg)
            if msgv then
              midiout_select.vmin = msgv
            end
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[957]) then
    
          local retval, msg = reaper.GetUserInputs('Value Range',1,'Value Max:',nz(midiout_select.vmax,127))
          if retval == true then
            local msgv = tonumber(msg)
            if msgv then
              midiout_select.vmax = msgv
            end
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[958]) then
          midiout_select.focus = midiout_select.focus + 1
          if midiout_select.focus > #lvar.focus_table then
            midiout_select.focus = 1
          end
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[963]) then
          if reaper.JS_Window_Find then
            local ret, tit = reaper.GetUserInputs('Focus Window',1,'Please enter title of window to focus:',midiout_select.focus_wintit or '')
            if ret == true then
              midiout_select.focus_wintit = tit
            end
            lupd.update_surface = true
          end
    
        elseif MOUSE_click(obj.sections[964]) then
          if reaper.JS_Window_Find then
            midiout_select.focus_winexact = not (midiout_select.focus_winexact or false)
            lupd.update_surface = true
          end
    
        elseif MOUSE_click(obj.sections[959]) then
          midiout_select.updategfx = not midiout_select.updategfx
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[961]) then
          midiout_select.onmu = not midiout_select.onmu
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[952]) then
          mouse.context = contexts.midiout_chan
          midiout_select.mchan = F_limit(midiout_select.mchan + 1,1,16)
          dragmidi = {pos = midiout_select.mchan, yoff = mouse.my-obj.sections[952].y}
    
          lupd.update_surface = true
        elseif MOUSE_click_RB(obj.sections[952]) then
          midiout_select.mchan = F_limit(midiout_select.mchan - 1,1,16)
          lupd.update_surface = true
    
        elseif MOUSE_click(obj.sections[953]) then
          mouse.context = contexts.midiout_msg
          midiout_select.msg3 = F_limit(midiout_select.msg3 + 1,0,127)
          dragmidi = {pos = midiout_select.msg3, yoff = mouse.my-obj.sections[953].y}
    
          lupd.update_surface = true
        elseif MOUSE_click_RB(obj.sections[953]) then
          midiout_select.msg3 = F_limit(midiout_select.msg3 - 1,0,127)
          lupd.update_surface = true
          
        end
        
      else
    
        if mouse.LB and not MOUSE_over(obj.sections[950]) then
          show_midiout = false
    
          local strip = tracks[track_select].strip
          if midioutedit_ctlselect == true then
            if ctl_select and #ctl_select > 0 then
              for c = 1, #ctl_select do
                local ctl = strips[strip][page].controls[ctl_select[c].ctl]
                if ctl and ((midiout_select.output and midioutsidx[midiout_select.output]) or midiout_select.osc) then
    
                  ctl.midiout = {output = midiout_select.output,
                                 msgtype = midiout_select.msgtype,
                                 mchan = midiout_select.mchan,
                                 msg3 = midiout_select.msg3,
                                 osc = midiout_select.osc,
                                 vmin = midiout_select.vmin,
                                 vmax = midiout_select.vmax,
                                 focus = midiout_select.focus,
                                 focus_wintit = midiout_select.focus_wintit,
                                 focus_winexact = midiout_select.focus_winexact,
                                 updategfx = midiout_select.updategfx,
                                 onmu = midiout_select.onmu}
    
                else
                  ctl.midiout = nil
                end
              end
            end
            midioutedit_ctlselect = nil
          
          elseif midioutedit_select then
            local ctl = strips[strip][page].controls[midioutedit_select]
            if ctl and ((midiout_select.output and midioutsidx[midiout_select.output]) or midiout_select.osc) then
    
              ctl.midiout = {output = midiout_select.output,
                             msgtype = midiout_select.msgtype,
                             mchan = midiout_select.mchan,
                             msg3 = midiout_select.msg3,
                             osc = midiout_select.osc,
                             vmin = midiout_select.vmin,
                             vmax = midiout_select.vmax,
                             focus = midiout_select.focus,
                             focus_wintit = midiout_select.focus_wintit,
                             focus_winexact = midiout_select.focus_winexact,
                             updategfx = midiout_select.updategfx,
                             onmu = midiout_select.onmu}
    
            else
              ctl.midiout = nil
            end
          end
    
          lupd.update_gfx = true
          RedrawGUIBitmap()
          
        end
      end
      
    else --context

      if mouse.context and mouse.context == contexts.midiout_chan then
        local v = MOUSE_slider(obj.sections[952], -dragmidi.yoff)
        if v then
          v=v-0.5
          midiout_select.mchan = F_limit(math.floor(dragmidi.pos - v*32),1,16)
          lupd.update_surface = true
        end
  
      elseif mouse.context and mouse.context == contexts.midiout_msg then
        local v = MOUSE_sliderX(obj.sections[953], -dragmidi.yoff)
        if v then
          v=v-0.5
          midiout_select.msg3 = F_limit(math.floor(dragmidi.pos - v*96),0,127)
          lupd.update_surface = true
        end
      end

    end
    
  end

  function A_Run_TFXOrder(char, rt)

    if char ~= 0 then
      if char == 49 then
        show_trackfxorder = false
        --lupd.update_gfx = true
        --lupd.update_trackfxorder = true
        lupd.update_trbtns = true
        RedrawGUIBitmap()

      elseif char == 52 then
        if mode == 0 then
          show_pinmatrix = not show_pinmatrix
          lupd.update_surface = true
          char = 0
          RedrawGUIBitmap()
        end
      end
    end

    local butt_cnt, bh = GetTFXOButtCnt()
    local xywh = {x = obj.sections[900].x+30,
                  y = obj.sections[900].y+30*pnl_scale,
                  w = obj.sections[900].w-50,
                  h = obj.sections[900].h-30*pnl_scale}
    local xywh2 = {x = obj.sections[900].x,
                      y = obj.sections[900].y,
                      w = obj.sections[900].w,
                      h = butt_h*pnl_scale}
    if gfx.mouse_wheel ~= 0 and MOUSE_over(xywh) then
      local v = mousewheel_val() --

      if butt_cnt < #tfxorder then
        tfxo_listpos = F_limit(tfxo_listpos -v,0,#tfxorder-butt_cnt)
        --lupd.update_surface = true
        lupd.update_trackfxorder = true
        gfx.mouse_wheel = 0
      end
    end
    
    if mouse.context == nil then
      
      if MC() then
      
        if MOUSE_click(xywh2) then
          mouse.context = contexts.move_fxorder
          movewin = {dx = mouse.mx, dy = mouse.my, ox = obj.sections[900].x, oy = obj.sections[900].y}
    
        elseif MOUSE_click(xywh) then
          --tfxo_sel =  F_limit(math.floor((mouse.my - xywh.y) / bh)+1 +tfxo_listpos, 1, #tfxorder)
          tfxo_sel =  math.floor((mouse.my - xywh.y) / bh)+1 +tfxo_listpos
          if tfxo_sel >= 1 and tfxo_sel <= #tfxorder then
            if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
              track = GetTrack(tracks[track_select].tracknum)
              local fxnum = tfxo_sel
              reaper.TrackFX_Show(track, fxnum, 3)
            else
              mouse.context = contexts.tfxo_shift
              tfxo_scrolldel = reaper.time_precise()
              tfxo_pos = tfxo_sel
            end
          else
            tfxo_sel = nil
          end
          lupd.update_trackfxorder = true
          --lupd.update_surface = true
        
        elseif MOUSE_click(obj.sections[900]) then
          mouse.context = contexts.dummy
    
        end
        
      elseif tfxo_pos then
      
        if lvar.livemode > 0 then
          if tfxo_pos ~= tfxo_sel then
            local extid = lvar.stripdim.swdata.extid
            local before = true
            if tfxo_pos > tfxo_sel then
              before = false
            end
            reaper.Undo_BeginBlock2(0)
            Switchers_Ext_MovePos(extid,tfxo_sel,tfxo_pos,before,true,true)
            reaper.Undo_EndBlock2(0,"Move Strip",-1)
  
          end
          tfxo_pos = nil
          tfxo_sel = nil
          tfxorder = tfxreorder
        else
          MoveFXChunk(tfxo_sel, tfxo_pos)
          tfxo_pos = nil
          tfxo_sel = nil
          tfxorder = tfxreorder
        end
        lupd.update_trackfxorder = true
        lupd.update_surface = true
      
      elseif mouse.LB and not MOUSE_over(obj.sections[901]) and show_pinmatrix == false then
        show_trackfxorder = false
        --lupd.update_surface = true
        lupd.update_trbtns = true
        RedrawGUIBitmap()
      
      end
      
    else
        
      if mouse.context == contexts.tfxo_shift then
        tfxo_lastpos = tfxo_pos
        local mpos = math.floor((mouse.my - xywh.y) / bh)+1
        tfxo_pos = F_limit(mpos +tfxo_listpos, 1, #tfxorder)
        if reaper.time_precise() > tfxo_scrolldel then
          if mpos < 1 then
            tfxo_listpos = math.max(tfxo_listpos -1,0)
          elseif mpos > butt_cnt then --hard coded size :/
            tfxo_listpos = math.min(tfxo_listpos +1,#tfxorder-butt_cnt)
          end
          tfxo_scrolldel = reaper.time_precise() + 0.1
          lupd.update_surface = true
        end
        if tfxo_pos ~= tfxo_lastpos then
          tfxreorder = ReOrderTable(tfxorder, 1, tfxo_sel, tfxo_pos)
          lupd.update_trackfxorder = true
          --lupd.update_surface = true
        end
        
      elseif mouse.context == contexts.move_fxorder then
        obj.sections[900].x = F_limit(movewin.ox + mouse.mx - movewin.dx,obj.sections[10000].x,gfx1.main_w -obj.sections[900].w)
        obj.sections[900].y = F_limit(movewin.oy + mouse.my - movewin.dy,obj.sections[10000].y,gfx1.main_h -obj.sections[900].h)
        obj.sections[900].y = math.max(obj.sections[900].y,obj.sections[10000].y)
        --lupd.update_surface = true
        lupd.update_trackfxorder = true
        RedrawGUIBitmap()
      end
      
    end
    
    return char
  end

  function ReOrderTable(tab, s, p1, p2)

    local newtab = {}
    local offs = 0
    for i = s, #tab do
      if i ~= p1 then
        table.insert(newtab, tab[i])
      end
    end
    if p2 == #tab then
      table.insert(newtab, tab[p1])
    else
      table.insert(newtab, p2, tab[p1])
    end
    return newtab

  end

  function DragFader_Assign(fd, c)

    local ctl = strips[tracks[track_select].strip][page].controls[c]
    if ctl then

      if ctl.ctlcat == ctlcats.snapshot then
        tt = 7
      elseif ctl.ctlcat == ctlcats.switcher then
        tt = 6
      else
        tt = 4
      end
      local f = {targettype = tt,
                 strip = tracks[track_select].strip,
                 page = page,
                 ctl = c,
                 c_id = ctl.c_id,
                 voffset = 0}
      if lvar.livemode == 2 then
        f.dm_trn = lvar.dynamicmode_trn
        f.dm_guid = lvar.dynamicmode_guid
      end
      AssignFader(fd, f)

    end

  end

  function ModMenu(mx, my)

    local mstr = 'Sine|Triangle|Ramp Up|Ramp Down||Flip Horiz|Flip Vert||Save Preset|Load Preset'
    gfx.x, gfx.y = mx, my
    local res = gfx.showmenu(mstr)
    if res > 0 then
      local m = modulators[mod_select]
      local bars = lvar.sync_mult_table[m.syncv]
      local barsteps
      if mouse.shift then
        barsteps = m.steps
      else
        barsteps = m.steps / bars
      end
      if barsteps > m.steps then barsteps = m.steps end
      --local barsteps = m.steps
      if res == 1 then

        for i = 1, m.steps do

          m.data[i] = (math.sin((((i-1) % barsteps)/barsteps)*2*pi)+1)/2

        end
        lupd.update_lfoedit = true

      elseif res == 2 then

        barsteps = barsteps*0.5
        for i = 1, m.steps do

          local v = ((i-1+barsteps/2) % barsteps)/barsteps
          if math.floor((i-1+barsteps/2) / barsteps) % 2 == 0 then
            m.data[i] = v
          else
            m.data[i] = 1-v
          end

        end
        lupd.update_lfoedit = true

      elseif res == 3 then

        for i = 1, m.steps do

          m.data[i] = ((i-1) % barsteps) /barsteps

        end
        lupd.update_lfoedit = true

      elseif res == 4 then

        for i = 1, m.steps do

          m.data[i] = 1-(((i-1) % barsteps) /barsteps)

        end
        lupd.update_lfoedit = true

      elseif res == 5 then

        local d = {}
        for i = 1, m.steps do

          d[m.steps-(i-1)] = m.data[i]

        end
        m.data = d
        lupd.update_lfoedit = true

      elseif res == 6 then

        for i = 1, m.steps do
        
          m.data[i] = 1-m.data[i]
        
        end
        lupd.update_lfoedit = true
        
      elseif res == 7 then

        OpenEB(120,'Please give the modulator preset a name:','Mod Preset')

      elseif res == 8 then
        local ret, fn = reaper.GetUserFileNameForRead(paths.mod_path..'*','Load Mod Preset','.lbxmod')
        if ret == true and fn then
          LoadModPreset(fn)
          lupd.update_lfoedit = true
        end

      end

    end

  end

  function DragMod_Assign(md, c)

    local ctl = strips[tracks[track_select].strip][page].controls[c]
    if ctl then

      local strip = tracks[track_select].strip
      local mt = modulators[md].targets
      local c_id = strips[strip][page].controls[c].c_id
      local fnd = false
      for i = 1, #mt do
        if mt[i].targettype == 1 then
          if lvar.livemode == 2 then
            if mt[i].dm_guid == lvar.dynamicmode_guid and
               mt[i].ctl == c and
               mt[i].c_id == c_id then
              fnd = true
              break
            end
          else
            if mt[i].strip == strip and
               mt[i].page == page and
               mt[i].ctl == c and
               mt[i].c_id == c_id then
              fnd = true
              break
            end
          end
        end
      end
      if fnd == false then

        Mod_RemoveAssign(strip, page, c)
        local idx = #mt+1
        mt[idx] = {targettype = 1,
                     strip = strip,
                     page = page,
                     ctl = c,
                     c_id = c_id}
        if lvar.livemode == 2 then
          mt[idx].dm_trn = lvar.dynamicmode_trn
          mt[idx].dm_guid = lvar.dynamicmode_guid
        end
        strips[strip][page].controls[c].mod = md

        SetCtlDirty(c)
        lupd.update_ctls = true

      end

    end

  end

  function Mod_ClearTarget(mod, tt, s, p, c, dm_guid)
    local m = modulators[mod]
    local trem
    for t = 1, #m.targets do
      if m.targets[t].targettype == tt then
        if tt == 1 then
          if m.targets[t].dm_guid then
            if m.targets[t].dm_guid == dm_guid and m.targets[t].ctl == c then
              if m.targets[t].dm_guid == lvar.dynamicmode_guid then
                SetCtlDirty(m.targets[t].ctl)
              end
              m.targets[t] = nil
              trem = true
              break
            end
          else
            if m.targets[t].strip == s and m.targets[t].page == p and m.targets[t].ctl == c then
              if m.targets[t].strip == tracks[track_select].strip and m.targets[t].page == page then
                SetCtlDirty(m.targets[t].ctl)
              end
              m.targets[t] = nil
              trem = true
              break
            end
          end
        end
      end
    end
    if trem then
      m.targets = Table_RemoveNils(m.targets, tcnt)
      lupd.update_ctls = true
    end
  end

  function Mod_SetTargetsDirty(mod)
    local m = modulators[mod]
    for t = 1, #m.targets do
      if m.targets[t].targettype == 1 then
        if m.targets[t].dm_guid then
          if m.targets[t].dm_guid == lvar.dynamicmode_guid then
            SetCtlDirty(m.targets[t].ctl)
          end
        else
          if m.targets[t].strip == tracks[track_select].strip and m.targets[t].page == page then
            SetCtlDirty(m.targets[t].ctl)
          end
        end
      end
    end
    lupd.update_ctls = true
  end

  function Mod_RemoveAssign(strip, page, ctl, dm_guid)

    local m = modulators
    local c_id
    if dm_guid then
      if lvar.stripstore[dm_guid] then
        c_id = lvar.stripstore[dm_guid].controls[ctl].c_id
      end
    else
      c_id = strips[strip][page].controls[ctl].c_id
    end
    for i = 1, #m do
      if m[i] and #m[i].targets > 0 then

        local remflag = false
        local tcnt = #m[i].targets
        for t = 1, tcnt do

          if m[i].targets[t].targettype == 1 then
            if m[i].targets[t].dm_guid then

              if m[i].targets[t].dm_guid == dm_guid and
                 m[i].targets[t].c_id == c_id then

                m[i].targets[t] = nil
                remflag = true

              end
            else
              if m[i].targets[t].strip == strip and
                 m[i].targets[t].page == page and
                 m[i].targets[t].c_id == c_id then

                m[i].targets[t] = nil
                remflag = true
              end
            end
          end
        end

        if remflag == true then
          m[i].targets = Table_RemoveNils(m[i].targets,tcnt)
        end
      end
    end

  end

  function Mod_ChangeCount(newcnt)

    if newcnt < modulator_cnt then
      local ret = reaper.MB('Reducing modulator count might delete used modulators in stored snapshots - Continue?','Modulators',4)
      if ret == 7 then return end
    end

    modulator_cnt = newcnt
    INIT_Modulators(modulators)

    if strips then
      for s = 1, #strips do
        if snapshots[s] then
          for p = 1, lvar.maxpage do

            if snapshots[s][p] then

              for sst = 1, #snapshots[s][p] do

                local snaptbl
                if sst == 1 then
                  snaptbl = snapshots[s][p][sst]
                else
                  snaptbl = snapshots[s][p][sst].snapshot
                end
                if snaptbl and #snaptbl > 0 then
                  for ss = 1, #snaptbl do
                    if snaptbl.moddata then
                      snaptbl.moddata = INIT_Modulators(snaptbl.moddata)
                    end
                  end
                end
              end
            end

            if strips[s] then
              if #strips[s][p].controls > 0 then
                for c = 1, #strips[s][p].controls do
                  local ctl = strips[s][p].controls[c]
                  if ctl.mod then
                    if ctl.mod > modulator_cnt then
                      ctl.mod = nil
                    end
                  end
                end
              end
            end
          end
        end
      end
    end
  end

  function BtnPnl_Menu(idx,row,col,btnobj,mx,my)

    local cpd = ''
    if not lvar.btnpnlcopy then
      cpd = '#'
    end
    local bobj_f = ''
    local pastecol = '#'
    if not btnobj then
      bobj_f = '#'
    else
      if lvar.pnlbtn_colour then
        pastecol = ''
      end
    end
    
    mstr = bobj_f..'Rename||'..bobj_f..'Set Colour|'..bobj_f..'Copy Colour|'..pastecol..'Paste Colour||'..bobj_f..'Copy|'..bobj_f..'Cut||'..cpd..'Replace|'..cpd..'Swap||Clear||Clear All'
    gfx.x = mx
    gfx.y = my
    local res = gfx.showmenu(mstr)
    if res > 0 then
      if res == 1 then

        lvar.btnpnl_obj = btnobj
        OpenEB(5040, 'Enter new description: ',btnobj.ndesc or '')

      elseif res == 2 then
        local retval, c = reaper.GR_SelectColor(_,lvar.dm_btnpnl[idx][row][col].rgb or (205 + (205 << 8) + (205 << 16)))
        if retval ~= 0 then
          if lvar.Mac_revcol then c = MacRevC(c) end
          lvar.dm_btnpnl[idx][row][col].rgb = c
          lupd.update_trbtns = true
        end

      elseif res == 3 then
        lvar.pnlbtn_colour = lvar.dm_btnpnl[idx][row][col].rgb or (205 + (205 << 8) + (205 << 16))
      elseif res == 4 then
        lvar.dm_btnpnl[idx][row][col].rgb = lvar.pnlbtn_colour
        lupd.update_trbtns = true
      elseif res == 5 then

        lvar.btnpnlcopy = {idx = idx, row = row, col = col, tab = lvar.dm_btnpnl[idx][row][col], copy = true}

      elseif res == 6 then

        lvar.btnpnlcopy = {idx = idx, row = row, col = col, tab = lvar.dm_btnpnl[idx][row][col], copy = false}

      elseif res == 7 then
      
        if lvar.btnpnlcopy then
          lvar.dm_btnpnl[idx][row][col] = lvar.btnpnlcopy.tab
          if lvar.btnpnlcopy.copy == false then
            lvar.dm_btnpnl[lvar.btnpnlcopy.idx][lvar.btnpnlcopy.row][lvar.btnpnlcopy.col] = nil
          end
          lupd.update_trbtns = true
        end

      elseif res == 8 then
      
        if lvar.btnpnlcopy then
          local tab = lvar.dm_btnpnl[idx][row][col]
          lvar.dm_btnpnl[idx][row][col] = lvar.btnpnlcopy.tab
          lvar.dm_btnpnl[lvar.btnpnlcopy.idx][lvar.btnpnlcopy.row][lvar.btnpnlcopy.col] = tab
          lupd.update_trbtns = true
        end
        
      elseif res == 9 then
        lvar.dm_btnpnl[idx][row][col] = nil
        lupd.update_trbtns = true

      elseif res == 10 then

        lvar.dm_btnpnl[idx] = {}
        lupd.update_trbtns = true

      end

    end
  end

  function TrackSetListMenu(mx, my)

    local x = obj.sections[5041].x+math.floor(obj.sections[5041].w/2)
    local ddtab = {idx = 6, bottom = true, hcentre = true, x = x, y = obj.sections[4999].y, w = 100, h = 100, items = {}, itemcol = {}, itemdisabled = {}, indcol = {}, data = {}, wpad = 40, scroll = -1}

    ddtab.items[1] = 'Add New Set'
    ddtab.itemcol[1] = '255 192 0'
    ddtab.items[2] = 'Save As Set'
    ddtab.itemcol[2] = '255 192 0'
    ddtab.items[3] = '-------'
    local txt = '['..(lvar.dm_trackbtns[lvar.dm_tbidx].name or ('Set '..string.format('%i',lvar.dm_tbidx)))..']'
    ddtab.items[4] = 'Rename '..txt
    ddtab.itemcol[4] = '0 255 0'
    ddtab.items[5] = 'Delete '..txt
    ddtab.itemcol[5] = '0 255 0'
    ddtab.items[6] = '-------'
    ddtab.itemdisabled[3] = true
    ddtab.itemdisabled[6] = true
    if lvar.dm_tbidx == 0 then
      ddtab.items[4] = 'Rename'
      ddtab.items[5] = 'Delete'
      ddtab.itemdisabled[4] = true
      ddtab.itemdisabled[5] = true
    end
    local dm_trackbtns = lvar.dm_trackbtns
    local ddcnt = 7
    for i = 1, #dm_trackbtns do
      ddtab.items[ddcnt] = dm_trackbtns[i].name or ('Set '..string.format('%i',i))
      ddtab.data[ddcnt] = i
      ddcnt = ddcnt + 1
    end
    OpenDropDown(6, ddtab, true, true)

  end

  function FolderTrackListMenu(mx, my)

    local x = obj.sections[5041].x+math.floor(obj.sections[5041].w/2)
    local ddtab = {idx = 5, bottom = true, hcentre = true, x = x, y = obj.sections[4999].y, w = 100, h = 100, items = {}, itemcol = {}, indcol = {}, data = {}, wpad = 40, scroll = -1}
    ddtab.items[1] = 'Auto Mode'
    ddtab.itemcol[1] = '0 255 255'
    ddtab.items[2] = 'Media Item Tracks'
    ddtab.itemcol[2] = '0 255 0'
    ddtab.items[3] = 'MIDI Item Tracks'
    ddtab.itemcol[3] = '0 255 0'
    ddtab.items[4] = 'Audio Item Tracks'
    ddtab.itemcol[4] = '0 255 0'
    ddtab.items[5] = '- FOLDER TRACKS -'
    ddtab.itemcol[5] = '255 0 255'
    ddtab.items[6] = 'MASTER'
    local ddcnt = 7
    for t = 0, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      if reaper.GetMediaTrackInfo_Value(tr, 'I_FOLDERDEPTH') == 1 then
        local r, trname = reaper.GetTrackName(tr)
        ddtab.items[ddcnt] = trname
        ddtab.data[ddcnt] = t

        col = reaper.GetMediaTrackInfo_Value(tr, 'I_CUSTOMCOLOR')
        if col and (col & 0x1000000 == 0x1000000) then
          local r,g,b = reaper.ColorFromNative(col)
          ddtab.indcol[ddcnt] = tostring(r)..' '..tostring(g)..' '..tostring(b)
        end
        ddcnt = ddcnt + 1
      end
    end

    OpenDropDown(5, ddtab, true, true)

  end

  function A_Run_AltStripFuncs(noscroll, rt)

    local xclicked
    if stripgallery_view == 0 then

      if mouse.context == nil then

        if MOUSE_click2(lvar.stripctlbox, mouse.mx-obj.sections[10].x+surface_offset.x*lvar.zoom, mouse.my-obj.sections[10].y+surface_offset.y*lvar.zoom) or
            (lvar.stripctlbox.overstrip and MOUSE_click2_RB(lvar.stripctlbox.overstrip, mouse.mx-obj.sections[10].x+surface_offset.x*lvar.zoom, mouse.my-obj.sections[10].y+surface_offset.y*lvar.zoom)) then
          noscroll = true
          xclicked = true
          lvar.mofader_takeover = nil

          cbdragstrip = {x = lvar.stripctlbox.x, y = lvar.stripctlbox.y,
                         nx = lvar.stripctlbox.x - surface_offset.x*lvar.zoom, ny = lvar.stripctlbox.y - surface_offset.y*lvar.zoom,
                         dx = 0, dy = 0, mx = mouse.mx, my = mouse.my}
          mouse.context = contexts.lv_dragstrip
          SelectStripElements(lvar.stripctlbox.id)
          GenCtlDragPreview(gui, 1)
          A_HideSelectedCtls(true, ctl_select, gfx3_select)
          lupd.update_gfx = true

        elseif MOUSE_click2(lvar.stripctlboxX, mouse.mx-obj.sections[10].x+surface_offset.x*lvar.zoom,
                              mouse.my-obj.sections[10].y+surface_offset.y*lvar.zoom) then
          noscroll = true
          xclicked = true
          if mouse.LB and mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
            DeleteStrip(lvar.stripctlbox.id, true)
            SetCtlBitmapRedraw(true)
            CreateStripCB(true)
            lupd.update_surface = true
          end

        elseif cbdragstrip then

          MoveSelectedCtls(cbdragstrip.nx2 + surface_offset.x - cbdragstrip.x, cbdragstrip.ny2 + surface_offset.y - cbdragstrip.y)
          UnhideCtls()
          SetCtlBitmapRedraw(true)
          reaper.MarkProjectDirty(0)
          lupd.update_gfx = true
          CreateStripCB(true)

          ctl_select = nil
          gfx3_select = nil

          cbdragstrip = nil

        elseif lvar.stripctlbox.ctl and MOUSE_over(lvar.stripctlbox.ctl,mouse.mx-obj.sections[10].x+surface_offset.x*lvar.zoom, mouse.my-obj.sections[10].y+surface_offset.y*lvar.zoom) then

          if MC() then
            xclicked = true
            mouse.context = contexts.dummy
            local strip = tracks[track_select].strip
            local ctl = strips[strip][page].controls[lvar.stripctlbox.ctl.ctl]
            ctl.ctllock = not (ctl.ctllock or false)
            SetCtlDirty(lvar.stripctlbox.ctl.ctl)

            lupd.update_ctls = true
          end

        elseif mouse.alt and mouse.shift and not mouse.altlatch and not mouse.LB and not mouse.RB and MOUSE_over(obj.sections[10]) then

          CreateStripCB()

        end

      else

        if mouse.context == contexts.lv_dragstrip then
          
          if lvar.stripctlbox.overstrip then
            local gs = settings_gridsize
            if mouse.shift then
              gs = 1
            end
            local dx, dy = (mouse.mx - cbdragstrip.mx), (mouse.my - cbdragstrip.my)
            cbdragstrip.nx = F_limit(math.floor(((cbdragstrip.x + dx)/gs)*gs) - surface_offset.x*lvar.zoom,0 - surface_offset.x,surface_size.w - surface_offset.x -lvar.stripctlbox.overstrip.w)
            cbdragstrip.ny = F_limit(math.floor(((cbdragstrip.y + dy)/gs)*gs) - surface_offset.y*lvar.zoom,0 - surface_offset.y,surface_size.h - surface_offset.y -lvar.stripctlbox.overstrip.h)
  
            if cbdragstrip.nx ~= cbdragstrip.ox or cbdragstrip.ny ~= cbdragstrip.oy then
              local nx = F_limit(math.floor(((cbdragstrip.x + dx/lvar.zoom)/gs)*gs) - surface_offset.x,0 - surface_offset.x,surface_size.w - surface_offset.x -lvar.stripctlbox.overstrip.w)
              local ny = F_limit(math.floor(((cbdragstrip.y + dy/lvar.zoom)/gs)*gs) - surface_offset.y,0 - surface_offset.y,surface_size.h - surface_offset.y -lvar.stripctlbox.overstrip.h)
              cbdragstrip.nx2 = nx
              cbdragstrip.ny2 = ny
              cbdragstrip.dx = nx +surface_offset.x - cbdragstrip.x
              cbdragstrip.dy = ny +surface_offset.y - cbdragstrip.y
  
              lupd.update_surface = true
  
              cbdragstrip.ox = cbdragstrip.nx
              cbdragstrip.oy = cbdragstrip.ny
            end
          else
            mouse.context = nil
            MoveSelectedCtls(cbdragstrip.nx2 + surface_offset.x - cbdragstrip.x, cbdragstrip.ny2 + surface_offset.y - cbdragstrip.y)
            UnhideCtls()
            SetCtlBitmapRedraw(true)
            reaper.MarkProjectDirty(0)
            lupd.update_gfx = true
            CreateStripCB(true)
            
            ctl_select = nil
            gfx3_select = nil
            
            cbdragstrip = nil
            
          end
        end
      end

    elseif stripgallery_view > 0 then

      if mouse.context == nil then

        --[[if MOUSE_click2(lvar.stripctlbox, mouse.mx-obj.sections[10].x+stlay_data.xpos, mouse.my-obj.sections[10].y) or
            mouse.RB then
          noscroll = true]]

        if (MOUSE_click2(lvar.stripctlboxX, mouse.mx-obj.sections[10].x+stlay_data.xpos, mouse.my-obj.sections[10].y)) then

          xclicked = true
          noscroll = true
          if mouse.LB and mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
            DeleteStrip(lvar.stripctlbox.id, true)
            SetCtlBitmapRedraw(true)
            stlay_data = AutoSnap_GetStripLocs(true)
            CreateStripCB(true)
            lupd.update_surface = true
          end

        elseif mouse.alt and not mouse.altlatch and not mouse.LB and not mouse.RB and MOUSE_over(obj.sections[10]) then

          CreateStripCB()

        end

      else


      end

    end

    return noscroll, xclicked
  end

  function A_Run_StripLayout(noscroll, rt)

    if stripgallery_view == 0 then

      local contexts = contexts
      local mouse = mouse

      local xywh = {x = striplayout_data.x+obj.sections[10].x,
                    y = striplayout_data.y+obj.sections[10].y,
                    w = striplayout_data.w,
                    h = striplayout_data.h}
      if mouse.context == nil and MOUSE_click(xywh) then

        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.3 then

          local mx = math.floor((((mouse.mx-obj.sections[10].x) - striplayout_data.x)/striplayout_data.w)*surface_size.w)
          local my = math.floor((((mouse.my-obj.sections[10].y) - striplayout_data.y)/striplayout_data.h)*surface_size.h)

          --striplayout_selstrip, striplayout_selstripid = GetStripAtXY(tracks[track_select].strip,page,mx,my)
          show_striplayout = false
          SetSurfaceSize2(obj)
          if striplayout_selstripid then

            local sel = striplayout_selstripid
            for i = 1, #stlay_data.reordered do
              if stlay_data.reordered[i].stripid == striplayout_selstrip then
                sel = i
                break
              end
            end
            surface_offset.x = math.floor(F_limit(stlay_data.reordered[sel].l - (obj.sections[10].w/2) + (stlay_data.reordered[sel].w/2),0,surface_size.w-obj.sections[10].w))
            surface_offset.y = math.floor(F_limit(stlay_data.reordered[sel].t - (obj.sections[10].h/2) + (stlay_data.reordered[sel].h/2),0,surface_size.h-obj.sections[10].h))
            if stripgallery_view ~= 0 then
              local xpos
              for i = 1, #stlay_data.loc do
                if stlay_data.loc[i].stripid == striplayout_selstrip then
                  xpos = math.floor(stlay_data.loc[i].runx_s - (obj.sections[10].w/2 - stlay_data.loc[i].w/2))
                  break
                end
              end
              if xpos then
                stlay_data.xpos = xpos
                GUI_DrawCtlBitmap2()
              end
            end

          else

            surface_offset.x = math.floor(F_limit(mx- (obj.sections[10].w/2),0,surface_size.w-obj.sections[10].w))
            surface_offset.y = math.floor(F_limit(my- (obj.sections[10].h/2),0,surface_size.h-obj.sections[10].h))

          end
          striplayout_mt = reaper.time_precise()+striplayout_mtime
          show_striplayout = false

        else
          local mx = math.floor((((mouse.mx-obj.sections[10].x) - (striplayout_data.x))/striplayout_data.w)*surface_size.w)
          local my = math.floor((((mouse.my-obj.sections[10].y) - (striplayout_data.y))/striplayout_data.h)*surface_size.h)

          striplayout_selstrip, striplayout_selstripid = GetStripAtXY(tracks[track_select].strip,page,mx,my)

          if striplayout_selstripid then
            lupd.update_surface = true
            mouse.context = contexts.sa_dragstrip
            --sa_dragstrip = true
          end
        end

      elseif mouse.context == nil and MOUSE_click_RB(xywh) then

        local mx = math.floor((((mouse.mx-obj.sections[10].x) - striplayout_data.x)/striplayout_data.w)*surface_size.w)
        local my = math.floor((((mouse.my-obj.sections[10].y) - striplayout_data.y)/striplayout_data.h)*surface_size.h)

        striplayout_selstrip, striplayout_selstripid = GetStripAtXY(tracks[track_select].strip,page,mx,my)

        if striplayout_selstripid then
          local slx = stlay_data.reordered[striplayout_selstripid].l
          dragstrip2 = {x = mx, y = my, slx = slx}

          mouse.context = contexts.sa_dragstrip2
          --sa_dragstrip = true
        end

      end

      if mouse.context and mouse.context == contexts.sa_dragstrip then

        if mouse.mx ~= mouse.last_x or mouse.my ~= mouse.last_y then
          sa_dragstrip = true
          local mx = math.floor((((mouse.mx-obj.sections[10].x) - striplayout_data.x)/striplayout_data.w)*surface_size.w)
          local my = math.floor((((mouse.my-obj.sections[10].y) - striplayout_data.y)/striplayout_data.h)*surface_size.h)

          striplayout_tgtstrip, striplayout_tgtstripid = GetStripAtXY(tracks[track_select].strip,page,mx,my)

          if striplayout_tgtstrip ~= striplayout_selstrip and striplayout_tgtstrip ~= lasttgtstrip then
            if striplayout_tgtstripid then

              striplayout_tgtpos = 0
              if mx > stlay_data.loc[striplayout_tgtstripid].l+stlay_data.loc[striplayout_tgtstripid].w/2 then
                --striplayout_tgtpos = 1
              end
            end

            if striplayout_selstripid and striplayout_tgtstripid then
              if striplayout_tgtstripid ~= osltgtsid or striplayout_tgtpos ~= osltgtp then
                lupd.update_surface = true
                osltgtsid = striplayout_tgtstripid
                osltgtp = striplayout_tgtpos

                local pos = striplayout_tgtstripid
                if pos then
                  if striplayout_tgtpos == 1 then
                    pos = math.min(pos + 1,#stlay_data.loc)
                  end
                  stlay_data = AutoSnap_ReorderStripLocs(striplayout_selstripid,pos,stlay_data)
                  stlay_data = table.copy(stlay_data)

                end
              end
            end

          end
          lasttgtstrip = striplayout_tgtstrip

        end

      elseif mouse.context and mouse.context == contexts.sa_dragstrip2 then

        local mx = math.floor((((mouse.mx-obj.sections[10].x) - striplayout_data.x)/striplayout_data.w)*surface_size.w)
        local my = math.floor((((mouse.my-obj.sections[10].y) - striplayout_data.y)/striplayout_data.h)*surface_size.h)

        dx = mx-dragstrip2.x

        if dx ~= 0 then

          sa_dragstrip = true
          local nx = dragstrip2.slx + dx
          if stlay_data.reordered[striplayout_selstripid-1] and stlay_data.reordered[striplayout_selstripid-1].t == stlay_data.reordered[striplayout_selstripid].t then
            nx = math.max(nx,stlay_data.reordered[striplayout_selstripid-1].l+stlay_data.reordered[striplayout_selstripid-1].w+autosnap_itemgap)
          end
          if stlay_data.reordered[striplayout_selstripid+1] and stlay_data.reordered[striplayout_selstripid+1].t == stlay_data.reordered[striplayout_selstripid].t then
            nx = math.min(nx,stlay_data.reordered[striplayout_selstripid+1].l-autosnap_itemgap-stlay_data.reordered[striplayout_selstripid].w)
          end
          stlay_data.reordered[striplayout_selstripid].l = F_limit(nx,0,surface_size.w-stlay_data.reordered[striplayout_selstripid].w)
          lupd.update_surface = true

        end

      elseif sa_dragstrip ~= nil then

        AutoSnap_MoveStrips()
        SetCtlBitmapRedraw(true)

        local op = stlay_data.xpos
        stlay_data = AutoSnap_GetStripLocs(true)
        if stripgallery_view ~= 0 then
          stlay_data.xpos = nz(op,0)
        end

        MoveFX(stlay_data)
        CheckStripControls()

        --SetCtlBitmapRedraw()

        sa_dragstrip = nil
        striplayout_tgtstrip = nil
        striplayout_tgtstripid = nil
        lasttgtstrip = nil
        osltgtsid = nil
        osltgtp = nil
        lupd.update_gfx = true


      end

      return true

    elseif stripgallery_view == 1 then

      local w,h = gfx.getimgdim(993)
      local x,y = math.floor(obj.sections[10].x + obj.sections[10].w/2 - w/2), math.floor(obj.sections[10].y + obj.sections[10].h/2-h/2)

      local strip = tracks[track_select].strip

      local xywh = {x = x,
                    y = y,
                    w = w,
                    h = h}
      if mouse.context == nil and MOUSE_click(xywh) then

        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.3 then

          local mx = math.floor(mouse.mx-xywh.x)
          local my = math.floor(mouse.my-xywh.y)

          --striplayout_selstrip, striplayout_selstripid = GetStripAtXY(tracks[track_select].strip,page,mx,my)
          show_striplayout = false
          SetSurfaceSize2(obj)
          if striplayout_selstripid then

            local sel = striplayout_selstripid
            for i = 1, #stlay_data.reordered do
              if stlay_data.reordered[i].stripid == striplayout_selstrip then
                sel = i
                break
              end
            end
            surface_offset.x = math.floor(F_limit(stlay_data.reordered[sel].l - (obj.sections[10].w/2) + (stlay_data.reordered[sel].w/2),0,surface_size.w-obj.sections[10].w))
            surface_offset.y = math.floor(F_limit(stlay_data.reordered[sel].t - (obj.sections[10].h/2) + (stlay_data.reordered[sel].h/2),0,surface_size.h-obj.sections[10].h))
            if stripgallery_view ~= 0 then
              local xpos
              for i = 1, #stlay_data.loc do
                if stlay_data.loc[i].stripid == striplayout_selstrip then
                  xpos = math.floor(stlay_data.loc[i].runx_s - (obj.sections[10].w/2 - stlay_data.loc[i].w/2))
                  break
                end
              end
              if xpos then
                stlay_data.xpos = xpos
                if strips[strip] then
                  strips[strip][page].xpos = xpos
                end
                GUI_DrawCtlBitmap2()
              end
            end

          else

            surface_offset.x = math.floor(F_limit(mx- (obj.sections[10].w/2),0,surface_size.w-obj.sections[10].w))
            surface_offset.y = math.floor(F_limit(my- (obj.sections[10].h/2),0,surface_size.h-obj.sections[10].h))

          end
          striplayout_mt = reaper.time_precise()+striplayout_mtime
          show_striplayout = false

        else
          local mx = math.floor(mouse.mx-xywh.x)
          local my = math.floor(mouse.my-xywh.y)
          striplayout_selstrip, striplayout_selstripid = GetStripAtXYGallery(tracks[track_select].strip,page,mx,my)
          if striplayout_selstripid then
            lupd.update_surface = true
            mouse.context = contexts.sa_dragstrip
          end
        end
      end


      if mouse.context and mouse.context == contexts.sa_dragstrip then

        if mouse.mx ~= mouse.last_x or mouse.my ~= mouse.last_y then
          sa_dragstrip = true
          local mx = math.floor(mouse.mx-xywh.x)
          local my = math.floor(mouse.my-xywh.y)
          striplayout_tgtstrip, striplayout_tgtstripid = GetStripAtXYGallery(tracks[track_select].strip,page,mx,my)

          if striplayout_tgtstrip ~= striplayout_selstrip and striplayout_tgtstrip ~= lasttgtstrip then
            if striplayout_tgtstripid then

              striplayout_tgtpos = 0
              if mx > stlay_data.reordered[striplayout_tgtstripid].l+stlay_data.reordered[striplayout_tgtstripid].w/2 then
                --striplayout_tgtpos = 1
              end
            end

            if striplayout_selstripid and striplayout_tgtstripid then
              if striplayout_tgtstripid ~= osltgtsid or striplayout_tgtpos ~= osltgtp then
                lupd.update_surface = true
                osltgtsid = striplayout_tgtstripid
                osltgtp = striplayout_tgtpos

                local pos = striplayout_tgtstripid
                if pos then
                  if striplayout_tgtpos == 1 then
                    pos = math.min(pos + 1,#stlay_data.reordered)
                  end
                  stlay_data = AutoSnap_ReorderStripLocs(striplayout_selstripid,pos,stlay_data)
                  stlay_data = table.copy(stlay_data)
                end
              end
            end

          end
          lasttgtstrip = striplayout_tgtstrip

        end


      elseif sa_dragstrip ~= nil then

        AutoSnap_MoveStrips()

        SetCtlBitmapRedraw(true)
        local op = stlay_data.xpos

        stlay_data = AutoSnap_GetStripLocs(true)
        if stripgallery_view ~= 0 then
          stlay_data.xpos = nz(op,0)
        end

        MoveFX(stlay_data)
        CheckStripControls()

        --force vertical correction
        --SetCtlBitmapRedraw()

        sa_dragstrip = nil
        striplayout_tgtstrip = nil
        striplayout_tgtstripid = nil
        lasttgtstrip = nil
        osltgtsid = nil
        osltgtp = nil
        lupd.update_gfx = true

      end

    end

  end

  function MoveFX(stlay_data)

    local strip = tracks[track_select].strip
    local trn = strips[strip].track.tracknum
    local track = GetTrack(trn)
    local fxtbl, guididx, trbeg, trend = GetFXChunks(trn)

    local ctls = strips[strip][page].controls
    for c = 1, #ctls do
      if ctls[c].id and ctls[c].fxguid and guididx[ctls[c].fxguid] and fxtbl[guididx[ctls[c].fxguid]] and fxtbl[guididx[ctls[c].fxguid]].stripid == nil then
        fxtbl[guididx[ctls[c].fxguid]].stripid = ctls[c].id
      end
    end

    fxidx = {}
    for i = 1, #stlay_data.reordered do

      for f = 1, #fxtbl do
        if stlay_data.reordered[i].stripid == fxtbl[f].stripid then
          fxidx[#fxidx+1] = f
        end
      end

    end
    local fxchunks = ''
    for i = 1, #fxidx do
      fxchunks = fxchunks..'\n'..fxtbl[fxidx[i]].chunk
    end
    for i = 1, #fxtbl do
      if fxtbl[i].stripid == nil then
        fxchunks = fxchunks..'\n'..fxtbl[i].chunk
      end
    end

    if trbeg and fxchunks and trend then
      local nchunk = trbeg..fxchunks..trend
      SetTrackChunk(track,nchunk, false)
    end

  end

  function TranslateGalleryPos2(mx, my, id)

    local d = stlay_data
    local ii
    local dd
    for i = 1, #d.reordered do
      if d.reordered[i].stripid == id then
        dd = d.reordered[i]
        ii = i
        break
      end
    end
    if dd then

      local dx = dd.runx_s
      local dy = math.floor(((obj.sections[10].h/2)-(dd.h/2)))
      mx, my = dx, dy

    end

    return mx, my, ii

  end

  function TranslateGalleryPos(mx, my, c)

    local d = stlay_data
    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    local id = ctl.id
    local ii
    local dd
    for i = 1, #d.reordered do
      if d.reordered[i].stripid == id then
        dd = d.reordered[i]
        ii = i
        break
      end
    end
    if dd then

      local dx = (mx +stlay_data.xpos) - dd.runx_s
      local dy = my-((obj.sections[10].h/2)-(dd.h/2))
      mx, my = dd.l + dx, dd.t + dy

    end

    return mx, my, ii

  end

  function TranslateGalleryCtlPos(c, ii)

    local d = stlay_data
    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    local id = ctl.id
    local dd
    if ii == nil then
      for i = 1, #d.reordered do
        if d.reordered[i].stripid == id then
          dd = d.reordered[i]
          ii = i
          break
        end
      end
    else
      dd = d.reordered[ii]
    end
    if dd then

      dx = ctl.xsc - dd.l
      dy = ctl.ysc - dd.t

      mx = dx + obj.sections[10].x + (dd.runx_s - stlay_data.xpos )
      my = dy + (obj.sections[10].y+(obj.sections[10].h/2)-(dd.h/2))
    end

    return mx, my, ii


  end

  function TranslateMixPos(mx, my, c, swid)

    if lvar.stripdim then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[c]

      --local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      --local extid = swdata.extid

      if not swid and ctl then
        swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
      end

      if swid and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[swid] then
        local idx = strips[strip][page].popidx[swid]
        local pop = strips[strip][page].pop[idx]
        mx = swdata[swid].sl + (mx - pop.x)
        my = swdata[swid].st + (my - pop.y)
      elseif swid and lvar.spos[swid] then
        mx = (swdata[swid].sl + (mx - lvar.spos[swid].x))--*lvar.zoom
        my = (swdata[swid].st + (my - lvar.spos[swid].y))--*lvar.zoom
        --DBG(swdata[swid].st..'  '..lvar.spos[swid].y)
      end
    end
    return mx, my, swid

  end

  --[[function TranslateMixPos2(mx, my, c, swid)

    if lvar.stripdim then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[c]

      --local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      --local extid = swdata.extid

      if not swid then
        swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
      end

      if swid and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[swid] then
        local idx = strips[strip][page].popidx[swid]
        local pop = strips[strip][page].pop[idx]
        mx = swdata[swid].sl + (mx - pop.x) - surface_offset.x
        my = swdata[swid].st + (my - pop.y) - surface_offset.y
      elseif swid and lvar.spos[swid] then
        mx = obj.sections[10].x + swdata[swid].sl + (mx - lvar.spos[swid].x) - surface_offset.x
        my = obj.sections[10].y + swdata[swid].st + (my - lvar.spos[swid].y) - surface_offset.y
      end
    end
    return mx, my, swid

  end]]

  function TranslateMixPos2(mx, my, c, swid)
  
    if lvar.stripdim then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[c]

      --local posidx = lvar.stripdim.extposidx
      local swdata = lvar.stripdim.swdata
      --local extid = swdata.extid

      if not swid then
        swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
      end

      if swid and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[swid] then
        local idx = strips[strip][page].popidx[swid]
        local pop = strips[strip][page].pop[idx]
        --add lvar.pop_yoff etc
        local xoff, yoff = 0, 0
        if lvar.popout_autoarrange then
          xoff = lvar.pop_xoff or 0
          yoff = lvar.pop_yoff or 0
        end
        mx = swdata[swid].sl + (mx - pop.x - xoff) - surface_offset.x
        my = swdata[swid].st + (my - pop.y - yoff) - surface_offset.y
      elseif swid and lvar.spos[swid] then
        mx = obj.sections[10].x + swdata[swid].sl*lvar.zoom + (mx - lvar.spos[swid].x) - surface_offset.x
        my = obj.sections[10].y + (swdata[swid].st - lvar.mmgap)*lvar.zoom + (my - lvar.spos[swid].y) - surface_offset.y
      end
    end
    return mx, my, swid

  end
  
  function TranslateMixCtlPos(c, swid)
 
    local mx, my = -lvar.maxdim,-lvar.maxdim --, yy|
    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]

    if not swid then
      swid = Switcher_GetTopLevelSwitcher(ctl.switcher)
    end
    local switchid = swid
    if switchid and lvar.stripdim then
      local swdata = lvar.stripdim.swdata[switchid]

      if swdata and switchid and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[switchid] then
        local idx = strips[strip][page].popidx[switchid]
        local pop = strips[strip][page].pop[idx]

        local xoff, yoff = 0, 0
        local switchhoff = (swdata.sb-swdata.st) + lvar.mmgap
        if lvar.popout_autoarrange then
          xoff = lvar.pop_xoff or 0
          yoff = lvar.pop_yoff or 0
          if lvar.popout_autoarrange_hideswitchers then
            switchhoff = 0
          end
        end

        mx = obj.sections[10].x + pop.x + xoff + (ctl.xsc*lvar.zoom - swdata.stripl*lvar.zoom)
        my = obj.sections[10].y + pop.y + yoff + (ctl.ysc- swdata.stript + switchhoff)*lvar.zoom

      elseif lvar.spos and lvar.spos[switchid] then
      --DBG(lvar.spos[switchid].x..'  '..ctl.xsc..'  '..swdata.stripl)
        mx = (lvar.spos[switchid].x + (ctl.xsc - swdata.stripl)*lvar.zoom)
        my = (lvar.spos[switchid].y + (ctl.ysc - swdata.stript + (swdata.sb-swdata.st) + lvar.mmgap)*lvar.zoom)
      end

    end
    return mx ,my, swid

  end

  function A_Run_MorphPU(noscroll, rt)

    local w, h = gfx.getimgdim(skin.morph_pop)
    local d = math.floor((mouse.my-morph_puw.y) / h)+1
    local yp = (mouse.my-morph_puw.y) - (d-1)*h
    local xp = mouse.mx-morph_puw.x
    local dd = 0
    local i, context
    for ii = 1, #morph_data do
      if morph_data[ii].active then
        dd = dd + 1
        if dd == d then
          i = ii
          break
        end
      end
    end

    context = contexts.dummy

    if i then
      if yp >= 28 and yp <= 50 then
        if xp <= 40 then
          --shape
          if mouse.LB then
            morph_data[i].morph_scale = nz(morph_data[i].morph_scale,1) + 1
            if morph_data[i].morph_scale > #lvar.macroscale_table then
              morph_data[i].morph_scale = 1
            end
            lupd.update_snaps = true
          else
            morph_data[i].morph_scale = nz(morph_data[i].morph_scale,1) - 1
            if morph_data[i].morph_scale < 1 then
              morph_data[i].morph_scale = #lvar.macroscale_table
            end
            lupd.update_snaps = true
          end

        elseif xp <= 68 then
          --stop
          nl = 1
          morph_data[i].morph_loop = nl
          morph_data[i].active = false
          lupd.update_surface = true
          lupd.update_snaps = true

        elseif xp <= 96 then
          --pause
          if not morph_data[i].paused then
            morph_data[i].paused = morph_data[i].end_time-reaper.time_precise()
          else
            morph_data[i].end_time = reaper.time_precise() + morph_data[i].paused
            morph_data[i].start_time = morph_data[i].end_time - morph_data[i].morph_time
            morph_data[i].paused = nil
          end
          lupd.update_snaps = true

        else
          --play
          if mouse.LB then
            local nl = (morph_data[i].morph_loop or 1) + 1
            if nl > 3 then
              nl = 2
            end
            morph_data[i].morph_loop = nl
            lupd.update_snaps = true
          else
            morph_data[i].dir = 1-(morph_data[i].dir or 0)
            morph_data[i].origst = morph_data[i].start_time
            local t = reaper.time_precise()
            if morph_data[i].dir ~= 1 then
              if morph_data[i].paused then
                morph_data[i].paused = morph_data[i].morph_time - morph_data[i].paused
              else
                morph_data[i].start_time = t - (morph_data[i].morph_time*morph_data[i].p)
                morph_data[i].end_time = morph_data[i].start_time + morph_data[i].morph_time
              end
            else
              if morph_data[i].paused then
                morph_data[i].paused = morph_data[i].morph_time - morph_data[i].paused
              else
                morph_data[i].start_time = t - (morph_data[i].morph_time*(1-morph_data[i].p))
                morph_data[i].end_time = morph_data[i].start_time + morph_data[i].morph_time
              end
            end
            lupd.update_snaps = true
          end
        end

      elseif yp < 28 then

        if morph_data[i].paused then

          context = contexts.morph_puw_slider
          puwdata = {xoff = xp, pos = morph_data[i].p, i = i, x = morph_puw.x, y = morph_puw.y, w = w, h = h}
          oms = mouse.shift

        end

      end
    end
    return true, context

  end

  function SBWin_CheckSize()
    if settings_sbdock == true then
      if lvar.stripbrowser.dockpos == 1 then

        local maxh
        if settings_moddock == true and show_lfoedit == true then
          maxh = gfx1.main_h - obj.sections[1350].y - obj.sections[1100].h
        else
          maxh = gfx1.main_h - obj.sections[1350].y
        end
        if sbwin.h*pnl_scale > maxh then
          sbwin.h = math.min(sbwin.h,math.floor(maxh/pnl_scale))
        end

      else

        local maxw
        if settings_ssdock == true and show_snapshots == true then
          maxw = gfx1.main_w - plist_w - obj.sections[160].w
        else
          maxw = gfx1.main_w - plist_w
        end
        if sbwin.w*pnl_scale > maxw then
          sbwin.w = math.min(sbwin.w,math.floor(maxw/pnl_scale))
        end

        if settings_ssdock == true and show_snapshots == true then
          sbwin.x = obj.sections[160].x-math.floor(sbwin.w*pnl_scale)
        else
          sbwin.x = gfx1.main_w-math.floor(sbwin.w*pnl_scale)
        end

      end

    else


    end
  end

  function SBDock(d)

    if not lvar.stripbrowser.fullscreen then
      if d == true then
        if d ~= settings_sbdock then
          lvar.osbh = {x = obj.sections[1350].x,
                        y = obj.sections[1350].y,
                        w = obj.sections[1350].w,
                        h = obj.sections[1350].h}
        end
        --if lvar.osbh2 then
          sbwin.w = math.floor(lvar.sbmin*pnl_scale) --math.floor(lvar.osbh2.w/pnl_scale)
          sbwin.h = math.floor(lvar.sbmin*pnl_scale) --math.floor(lvar.osbh2.h/pnl_scale)
          resize_display = true
        --end
      elseif lvar.osbh then
        if d ~= settings_sbdock then
          lvar.osbh2 = {x = obj.sections[1350].x,
                        y = obj.sections[1350].y,
                        w = obj.sections[1350].w,
                        h = obj.sections[1350].h}
        end
        sbwin.w = math.floor(lvar.osbh.w/pnl_scale)
        sbwin.h = math.floor(lvar.osbh.h/pnl_scale)
        obj.sections[1350] = lvar.osbh
        resize_display = true
      else
        if d ~= settings_sbdock then
          lvar.osbh2 = {x = sbwin.x or obj.sections[1350].x,
                        y = sbwin.y or obj.sections[1350].y,
                        w = sbwin.w or obj.sections[1350].w,
                        h = sbwin.h or obj.sections[1350].h}
        end
        sbwin.w = sbwin.w or (180*pnl_scale)
        sbwin.h = sbwin.h or (216*pnl_scale)
  
        resize_display = true
      end
      settings_sbdock = d
      SBWin_CheckSize()
  
      obj = GetObjects()
      lupd.update_gfx = true
    else
      settings_sbdock = false
      obj = GetObjects()
      lupd.update_gfx = true
    end
  end

  function DuplicateStrip()

    --select only track
    local srctn = tracks[track_select].tracknum
    local srctguid = tracks[track_select].guid
    local dsttn, dsttguid
    local sstrip = tracks[track_select].strip
    local track = GetTrack(srctn)

    if track then
      reaper.SetOnlyTrackSelected(track)
      reaper.Main_OnCommand(40062,1)
      dsttn = srctn+1 --assume duplicate track is next track
      local track2 = GetTrack(dsttn)
      dsttguid = GetTrackGUID(track2)

      local fxlst = {}
      for i = 0, reaper.TrackFX_GetCount(track2)-1 do

        local sgui = reaper.TrackFX_GetFXGUID(track, i)
        local dgui = reaper.TrackFX_GetFXGUID(track2, i)
        fxlst[i] = {sgui = sgui,
                    dgui = dgui}
        fxlst[sgui] = dgui

      end

      --Copy strip data
      PopulateTracks()
      ChangeTrack(dsttn)
      --DBG(reaper.GetTrackState(track2)..'  '..track_select)

      local dstrip = Strip_INIT()
      Snapshots_INIT()

      for p = 1, lvar.maxpage do
        strips[dstrip][p] = table.deepcopy(strips[sstrip][p])
        snapshots[dstrip][p] = table.deepcopy(snapshots[sstrip][p])

        local stripids = {}
        local grpids = {}
        local cids = {}
        local swids = {}
        local extids = {}
        local swcnt = #switchers+1

        strips[dstrip][p].pop = nil

        for c = 1, #strips[dstrip][p].controls do
          local ctl = strips[dstrip][p].controls[c]
          ctl.ext_identifier = nil
          if ctl.id then
            if not stripids[ctl.id] then
              stripids[ctl.id] = GenID()
            end
          end
          if ctl.grpid then
            if not grpids[ctl.grpid] then
              grpids[ctl.grpid] = GenID()
            end
          end
          if ctl.ctlcat == ctlcats.switcher and ctl.switcherid then
            local swid = #switchers+1
            swids[ctl.switcherid] = swid
            switchers[swid] = table.deepcopy(switchers[ctl.switcherid])
          end
          cids[ctl.c_id] = GenID()
        end

        for g = 1, #strips[dstrip][p].graphics do
          local ctl = strips[dstrip][p].graphics[g]
          if ctl.id then
            if not stripids[ctl.id] then
              stripids[ctl.id] = GenID()
            end
          end
          if ctl.grpid then
            if not grpids[ctl.grpid] then
              grpids[ctl.grpid] = GenID()
            end
          end
        end

        for s = swcnt, #switchers do
          if switchers[s].extendid then
            if not extids[switchers[s].extendid] then
              extids[switchers[s].extendid] = GenID()
            end
            switchers[s].extendid = extids[switchers[s].extendid]
          end
          for g = 1, #switchers[s].grpids do
            switchers[s].grpids[g].id = grpids[switchers[s].grpids[g].id]
          end
          if switchers[s].fxguids then
            for f = 1, #switchers[s].fxguids do
              switchers[s].fxguids[f] = fxlst[switchers[s].fxguids[f]]
            end
          end
          if switchers[s].parent and switchers[s].parent.switcherid then
            switchers[s].parent.switcherid = swids[switchers[s].parent.switcherid]
            switchers[s].parent.grpid = grpids[switchers[s].parent.grpid]
          end
          if switchers[s].current then
            switchers[s].current = grpids[switchers[s].current]
          end
        end

        for c = 1, #strips[dstrip][p].controls do
          local ctl = strips[dstrip][p].controls[c]
          ctl.c_id = cids[ctl.c_id]
          if ctl.id then
            ctl.id = stripids[ctl.id]
          end
          if ctl.grpid then
            ctl.grpid = grpids[ctl.grpid]
          end
          if ctl.fxguid and (ctl.trackguid == nil or ctl.trackguid == srctguid) then
            ctl.fxguid = fxlst[ctl.fxguid]
          end
          if ctl.ctlcat == ctlcats.switcher then
            ctl.switcherid = swids[ctl.switcherid]
          end
          if ctl.switcher then
            ctl.switcher = swids[ctl.switcher]
          end
          if ctl.ctlcat == ctlcats.switcher_pagesel then
            ctl.param = grpids[ctl.param]
          end

          if ctl.trackguid == srctguid then
            ctl.trackguid = dsttguid
          end

          if ctl.addfx then
            for a = 1, #ctl.addfx do
              if ctl.addfx[a].trguid == srctguid then
                ctl.addfx[a].trguid = dsttguid
                ctl.addfx[a].guid = fxlst[ctl.addfx[a].guid]
              end
            end
          end

          if ctl.eqbands then
            for a = 1, #ctl.eqbands do
              ctl.eqbands[a].fxguid = fxlst[ctl.eqbands[a].fxguid]
            end
          end

          if ctl.random then

            ctl.random.parent_cid = cids[ctl.random.parent_cid]
            if ctl.random.ctls then
              for cc = 1, #ctl.random.ctls do
                ctl.random.ctls[cc].c_id = cids[ctl.random.ctls[cc].c_id]
              end
            end

          end

          --snapshots + c_ids
        end

        for g = 1, #strips[dstrip][p].graphics do
          local ctl = strips[dstrip][p].graphics[g]
          if ctl.id then
            ctl.id = stripids[ctl.id]
          end
          if ctl.grpid then
            ctl.grpid = grpids[ctl.grpid]
          end
          if ctl.switcher then
            ctl.switcher = swids[ctl.switcher]
          end
        end

        --snapshots
        local s_ids = {}

        for sst = 1, #snapshots[dstrip][p] do
          local sdata_ss
          if sst == 1 then
            sdata_ss = snapshots[dstrip][p][sst]
          else

            local sdatactls = snapshots[dstrip][p][sst].ctls
            for c = 1, #sdatactls do
              sdatactls[c].c_id = cids[sdatactls[c].c_id]

              local id = GenID()
              s_ids[sdatactls[c].id] = id
              sdatactls[c].id = id
            end

            sdata_ss = snapshots[dstrip][p][sst].snapshot
          end
          for ss = 1, #sdata_ss do

            local sdata
            if sst == 1 then
              sdata = snapshots[dstrip][p][sst][ss]
            else
              sdata = snapshots[dstrip][p][sst].snapshot[ss]
            end

            for d = 1, #sdata.data do
              sdata.data[d].c_id = cids[sdata.data[d].c_id]
              if sst > 1 then
                sdata.data[d].id = s_ids[sdata.data[d].id]
              end
              if sdata.data[d].mf then
                if sdata.data[d].mfdata.strip == sstrip then
                  sdata.data[d].mfdata.strip = dstrip
                  if sdata.data[d].mfdata.c_id then
                    sdata.data[d].mfdata.c_id = cids[sdata.data[d].mfdata.c_id]
                  end
                end
              end

              --sdata.data[d].mf = nil
              --sdata.data[d].mfdata = nil
              --sdata.data[d].mfset = nil

            end

            if sdata.moddata then
              for m = 1, #faders do

                if sdata.moddata[m] then

                  for t = 1, #sdata.moddata[m].targets do
                    if sdata.moddata[m].targets[t] then
                      if sdata.moddata[m].targets[t].strip == sstrip then
                        sdata.moddata[m].targets[t].strip = dstrip
                        if sdata.moddata[m].targets[t].c_id then
                          sdata.moddata[m].targets[t].c_id = cids[sdata.moddata[m].targets[t].c_id]
                        end
                      end
                    end
                  end
                end
              end
            end
            if sdata.faddata then
              for m = 1, #faders do

                if sdata.faddata[m] then

                  if sdata.faddata[m].strip == sstrip then
                    sdata.faddata[m].strip = dstrip
                    if sdata.faddata[m].c_id then
                      sdata.faddata[m].c_id = cids[sdata.faddata[m].c_id]
                    end
                  end
                end
              end
            end

            sdata.modset = nil
            sdata.moddata = nil
            sdata.fadset = nil
            sdata.faddata = nil


          end
        end

      end

    end
    ChangeTrack2(dsttn)
    update_gfx = true

  end

  function DupSend(OrigSendTrack, NewSendTrack, DestTrack, sendno, recno)
    local sidx = reaper.CreateTrackSend(NewSendTrack, DestTrack)

    local B_MUTE,B_PHASE,B_MONO,D_VOL,D_PAN,D_PANLAW,I_SENDMODE,I_SRCCHAN,I_DSTCHAN,I_MIDIFLAGS
    if sendno then
      B_MUTE = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'B_MUTE')
      B_PHASE = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'B_PHASE')
      B_MONO = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'B_MONO')
      D_VOL = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'D_VOL')
      D_PAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'D_PAN')
      D_PANLAW = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'D_PANLAW')
      I_SENDMODE = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'I_SENDMODE')
      I_SRCCHAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'I_SRCCHAN')
      I_DSTCHAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'I_DSTCHAN')
      I_MIDIFLAGS = reaper.GetTrackSendInfo_Value(OrigSendTrack, 0, sendno, 'I_MIDIFLAGS')
    else
      B_MUTE = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'B_MUTE')
      B_PHASE = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'B_PHASE')
      B_MONO = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'B_MONO')
      D_VOL = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'D_VOL')
      D_PAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'D_PAN')
      D_PANLAW = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'D_PANLAW')
      I_SENDMODE = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'I_SENDMODE')
      I_SRCCHAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'I_SRCCHAN')
      I_DSTCHAN = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'I_DSTCHAN')
      I_MIDIFLAGS = reaper.GetTrackSendInfo_Value(OrigSendTrack, -1, recno, 'I_MIDIFLAGS')
    end

    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'B_MUTE', B_MUTE)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'B_PHASE', B_PHASE)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'B_MONO', B_MONO)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'D_VOL', D_VOL)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'D_PAN', D_PAN)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'D_PANLAW', D_PANLAW)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'I_SENDMODE', I_SENDMODE)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'I_SRCCHAN', I_SRCCHAN)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'I_DSTCHAN', I_DSTCHAN)
    reaper.SetTrackSendInfo_Value(NewSendTrack, 0, sidx, 'I_MIDIFLAGS', I_MIDIFLAGS)

  end

  function TSM_Trigger()
    if lvar.TSM_MOver then
      if lvar.TSM_FocusHwnd then
        reaper.JS_Window_SetFocus(lvar.TSM_FocusHwnd)
      end
      if lvar.TSM_LegalMP then
        reaper.JS_Mouse_SetPosition(lvar.TSM_LegalMP.x, lvar.TSM_LegalMP.y)
      end
      --lvar.TSM_Timer = reaper.time_precise()+lvar.TSM_time
      --lvar.TSM_MOver = nil
    end
  end

  ------------------------
  --- M0 MOUSE CLICK
  ------------------------

  function A_Click_M0_StripSurface(rt, noscroll)
    
    local togfsnap = false
    
    if mouse.mx > obj.sections[10000].x then
      if strips and tracks[track_select] and strips[tracks[track_select].strip] then

        local i
        --local ttt = reaper.time_precise()
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)

        --[[if lvar.livemode == 2 and MOUSE_click(obj.sections[5000]) then

          c = nil
          noscroll = true

          GUI_DrawButton(gui,'REFRESH',obj.sections[5000],-2,gui.color.white,true,nil,nil,4)
          lupd = GUI_draw(obj, gui)
          gfx.update()
          DM_RefreshPage()

        else]]if lvar.livemode >= 1 and lvar.mmov_show == true then
          if mouse.RB then
            local strip = tracks[track_select].strip
            if (lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0 and strips[strip][page].pop and #strips[strip][page].pop > 0)) then
              if lvar.mixmodedir == 0 then
                local mpad = lvar.mmov_pad
                if mouse.mx < obj.sections[10000].x+lvar.mmov_vsize+mpad*2 then
                  Process_MMOV2(rt,nil,true)
                  c = nil
                  noscroll = true
                end
              else
                local mpad = lvar.mmov_pad
                if mouse.my < obj.sections[10000].y+lvar.mmov_vsize+mpad*2 then
                  Process_MMOV2(rt,nil,true)
                  c = nil
                  noscroll = true
                end
              end
            else
              if lvar.mixmodedir == 0 then
                local mpad = lvar.mmov_pad
                if mouse.mx < obj.sections[10000].x+lvar.mmov_vsize+mpad*2 then
                  mouse.context = contexts.mmov_dragv
                  lvar.mixupdate = nil
                  lvar.mmov_drag = true
                  c = nil
                  noscroll = true
                end
              else
                local mpad = lvar.mmov_pad
                if mouse.my < obj.sections[10000].y+lvar.mmov_vsize+mpad*2 then
                  mouse.context = contexts.mmov_dragh
                  lvar.mixupdate = nil
                  lvar.mmov_drag = true
                  c = nil
                  noscroll = true
                end
              end
            end

          elseif mouse.LB then
            if lvar.mixmodedir == 0 then
              local mpad = lvar.mmov_pad
              if mouse.mx < obj.sections[10000].x+lvar.mmov_vsize+mpad*2 then
                Process_MMOV2(rt,true,nil)
                c = nil
                noscroll = true
              end
            else
              local mpad = lvar.mmov_pad
              if mouse.my < obj.sections[10000].y+lvar.mmov_vsize+mpad*2 then
                Process_MMOV2(rt,true,nil)
                c = nil
                noscroll = true
              end
            end
          elseif gfx.mouse_wheel ~= 0 then
            if lvar.mixmodedir == 0 then
              local mpad = lvar.mmov_pad
              if mouse.mx < obj.sections[10000].x+lvar.mmov_vsize+mpad*2 then
                if mouse.shift then
                  local v = mousewheel_val() --
                  lvar.mmov_vsize = F_limit(lvar.mmov_vsize + v*4,32,200)
                  lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)
                  lupd.update_mmov = true
                  lupd.update_surface = true
                  --Repos5001()
                  Repos5005()
                  GUI_DrawCtlBitmap_Mix()
                  RedrawGUIBitmap()
                  gfx.mouse_wheel = 0
                else
                  if obj.sections[10000].h < lvar.mmov_max then
                    local v = mousewheel_val() --
                    lvar.mmov_pos = F_limit(lvar.mmov_pos - v*20,0,lvar.mmov_max-obj.sections[10000].h)
                    lupd.update_surface = true
                  end
                  gfx.mouse_wheel = 0
                end                  
              end
            else
              local mpad = lvar.mmov_pad
              if mouse.my < obj.sections[10000].y+lvar.mmov_vsize+mpad*2 then
                if mouse.shift then
                  local v = mousewheel_val() --
                  lvar.mmov_vsize = F_limit(lvar.mmov_vsize + v*4,32,200)
                  lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)
                  lupd.update_mmov = true
                  lupd.update_surface = true
                  --Repos5001()
                  Repos5005()
                  GUI_DrawCtlBitmap_Mix()
                  RedrawGUIBitmap(0.3)
                  gfx.mouse_wheel = 0
                else
                  if obj.sections[10000].w < lvar.mmov_max then  
                    local v = mousewheel_val() --
                    lvar.mmov_pos = F_limit(lvar.mmov_pos - v*20,0,lvar.mmov_max-obj.sections[10000].w)
                    lupd.update_surface = true
                  end
                  gfx.mouse_wheel = 0
                end
              end
            end
          end
        end
        if lvar.livemode >= 1 and gfx.mouse_wheel ~= 0 then
          --surface wheel
          if lvar.showpop and lvar.popout_autoarrange then
            if mouse.ctrl then
              local v = gfx.mouse_wheel
              if v < 0 then
                MixMode_Swipe_Pop(0, false)
              else
                MixMode_Swipe_Pop(1, false)
              end
              SetCtlBitmapRedraw_Mix()
              gfx.mouse_wheel = 0
            end
          end
        end
        
        if lvar.livemode >= 1 and gfx.mouse_wheel == 0 and lvar.mmtouch and mouse.LB then
          if stripid then
            local switchid
            if lvar.stripdim then
              switchid = lvar.stripdim.swidx[stripid]
            else
              for i = 1, #ctls do
                if ctls[i].id == stripid then
                  switchid = ctls[i].switcher
                  break
                end
              end
            end

            if switchid and switchers[switchid] and not noscroll then
              lvar.active_switcher = {switchid = switchid}
              local swdata = lvar.stripdim.swdata
              if not c and lvar.popout_autoarrange and swdata[switchid] then
                local rn = swdata[switchid].rownum
                if rn then
                  MixMode_Swipe_Pop(0,false,rn-1)
                end
              end
              
              if switchers[switchid].fxguids then
                local fxguid = switchers[switchid].fxguids[1]
                if fxguid and lvar.lasttouchedfx ~= fxguid then
                  lvar.lasttouchedfx = fxguid
                  local track = GetTrack(lvar.dynamicmode_trn)
                  if track then
                    local trguid = GetTrackGUID(track)
                    local fxn = GetFXNFromGUID(track,fxguid)
                    if fxn then
                      TouchFX(track, trguid, fxn, fxguid)
                    end
                  end
                end
              end
            end
          end
        end
        
        if c then
          i = c

          local ctl = ctls[i]
          ctlxywh = {x = ctl.xsc * lvar.zoom - surface_offset.x * lvar.zoom +obj.sections[10].x,
                     y = ctl.ysc * lvar.zoom - surface_offset.y * lvar.zoom +obj.sections[10].y,
                     w = ctl.wsc * lvar.zoom,
                     h = ctl.hsc * lvar.zoom}
          noscroll = (ctls[i].ctllock or noscroll)
        elseif MC() and mouse.shift and stripid and lvar.livemode >= 1 --[[and (not lvar.showpop or not lvar.popout_autoarrange)]] then
          lvar.dragswitcher = DragSwitcher_Ext(stripid)
          if lvar.dragswitcher then
            local strip = tracks[track_select].strip
            lvar.omx, lvar.omy = mouse.mx, mouse.my

            if lvar.livemode >= 1 and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[lvar.dragswitcher.selected] then
              PopOut_ToTop(lvar.dragswitcher.selected)
            else
              switchers[lvar.dragswitcher.selected].dragging = true
              lupd.update_surface = true
            end
            lvar.edgedrag_mult = 1
            mouse.context = contexts.switchdrag_ext2
          end
          --[[if lvar.dragswitcher then
            switchers[lvar.dragswitcher.selected].dragging = true
            lupd.update_surface = true

            mouse.context = contexts.switchdrag_ext2
          end]]
        elseif stripid and lvar.livemode >= 1 then
          if lvar.stripdim then
            switchid = lvar.stripdim.swidx[stripid]
            if lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[switchid] then
              --if not lvar.popout_autoarrange then --cannot drag strips so no need to make top
                PopOut_ToTop(switchid)
              --end
            end
          end
        end

        if i and not ctls[i].hidden and not ctls[i].ctllock then

          if ctls[i].fxfound or ctls[i].ctlcat == ctlcats.switcher then

            if MOUSE_LB() or gfx.mouse_wheel ~= 0 then
              lvar.disabletakeover_ctl = i
            end

            local skip
            if ctls[i].ctlcat == ctlcats.fxmulti then
              if MOUSE_LB() then
                local ctl = ctls[i]
                local cval = ctl.val
                local trn = ctl.tracknum or tracks[track_select].tracknum
                if mouse.ctrl then
                  SetFXOffline3(trn, ctl.fxnum, 1)
                elseif mouse.shift then
                  SetFXOffline3(trn, ctl.fxnum, 0, 1)
                else
                  SetFXOffline3(trn, ctl.fxnum, 0, 0)
                  if cval <= 0.34 then
                    ToggleFXWet(strip, page, i, strips[strip].track.tracknum)
                  else
                    ToggleFXWet(strip, page, i, strips[strip].track.tracknum,true)
                  end
                end
                SetCtlEnabled(ctl.fxnum)

                local state = FXMulti_GetState(tr, ctl)
                ctl.val = (state-1)/(#lvar.fxmulti_table-1)

                if ctl.addfx and #ctl.addfx > 0 then
                  local tr = GetTrack(ctl.tracknum or tracks[track_select].tracknum)
                  if tr then
                    FXMulti_SetAddFX(ctl, state)
                  end
                end

                SetCtlDirty(i)
                lupd.update_ctls = true

                skip = true
                noscroll = true
              end
              
            elseif ctls[i].ctlcat == ctlcats.sk2ctl then
              if mouse.shift and mouse.ctrl then
              
                mouse.context = contexts.sk2_dragassign
                local idx = tonumber(ctls[i].param_info.paramidx)
                if idx then
                  if lvar.sk2data_assign[idx] and lvar.sk2data_assign[idx].active == 1 then
                    local name = ctls[i].fxslot_name or lvar.sk2data_assign[idx].name or 'SWAP'
                    local wwdata
                    local sz = 50
                    GUI_StrFontOnly(gui, 0, _, _)
                    wwdata, th = GetWWData(name, sz*2-12)
                    if not wwdata[#wwdata].t then
                      wwdata[#wwdata] = nil
                    end
                    lvar.sk2drag = {ctl = ctls[i], c = i, name = name, wwdata = wwdata, th = th, sz = sz}
                  end
                end
                skip = true
                noscroll = true
              
              elseif mouse.ctrl and mouse.alt then
                
                local i = tonumber(ctls[i].param_info.paramidx)
                if i then
                  reaper.SetExtState(REMSCRIPT, 'REMOTE_CTL', 'SK2_LEARNFX', false)
                  reaper.SetExtState(REMSCRIPT, 'REMOTE_DATA', i+1, false)
                end
              end
            end

            local todef = false

            if not skip then
              if MOUSE_LB() and not mouse.ctrl and not mouse.alt then
             
                local ctltype = ctls[i].ctltype

                if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 and ctltype ~= 5 and ctltype ~= 2 and ctltype ~= 3 then
                  if ctls[i].ctlcat ~= ctlcats.rs5k then
                    if settings_swapctrlclick == false then
                      SetParam_ToDef(i)
                      todef = true
                    else
                      SetParam_EnterVal(i)
                    end
                  else
                    SetShowSampleManager(true, i)
                  end
                  noscroll = true

                end

                --if ctltype == 12 then

                if ctltype == 1 or ctltype == 11 or ctltype == 12 then
                  if ctltype == 12 then
                    lvar.magnetic_active = i
                  end

                  local ctype = ctl_files[ctls[i].knob_select].ctltype

                  if ctls[i].ctlcat ~= ctlcats.macro then
                    --knob/slider
                    if ctype ~= 5 and ctype ~= 6 and ctype ~= 7 then
                      if lvar.sliderxy == true then
                        mouse.context = contexts.sliderctlxy
                        mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                        mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                        octlval = ctls[i].val
                        if lvar.hidecursordrag == true then
                          mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                          lvar.hidecursor = true
                          --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                        end

                      else
                        if ctls[i].horiz then
                          mouse.context = contexts.sliderctl_h
                          mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                          octlval = ctls[i].val
                          if lvar.hidecursordrag == true then
                            mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                            lvar.hidecursor = true
                            --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                          end

                        else
                          mouse.context = contexts.sliderctl
                          mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                          octlval = ctls[i].val
                          if lvar.hidecursordrag == true then
                            mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                            lvar.hidecursor = true
                            --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                          end
                        end
                      end
                      ctlpos = ctlScaleInv(ctls[i].scalemode or 8,
                                           ctls[i].val)
                    else

                      if todef == false then
                        local ctl = ctls[i]
                        if ctype == 6 or (ctype == 7 and ctl.horiz == true) then
                          mouse.context = contexts.sliderctl_h_t2
                          slidt2 = {}
                          slidt2.offs = 0
                          slidt2.knbsz = ctl_files[ctl.knob_select].knbsz * lvar.zoom

                          local mx = mouse.mx-ctlxywh.x
                          local my, ci
                          if stripgallery_view > 0 then
                            mx, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
                            mx, my = mx - ctlxywh.x, my - ctlxywh.y
                          end
                          local knbctr = math.floor((ctlxywh.w-(slidt2.knbsz*ctl.scale)) * ctlScaleInv(ctl.scalemode,ctl.val)) + math.floor((slidt2.knbsz*ctl.scale)/2)
                          if mx >= knbctr-math.ceil((slidt2.knbsz*ctl.scale)/2) and mx <= knbctr+math.ceil((slidt2.knbsz*ctl.scale)/2) then
                            slidt2.offs = mx-knbctr
                          end

                        elseif ctype == 5 or ctype == 7 then

                          mouse.context = contexts.sliderctl_t2
                          slidt2 = {}
                          slidt2.offs = 0
                          slidt2.knbsz = ctl_files[ctl.knob_select].knbsz * lvar.zoom

                          if lvar.livemode == 0 then
                            local my = (mouse.my-ctlxywh.y)
                            local mx, ci
                            if stripgallery_view > 0 then
                              mx, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
                              mx, my = mx - ctlxywh.x, my - ctlxywh.y
                            end
                            local knbctr = math.floor((ctlxywh.h -(slidt2.knbsz*ctl.scale)) - math.floor((ctlxywh.h -(slidt2.knbsz*ctl.scale))
                                           * ctlScaleInv(ctl.scalemode,ctl.val)) + math.floor((slidt2.knbsz*ctl.scale)/2))

                            if my >= knbctr-math.ceil((slidt2.knbsz*ctl.scale)/2) and my <= knbctr+math.ceil((slidt2.knbsz*ctl.scale)/2) then
                              slidt2.offs = math.floor((my-knbctr))
                            end
                          else
                            local mx, my, swid

                            _, _, swid = TranslateMixPos(mouse.mx, mouse.my, i)
                            local xx, yy = TranslateMixCtlPos(i, swid)
                            my = mouse.my - yy -math.floor((((slidt2.knbsz)*ctl.scale)/2))

                            slidt2.swid = swid
                            local knbctr = math.floor((ctlxywh.h -(slidt2.knbsz*ctl.scale)) - ((ctlxywh.h -(slidt2.knbsz*ctl.scale))
                                            * ctlScaleInv(ctl.scalemode,ctl.val)) )-- math.floor((slidt2.knbsz*ctl.scale)/2)) --+((lvar.zoom-1)*4)*(slidt2.knbsz/lvar.zoom)
                            if my >= knbctr-math.ceil((slidt2.knbsz*ctl.scale)/2) and my <= knbctr+math.ceil((slidt2.knbsz*ctl.scale)/2) then
                              slidt2.offs = math.floor(my-knbctr)
                            end
                          end
                        end
                      end
                    end
                    trackfxparam_select = i
                    oms = mouse.shift
                  else
                    if ctype ~= 5 and ctype ~= 6 and ctype ~= 7 then
                      if lvar.sliderxy == true then
                        mouse.context = contexts.macctlxy
                        mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                        mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                        octlval = ctls[i].val
                        if lvar.hidecursordrag == true then
                          mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                          lvar.hidecursor = true
                          --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                        end
                      else
                        if ctls[i].horiz then
                          mouse.context = contexts.macctl_h
                          mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                          octlval = ctls[i].val
                          if lvar.hidecursordrag == true then
                            mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                            lvar.hidecursor = true
                            --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                          end

                        else
                          mouse.context = contexts.macctl
                          mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                          octlval = ctls[i].val
                          if lvar.hidecursordrag == true then
                            mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                            lvar.hidecursor = true
                            --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                          end

                        end
                      end
                      ctlpos = ctlScaleInv(nz(ctls[i].scalemode,8),
                                           ctls[i].val)
                    else

                      if todef == false then
                        local ctl = ctls[i]
                        if ctype == 6 or (ctype == 7 and ctl.horiz == true) then
                          mouse.context = contexts.macsliderctl_h_t2
                          slidt2 = {}
                          slidt2.offs = 0
                          slidt2.knbsz = ctl_files[ctl.knob_select].knbsz * lvar.zoom

                          local mx = mouse.mx-ctlxywh.x
                          local my, ci
                          if stripgallery_view > 0 then
                            mx, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
                            mx, my = mx - ctlxywh.x, my - ctlxywh.y
                          end
                          local knbctr = math.floor((ctlxywh.w-(slidt2.knbsz*ctl.scale)) * ctlScaleInv(ctl.scalemode,ctl.val)) + math.floor((slidt2.knbsz*ctl.scale)/2)
                          if mx >= knbctr-math.ceil((slidt2.knbsz*ctl.scale)/2) and mx <= knbctr+math.ceil((slidt2.knbsz*ctl.scale)/2) then
                            slidt2.offs = mx-knbctr
                          end

                        elseif ctype == 5 or ctype == 7 then
                          mouse.context = contexts.macsliderctl_t2
                          slidt2 = {}
                          slidt2.offs = 0
                          slidt2.knbsz = ctl_files[ctl.knob_select].knbsz * lvar.zoom

                          local my = mouse.my-ctlxywh.y
                          local mx, ci
                          if stripgallery_view > 0 then
                            mx, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
                            mx, my = mx - ctlxywh.x, my - ctlxywh.y
                          end
                          local knbctr = (ctlxywh.h-(slidt2.knbsz*ctl.scale)) - math.floor((ctlxywh.h-(slidt2.knbsz*ctl.scale)) * ctlScaleInv(ctl.scalemode,ctl.val)) + math.floor((slidt2.knbsz*ctl.scale)/2)
                          if my >= knbctr-math.ceil((slidt2.knbsz*ctl.scale)/2) and my <= knbctr+math.ceil((slidt2.knbsz*ctl.scale)/2) then
                            slidt2.offs = my-knbctr
                          end
                        end
                      end

                    end

                    macctlactive = i
                    --ctls[i].mval = nil
                    trackfxparam_select = i
                    oms = mouse.shift
                  end
                  if ctls[i].mod and mod_select ~= ctls[i].mod then
                    mod_select = ctls[i].mod
                    lupd.update_gfx = true
                  end

                  --undotxt = 'Parameter Change'
                  --reaper.Undo_BeginBlock2()

                elseif ctltype == 2 or ctltype == 3 then
                  --button/button inverse
                  if lvar.TSM_MOver then
                    if lvar.TSM_FocusHwnd then
                      reaper.JS_Window_SetFocus(lvar.TSM_FocusHwnd)
                    end
                    if lvar.TSM_LegalMP then
                      reaper.JS_Mouse_SetPosition(lvar.TSM_LegalMP.x, lvar.TSM_LegalMP.y)
                    end
                    --lvar.TSM_Timer = reaper.time_precise()+lvar.TSM_time
                    --lvar.TSM_MOver = nil
                  end

                  trackfxparam_select = i
                  ctls[i].oval = ctls[i].val
                  if ctls[i].val and ctls[i].val < 0.5 then
                    ctls[i].val = 1
                  else
                    ctls[i].val = 0
                  end

                  if ctls[i].mod == nil or (ctls[i].mod and modulators[ctls[i].mod].active ~= true) then
                    A_SetParam(tracks[track_select].strip,page,i,ctls[i])
                    --ctls[i].dirty = true
                    SetCtlDirty(i)
                    if ctls[i].param_info.paramname == 'Bypass' then
                      SetCtlEnabled(ctls[i].fxnum)
                    end
                    if ctls[i].random then
                      if show_randomopts == true and randopts_selectctl then
                        SetCtlDirty(randopts_selectctl)
                        RandomOpts_INIT(i)
                        randopts_selectctl = i
                        lupd.update_randomopts = true
                      end
                    end
                  end
                  if ctls[i].mod and mod_select ~= ctls[i].mod then
                    mod_select = ctls[i].mod
                    lupd.update_gfx = true
                  end
                  noscroll = true

                  SetCtlDirty(i)
                  lupd.update_ctls = true

                elseif ctltype == 4 then
                  --cycle
                  if ctls[i].cycledata.draggable then
                    if lvar.sliderxy == true then
                      mouse.context = contexts.dragcyclexy
                      mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                      mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                      if lvar.hidecursordrag == true then
                        mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                        lvar.hidecursor = true
                        --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                      end
                    else
                      if ctls[i].horiz then
                        mouse.context = contexts.dragcycle_h
                        mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
                        if lvar.hidecursordrag == true then
                          mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                          lvar.hidecursor = true
                          --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                        end
                      else
                        mouse.context = contexts.dragcycle
                        mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
                        if lvar.hidecursordrag == true then
                          mouse.ox, mouse.oy  = mouse.smx, mouse.smy --reaper.GetMousePosition()
                          lvar.hidecursor = true
                          --reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                        end
                      end
                    end
                    ctlpos = normalize(0, ctls[i].cycledata.statecnt,
                                       ctls[i].cycledata.pos)
                    trackfxparam_select = i
                    ctls[i].cycledata.posdirty = false
                    oms = mouse.shift
                  else
                    if lvar.TSM_MOver then
                      if lvar.TSM_FocusHwnd then
                        reaper.JS_Window_SetFocus(lvar.TSM_FocusHwnd)
                      end
                      if lvar.TSM_LegalMP then
                        reaper.JS_Mouse_SetPosition(lvar.TSM_LegalMP.x, lvar.TSM_LegalMP.y)
                      end
                      --lvar.TSM_Timer = reaper.time_precise()+lvar.TSM_time
                      --lvar.TSM_MOver = nil
                    end

                    if ctls[i].cycledata.pos == nil then
                      ctls[i].cycledata.pos = 1
                    else
                      ctls[i].cycledata.pos = ctls[i].cycledata.pos +1
                      if ctls[i].cycledata.pos > ctls[i].cycledata.statecnt
                         or ctls[i].cycledata.pos < 1 then
                        ctls[i].cycledata.pos = 1
                      end
                    end
                    if ctls[i].cycledata.pos <=
                              ctls[i].cycledata.statecnt then
                      trackfxparam_select = i
                      ctls[i].oval = ctls[i].val
                      ctls[i].val =
                          ctls[i].cycledata[ctls[i].cycledata.pos].val
                      A_SetParam(tracks[track_select].strip,page,i,ctls[i])
                      ctls[i].dirty = true
                      ctls[i].cycledata.posdirty = false
                      lupd.update_ctls = true
                    end
                    SetCtlDirty(i)
                    lupd.update_ctls = true
                  end
                  if ctls[i].mod and mod_select ~= ctls[i].mod then
                    mod_select = ctls[i].mod
                    lupd.update_gfx = true
                  end

                  noscroll = true
                elseif ctltype == 6 then
                  --mem button
                  trackfxparam_select = i
                  if ctls[i].membtn.state == nil then
                    ctls[i].membtn.state = false
                  end
                  ctls[i].membtn.state = not ctls[i].membtn.state
                  if ctls[i].membtn.state == true then
                    ctls[i].membtn.mem = ctls[i].val
                    ctls[i].oval = ctls[i].val
                    ctls[i].val = ctls[i].defval
                    A_SetParam(strip,page,i,ctls[i])
                  else
                    ctls[i].oval = ctls[i].val
                    ctls[i].val = ctls[i].membtn.mem
                    A_SetParam(strip,page,i,ctls[i])
                  end
                  if ctls[i].mod and mod_select ~= ctls[i].mod then
                    mod_select = ctls[i].mod
                    lupd.update_gfx = true
                  end
                  SetCtlDirty(i)
                  lupd.update_ctls = true

                elseif ctltype == 5 then

                  if ctls[i].ctlcat == ctlcats.xy then

                    local ctlx, ctly
                    if lvar.livemode == 0 then
                      ctly = (ctls[i].y*lvar.zoom + obj.sections[10].y - surface_offset.y*lvar.zoom)
                      ctlx = ctls[i].x*lvar.zoom + obj.sections[10].x - surface_offset.x*lvar.zoom
                    else
                      local _, _, swid = TranslateMixPos(mouse.mx, mouse.my, i)
                      local xx, yy = TranslateMixCtlPos(i, swid)
                      ctlx, ctly = xx, yy
                    end

                    if mouse.my - ctly --[[obj.sections[10].y + surface_offset.y*lvar.zoom - ctls[i].y*lvar.zoom]] < (ctls[i].ctl_info.cellh - 38)*lvar.zoom then
                      mouse.context = contexts.dragxy
                      lvar.xyswid = swid
                      xy_select = i
                    else
                      local xp = math.floor((mouse.mx-12*lvar.zoom - ctlx)/((((ctls[i].w-24)*lvar.zoom)/4)))+1
                      xp = F_limit(xp, 1, 4)
                      --DBG(ctlx..'  '..mouse.mx-ctlx-12*lvar.zoom ..'  '..xp)
                      xysnap_select = xp
                      xy_select = i

                      --open fss
                      togfsnap = true
                      if fsstype_select == ctls[i].param then
                        show_xysnapshots = not show_xysnapshots
                        show_fsnapshots = false
                        
                        local w = ctls[i].wsc*lvar.zoom
                        obj.sections[180].w = w--math.max(w - (170-138),138)
                        obj.sections[181].w = obj.sections[180].w-6
                        obj.sections[182].w = obj.sections[180].w
                        
                        RedrawGUIBitmap()
                      else
                        show_xysnapshots = true
                        show_fsnapshots = false
                        
                        local w = ctls[i].wsc*lvar.zoom
                        obj.sections[180].w = w--math.max(w - (170-138),138)
                        obj.sections[181].w = obj.sections[180].w-6
                        obj.sections[182].w = obj.sections[180].w
                        
                        RedrawGUIBitmap()
                      end
                      fsstype_select = ctls[i].param
                      fsstype_color = ctls[i].textcolv
                      if show_xysnapshots then
                        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][fsstype_select] then

                          if xysnap_select == 1 then
                            fss_select = ctls[i].xydata.snapa
                          elseif xysnap_select == 2 then
                            fss_select = ctls[i].xydata.snapb
                          elseif xysnap_select == 3 then
                            fss_select = ctls[i].xydata.snapc
                          elseif xysnap_select == 4 then
                            fss_select = ctls[i].xydata.snapd
                          end
                          --[[obj.sections[180].x = F_limit(ctls[i].x - surface_offset.x + obj.sections[10].x +
                                                        math.floor((ctls[i].w - obj.sections[180].w)/2),
                                                        obj.sections[10].x,obj.sections[10].x+obj.sections[10].w-obj.sections[180].w)]]
                          --[[obj.sections[180].y = F_limit(ctls[i].y+ctls[i].ctl_info.cellh
                                                        - surface_offset.y  + obj.sections[10].y - 3,
                                                        obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-obj.sections[180].h)]]
                          obj.sections[180].x = F_limit(ctlx,
                                                        obj.sections[10].x,obj.sections[10].x+obj.sections[10].w-obj.sections[180].w)
                          obj.sections[180].y = F_limit(ctly +ctls[i].ctl_info.cellh*lvar.zoom,
                                                        obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-obj.sections[180].h)
                          --obj.sections[180].w = ctls[i].wsc * lvar.zoom
                        else
                          show_xysnapshots = false
                          RedrawGUIBitmap()
                        end
                      end
                      lupd.update_fsnaps = true
                      lupd.update_surface = true
                    end

                  elseif ctls[i].ctlcat == ctlcats.snapshot then

                    togfsnap = FSS_Click(i, ctlxywh, togfsnap)

                  elseif ctls[i].ctlcat == ctlcats.eqcontrol then
                    eqcontrol_select = i
                    show_eqcontrol = true
                    --navigate = false
                    if ctls[i].eqbands and ctls[i].eqbands[1] then
                      eqcontrolband_select = 1
                    end
                    --EQC_OpenEQs()
                    lupd.update_gfx = true
                    RedrawGUIBitmap()
                  elseif ctls[i].ctlcat == ctlcats.switcher then

                    switcher_select = i
                    local swctl = switchers[ctls[i].switcherid]
                    if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                      local strip = tracks[track_select].strip
                      if lvar.livemode >= 1 and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[ctls[i].switcherid] then
                        PopOut_Delete(ctls[i].switcherid)
                      elseif lvar.livemode >= 1 and ((strips[strip][page].popidx and not strips[strip][page].popidx[ctls[i].switcherid]) or
                        strips[strip][page].popidx == nil) then
                        local x = lvar.spos[ctls[i].switcherid].x - obj.sections[10].x
                        local y = lvar.spos[ctls[i].switcherid].y - obj.sections[10].y
                        local w = lvar.spos[ctls[i].switcherid].w
                        local h = lvar.spos[ctls[i].switcherid].h

                        if lvar.dm_singlepopup then
                          PopOut_DeleteAll()
                          x = math.floor(obj.sections[10].w/2 - w/2) -- obj.sections[10].x
                          y = math.floor(obj.sections[10].h/2 - h/2) -- obj.sections[10].y
                          if lvar.mmov_show then
                            if lvar.mixmodedir == 0 then
                              x = x + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                            else
                              y = y + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                            end
                          end
                        end

                        PopOut(ctls[i].switcherid,x,y)
                        ShowPop(true)
                      elseif lvar.livemode >= 1 and (strips[strip][page].popidx and strips[strip][page].popidx[ctls[i].switcherid]) then
                        if lvar.dm_singlepopup then
                          PopOut_DeleteAll()
                          local w = lvar.spos[ctls[i].switcherid].w
                          local h = lvar.spos[ctls[i].switcherid].h
                          local x = math.floor(obj.sections[10].w/2 - w/2) -- obj.sections[10].x
                          local y = math.floor(obj.sections[10].h/2 - h/2) -- obj.sections[10].y
                          if lvar.mmov_show then
                            if lvar.mixmodedir == 0 then
                              x = x + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                            else
                              y = y + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                            end
                          end
                          PopOut(ctls[i].switcherid,x,y)
                        end
                        ShowPop(true)
                      end

                    elseif swctl.switchmode == 1 and swctl.extendmode == true --[[and (not lvar.showpop or not lvar.popout_autoarrange)]] then
                      lvar.dragswitcher = DragSwitcher_Ext(nil, ctls[i].switcherid)
                      if lvar.dragswitcher then
                        local strip = tracks[track_select].strip
                        lvar.omx, lvar.omy = mouse.mx, mouse.my

                        if lvar.livemode >= 1 and lvar.showpop == true and strips[strip][page].popidx and strips[strip][page].popidx[ctls[i].switcherid] then
                          PopOut_ToTop(ctls[i].switcherid)
                        else
                          switchers[ctls[i].switcherid].dragging = true
                          lupd.update_surface = true
                        end
                        lvar.edgedrag_mult = 1
                        mouse.context = contexts.switchdrag_ext2
                      end
                    else
                      SwitcherMenu_LB()
                    end
                    --DragSwitcher_Ext(nil, ctls[i].switcherid)
                    --if mouse.shift and swctl.switchmode == 1 and swctl.extendmode == true then
                      --Switcher_Ext_Drag(ctls[i].switcherid, i)
                      --mouse.context = contexts.switchdrag_ext
                      --lvar.switchdrag = {c = i, switchid = ctls[i].switcherid}
                    --else
                    --  SwitcherMenu_LB()
                    --end
                  elseif ctls[i].ctlcat == ctlcats.rcm_switch then
                    rcm_select = i
                    RCMMenu_RB()
                  elseif ctls[i].ctlcat == ctlcats.infoctl then

                    if ctls[i].param == 2 then
                      mouse.context = contexts.infoctl_click
                      local ctl = ctls[i]
                      local offs = lvar.slotoffset[ctl.tracknum or tracks[track_select].tracknum] or 0
                      lvar.infoclick = {src = i, soffs = offs, t = reaper.time_precise(), active = false, mx = mouse.mx, my = mouse.my}
                      lvar.omx = mouse.mx
                      lvar.omy = mouse.my
                    end

                  elseif ctls[i].ctlcat == ctlcats.statectl_str then

                    lvar.statestr_edit = i
                    OpenEB(499,'Enter state string to store:',ctls[i].param_info.paramstr or '')

                  end

                elseif ctltype == 7 or ctltype == 8 or ctltype == 9 or ctltype == 10 then
                  --hold button
                  if lvar.TSM_MOver then
                    if lvar.TSM_FocusHwnd then
                      reaper.JS_Window_SetFocus(lvar.TSM_FocusHwnd)
                    end
                    if lvar.TSM_LegalMP then
                      reaper.JS_Mouse_SetPosition(lvar.TSM_LegalMP.x, lvar.TSM_LegalMP.y)
                    end
                    --lvar.TSM_Timer = reaper.time_precise()+lvar.TSM_time
                    --lvar.TSM_MOver = nil
                  end

                  holdbtn = i
                  trackfxparam_select = i
                  mouse.context = contexts.hold
                  ctls[i].oval = ctls[i].val
                  ctls[i].val = 1
                  ctls[i].dirty = true
                  SetCtlDirty(i)
                  lupd.update_ctls = true

                  A_SetParam(strip, page, i, ctls[i])
                end
                noscroll = true
                --break

              elseif MOUSE_RB() and mouse.ctrl == false then
                local ccat = ctls[i].ctlcat
                if ccat == ctlcats.macro then
                 -- mstr = 'Select Macro Parameters|Edit Macro Parameters'
                  macroedittype_select = 0
                  macro_edit_mode = true
                  macroedit_poffs = 0
                  trackfxparam_select = i
                  macroctl_select = trackfxparam_select
                  RedrawGUIBitmap()
                  --lupd.update_surface = true
                  lupd.update_gfx = true
                elseif ccat == ctlcats.macro_updateparam then
                  macroedittype_select = 1
                  macro_edit_mode = true
                  macroedit_poffs = 0
                  trackfxparam_select = i
                  macroctl_select = trackfxparam_select
                  --lupd.update_surface = true
                  lupd.update_gfx = true
                  RedrawGUIBitmap()
                elseif ccat == ctlcats.snapshotrand then
                  if not mouse.shift then
                    if show_mutate then
                      local ctltype = ctls[i].ctltype
                      if ctltype == 7 or ctltype == 8 or ctltype == 9 or ctltype == 10 then
                        --hold button
                        holdbtn = i
                        trackfxparam_select = i
                        mouse.context = contexts.hold
                        ctls[i].oval = ctls[i].val
                        ctls[i].val = 1
                        ctls[i].dirty = true
                        SetCtlDirty(i)
                        lupd.update_ctls = true
                      end
                      A_SetParam(strip, page, i, ctls[i])
                    else
                      show_mutate = not show_mutate
                      lupd.update_surface = true
                      lupd.update_mutate = true
                      RedrawGUIBitmap()
                    end
                  else
                    show_mutate = not show_mutate
                    lupd.update_surface = true
                    lupd.update_mutate = true
                    RedrawGUIBitmap()
                    --RBMenu(0, ccat, i)
                  end
                elseif ccat == ctlcats.fxgui then
                  CloseFXGUI(ctls[i])
                else
                  RBMenu(0, ccat, i)
                end
                noscroll = true

              elseif MOUSE_LB() and mouse.alt and not mouse.shift then

                if ctls[i].ctlcat == ctlcats.fxparam or
                   ctls[i].ctlcat == ctlcats.fxoffline then
                  --need to detect if mouse is over ctllock
                  OpenFXGUI(ctls[i])
                  
                elseif ctls[i].ctlcat == ctlcats.switcher then
                  --delete 
                  if lvar.livemode == 2 and ctls[i].switcher == nil then
                    --top level switcher
                    local switchid = ctls[i].switcherid
                    if switchid then
                      Switcher_DeleteExt(switchid)
                      UpdateControlValues3(nil, ctls_upd, ctls_orr)
                      DM_RefreshFX()
                    end
                  end
                end

              elseif MOUSE_LB() and mouse.ctrl then --make double-click?
                local ccat = ctls[i].ctlcat
                if ccat == ctlcats.switcher and switchers[ctls[i].switcherid].switchmode == 1 and
                   switchers[ctls[i].switcherid].extendmode == true and mouse.shift then
                  ShowPop(true)
                  lvar.dragswitcher = DragSwitcher_Ext(nil, ctls[i].switcherid)
                  if lvar.dragswitcher then
                    lvar.edgedrag_mult = 1
                    mouse.context = contexts.switchdrag_ext2
                  end

                elseif ccat == ctlcats.snapshotrand then
                  show_randomopts = true
                  if randopts_selectctl then
                    SetCtlDirty(randopts_selectctl)
                  end
                  randopts_selectctl = i

                  SetCtlDirty(i)
                  lupd.update_ctls = true

                  if ctls[i].param == 1 then
                    show_randomopts = false
                  end
                  if show_randomopts == true then

                    RandomOpts_INIT(i)

                  end
                  lupd.update_gfx = true
                  RedrawGUIBitmap()
                
                elseif ccat == ctlcats.sk2ctl then
                  
                  reaper.SetExtState('LBX_SK2_POPUP', 'selectslot', tonumber(ctls[i].param_info.paramidx)+1, false)  
                  reaper.SetExtState('LBX_SK2_POPUP', 'datadirty', 1, false)
                  
                else
                  if mouse.shift then
                    local strip = tracks[track_select].strip
                    if strips[strip] then
                      Envelope_Add(strip,page,i)
                    end
                  else
                    if settings_swapctrlclick == true then
                      SetParam_ToDef(i)
                    else
                      SetParam_EnterVal(i)
                    end
                  end
                end
                noscroll = true

              elseif settings_mousewheelknob and not mouse.ctrl and gfx.mouse_wheel ~= 0 --[[and i]] then

                local ctltype = ctls[i].ctltype
                if ctltype == 1 or ctltype == 11 then
                  trackfxparam_select = i
                  local v
                  if ctls[i].ctlcat ~= ctlcats.rs5k then
                    if mouse.shift then
                      local mult = ctls[i].knobsens.wheelfine * (ctls[i].knobsens.m_wheelfine or 1)
                      if mult == 0 then mult = settings_defknobsens.wheelfine end
                      v = mousewheel_val() * mult
                    else
                      local mult = ctls[i].knobsens.wheel * (ctls[i].knobsens.m_wheel or 1)
                      if mult == 0 then mult = settings_defknobsens.wheel end
                      v = mousewheel_val() * mult
                    end
                  else
                    local mult = 1/lvar.maxsamples
                    v = mousewheel_val() * mult
                  end
                  if ctltype == 11 then v=-v end
                  ctls[i].oval = ctls[i].val
                  ctls[i].val = F_limit(ctls[i].val+v,0,1)
                  A_SetParam(tracks[track_select].strip,page,i,ctls[i])
                  --SetParam()
                  SetCtlDirty(i)
                  --ctls[i].dirty = true
                  lupd.update_ctls = true
                  gfx.mouse_wheel = 0

                elseif ctltype == 4 then
                  local v = mousewheel_val() 
                  if ctls[i].cycledata.pos == nil then
                    ctls[i].cycledata.pos = 1
                  else
                    ctls[i].cycledata.pos = ctls[i].cycledata.pos + v
                    if ctls[i].cycledata.pos < 1 then
                      if ctls[i].cycledata.draggable then
                        ctls[i].cycledata.pos = 1
                      else
                        ctls[i].cycledata.pos = ctls[i].cycledata.statecnt
                      end
                    elseif ctls[i].cycledata.pos >
                            ctls[i].cycledata.statecnt then
                      if ctls[i].cycledata.draggable then
                        ctls[i].cycledata.pos = ctls[i].cycledata.statecnt
                      else
                        ctls[i].cycledata.pos = 1
                      end
                    end
                  end
                  if ctls[i].cycledata.pos <=
                            ctls[i].cycledata.statecnt then
                    trackfxparam_select = i
                    if ctls[i].cycledata[ctls[i].cycledata.pos] then
                      ctls[i].oval = ctls[i].val
                      ctls[i].val =
                          ctls[i].cycledata[ctls[i].cycledata.pos].val
                      --SetParam()
                      A_SetParam(tracks[track_select].strip,page,i,ctls[i])
                      --ctls[i].dirty = true
                      SetCtlDirty(i)
                      lupd.update_ctls = true
                    end
                  end
                  noscroll = true
                  gfx.mouse_wheel = 0

                elseif ctls[i].ctlcat == ctlcats.snapshot then

                  if ctls[i].param_info.paramnum == 1 then
                    local v = mousewheel_val()
                    local xsstype_select,xss_select
                    xsstype_select = ctls[i].param
                    if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][xsstype_select]
                                                and snapshots[tracks[track_select].strip][page][xsstype_select].selected then
                      if snapshots[tracks[track_select].strip][page][xsstype_select].selected then
                        if xsstype_select == 1 then
                          xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected-v
                          if xss_select < 1 then
                            xss_select = #snapshots[tracks[track_select].strip][page][xsstype_select]
                          elseif xss_select > #snapshots[tracks[track_select].strip][page][xsstype_select] then
                            xss_select = 1
                          end

                        else
                          xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected-v
                          if xss_select < 1 then
                            xss_select = #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot
                          elseif xss_select > #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot then
                            xss_select = 1
                          end
                        end
                      else
                        if xsstype_select == 1 then
                          if #snapshots[tracks[track_select].strip][page][xsstype_select] > 0 then
                            xss_select = 1
                          end
                        else
                          if #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot > 0 then
                            xss_select = 1
                          end
                        end
                      end
                      if xss_select then
                        Snapshot_Set(tracks[track_select].strip, page, xsstype_select, xss_select)
                        if xsstype_select == sstype_select then
                          ss_select = xss_select
                        end
                        SetCtlDirty(i)
                        lupd.update_ctls = true
                        lupd.update_snaps = true
                        --lupd.update_fsnaps = true
                      end
                    end
                  end
                  noscroll = true
                  gfx.mouse_wheel = 0
                elseif ctls[i].ctlcat == ctlcats.infoctl then
                  local ctl = ctls[i]

                  if ctl.param == 2 then
                    local v = mousewheel_val()
                    local idx = ctl.tracknum or tracks[track_select].tracknum
                    if idx then
                      local tr = GetTrack(idx)
                      local fxcnt = reaper.TrackFX_GetCount(tr)
                      lvar.slotoffset[idx] = math.min(math.max((lvar.slotoffset[idx] or 0) - v,0),fxcnt)
                      SetCtlDirty(i)
                      lupd.update_ctls = true
                    end
                  end
                  noscroll = true
                  gfx.mouse_wheel = 0
                end
              end
            end

            if show_randomopts == true and randomopts_ctls then
              if randomopts_ctls[i] and randomopts_ctls[i] ~= randomopts_select.param then
                randomopts_select.param = randomopts_ctls[i]
                lupd.update_randomopts = true
              end
            end

          end
        end

      end

      if tracks[track_select] then
        if noscroll == false and MOUSE_click_RB(obj.sections[10]) then
          local i = GetControlAtXY(tracks[track_select].strip,page,mouse.mx,mouse.my)
          if i then
            local ctl = strips[tracks[track_select].strip][page].controls[i]
            RBMenu(0,ctl.ctlcat,i)
          else
            RBMenu(1,nil,nil)
          end
        end
      end

    end

    if show_fsnapshots and togfsnap == false then
      show_fsnapshots = false
      lupd.update_surface = true
      RedrawGUIBitmap()
    end

    return noscroll
  end

  function A_Click_M0_StripBrowser(rt, noscroll)
  
    noscroll = true
    mx,my = mouse.mx, mouse.my
    mouse.mx = mouse.mx - obj.sections[1350].x
    mouse.my = mouse.my - obj.sections[1350].y

    if MOUSE_click(obj.sections[1353]) then

      if mouse.alt then
        StripSearch()
        
      elseif lvar.stripbrowser.search == true then
        lvar.stripbrowser.search = nil
        lvar.reloadsbimages = true
        lupd.update_stripbrowser = true
      else
        --lvar.stripbrowser.favs = true
        --DBG('AA')
        --lvar.stripbrowser.showlist = not (lvar.stripbrowser.showlist or false)
        --lupd.update_stripbrowser = true
        local ddtab = {idx = 3, x = obj.sections[1350].x+obj.sections[1353].x, y = obj.sections[1350].y+obj.sections[1353].y+obj.sections[1353].h+2, w = obj.sections[1353].w, h = 100, items = {}, wpad = 40}
        local cnt = #strip_folders
        ddtab.items[1] = 'FAVS'
        for sid = 0, cnt do
          ddtab.items[sid+2] = strip_folders[sid].fn
        end
        OpenDropDown(3, ddtab, true, true)
      end
      
    elseif MOUSE_click_RB(obj.sections[1353]) then

      local export = '#'
      local exportstrip, exportfolder = ''
      if lvar.stripbrowser.select then
        if lvar.stripbrowser.search == true and strip_search[lvar.stripbrowser.select+1] then
          export = ''
          exportfolder = string.match(strip_search[lvar.stripbrowser.select+1],'(.-)[\\/].*')
          exportstrip = string.match(strip_search[lvar.stripbrowser.select+1],'.-[\\/](.*)')
        elseif lvar.stripbrowser.favs == true and strip_favs[lvar.stripbrowser.select+1] then
          export = ''
          exportfolder = string.match(strip_favs[lvar.stripbrowser.select+1],'(.-)[\\/].*')
          exportstrip = string.match(strip_favs[lvar.stripbrowser.select+1],'.-[\\/](.*)')
        elseif lvar.stripbrowser.favs ~= true and strip_files[lvar.stripbrowser.select] then
          export = ''
          exportfolder = strip_folders[stripfol_select].fn
          exportstrip = strip_files[lvar.stripbrowser.select].fn
        end
      end
      local fbs = ''
      if lvar.sb_folbtn_show then
        fbs = '!'
      end
      local impfol = strip_folders[stripfol_select].fn
      local ass = ''
      if lvar.stripbrowser.favs == true or lvar.stripbrowser.search == true then
        ass = '#'
      end
      local sbfs = ''
      if lvar.stripbrowser.fullscreen then
        sbfs = '!'
      end
      local sbt2 = ''
      if lvar.stripbrowser.type2 then
        sbt2 = '!'
      end
      local ql = ''
      if lvar.stripbrowser.favs == true then
        ql = '#'
      end
      
      local mstr = 'Import Share Strip File (to '..impfol..' folder)|Batch Import Folder Of Share Strips||'
                    .. export .. 'Export Share Strip File ('..exportstrip..')|'..ass..'Batch Export All Strips In Folder As Share Strip Files'..
                    '||'..ass..'Associate All Strips In Folder With Plugins|Strip Association Manager||'..fbs..'Show Additional Folder Buttons||'..
                    sbfs..'Fullscreen Mode|'..sbt2..'Use Button Background'
                    ..'||'..ql..'Strip Folder: Enable Quick Load For All Strips|'..ql..'Strip Folder: Disable Quick Load For All Strips'

      gfx.x = mx
      gfx.y = my
      local res = gfx.showmenu(mstr)
      if res > 0 then
        if res == 1 then
          local stripfn = StripShare_Import()
          loadstrip = LoadStrip(nil, impfol, stripfn)
          if loadstrip then
            local sfxi = GetStripFXInfo(nil, loadstrip)
            if sfxi and #sfxi == 1 then
              local stripfn2 = string.match(stripfn,'(.+)%.strip')

              PlugDef_Add(sfxi[1].fxfn, stripfn2, impfol, true, nil)
            end
          end
          
        elseif res == 2 then
        
          BatchImportShareStrips()
        
        elseif res == 3 then
          StripShare_Export(exportfolder..'/',exportstrip)
        elseif res == 4 then
          local sfcnt = #strip_files + 1
          exportfolder = strip_folders[stripfol_select].fn
          for i = 0, sfcnt-1 do
            exportstrip = strip_files[i].fn
            StripShare_Export(exportfolder..'/',exportstrip,exportfolder)
          end          
        elseif res == 5 then
          local sfcnt = #strip_files + 1
          for i = 0, sfcnt-1 do
            Strip_SetPlugDef(i, stripfol_select, true)
            Save_PlugDefs()
          end
        elseif res == 6 then
          lvar.show_stripassoc = true
          StripAssoc_GetData()
          lupd.update_gfx = true
        elseif res == 7 then
          lvar.sb_folbtn_show = not lvar.sb_folbtn_show
          lupd.update_stripbrowser = true

        elseif res == 8 then
          lvar.stripbrowser.fullscreen = not lvar.stripbrowser.fullscreen
          if lvar.stripbrowser.fullscreen then
            SBDock(false)
          end
          sbwin.w = lvar.sbmin*pnl_scale
          sbwin.h = lvar.sbmin*pnl_scale
          obj = GetObjects()
          lupd.update_gfx = true
        elseif res == 9 then
          lvar.stripbrowser.type2 = not lvar.stripbrowser.type2
          lupd.update_gfx = true
        elseif res == 10 then
          SetStripQuickLoadSetting_ss(stripfol_select, nil, true)
        elseif res == 11 then
          SetStripQuickLoadSetting_ss(stripfol_select, nil, false)
        end
      end

    elseif MOUSE_click(obj.sections[1358]) and lvar.sb_folbtn_c > 1 and lvar.sb_folbtn_show then

      local idx = math.floor((mouse.mx-obj.sections[1358].x)/lvar.sb_folbtn_w)
      if idx < lvar.sb_folbtn_c then
        idx = idx + lvar.sb_folbtn_offs
        if idx == 0 then
          lvar.stripbrowser.favs = true
          lupd.update_stripbrowser = true
          lvar.reloadsbimages = true
          PopulateStrips()
        elseif strip_folders[idx-1] then
          lvar.stripbrowser.favs = false
          stripfol_select = idx-1
          lupd.update_stripbrowser = true
          lvar.reloadsbimages = true
          PopulateStrips()
        end
      end

    elseif MOUSE_click(obj.sections[1359]) and settings_sbdock == true and lvar.sb_folbtn_c > 1 and lvar.sb_folbtn_show then

      lvar.sb_folbtn_offs = math.max(lvar.sb_folbtn_offs - lvar.sb_folbtn_c,0)
      lupd.update_stripbrowser = true

    elseif MOUSE_click(obj.sections[1360]) and settings_sbdock == true and lvar.sb_folbtn_c > 1 and lvar.sb_folbtn_show then

      lvar.sb_folbtn_offs = math.min(lvar.sb_folbtn_offs + lvar.sb_folbtn_c, #strip_folders-lvar.sb_folbtn_c+2)
      lupd.update_stripbrowser = true

    elseif mouse.my < butt_h*pnl_scale then
      if mouse.RB and MOUSE_over(obj.sections[1357]) then

        if lvar.stripbrowser.dockpos == 1 then
          mstr = '!Dock to top edge|Dock to right edge'
        else
          mstr = 'Dock to top edge|!Dock to right edge'
        end
        gfx.x, gfx.y = mx, my
        local res = gfx.showmenu(mstr)
        if res > 0 then
          lvar.stripbrowser.dockpos = res
          sbwin.w = lvar.sbmin*pnl_scale
          sbwin.h = lvar.sbmin*pnl_scale
          SBDock(true)
          obj = GetObjects()
          lupd.update_gfx = true
        end

      elseif mouse.RB then
        SetShowSB(false)
        lupd.update_surface = true

      elseif mouse.LB then
        if MOUSE_click(obj.sections[1357]) then

          SBDock(not settings_sbdock)

        elseif settings_sbdock ~= true then
          mouse.context = contexts.move_sbwin
          movesbwin = {dx = mouse.mx, dy = mouse.my}
        end
      end

    elseif MOUSE_click(obj.sections[1354])  then

      if settings_sbdock ~= true and not lvar.stripbrowser.fullscreen then
        mouse.context = contexts.resize_sbwin
        sbwinrsz = {mx = mx, my = my, w = sbwin.w, h = sbwin.h, x = obj.sections[1350].x, y = obj.sections[1350].y, sc_w = obj.sections[1350].w, sc_h = obj.sections[1350].h}
      end

    elseif MOUSE_click(obj.sections[1355]) then

      if settings_sbdock ~= true or lvar.stripbrowser.dockpos == 1 and not lvar.stripbrowser.fullscreen then
        mouse.context = contexts.resize_sbwinv
        sbwinrsz = {my = my, h = sbwin.h, y = obj.sections[1350].y, sc_h = obj.sections[1350].h}
      end

    elseif MOUSE_click(obj.sections[1356]) and not lvar.stripbrowser.fullscreen then

      mouse.context = contexts.resize_sbwinh
      sbwinrsz = {mx = mx, w = sbwin.w, x = obj.sections[1350].x, sc_w = obj.sections[1350].w, mmx = mouse.mx, ddx = mx - obj.sections[1350].x, ep = obj.sections[1350].x + obj.sections[1350].w}

    elseif lvar.stripbrowser.showlist == true and MOUSE_click(obj.sections[1351]) then

      local n = math.floor((mouse.my - obj.sections[1351].y) / math.floor(butt_h*pnl_scale))-1
      if n == -1 then
        lvar.stripbrowser.favs = true
      else
        if strip_folders[n+sbsflist_offset] then
          lvar.stripbrowser.favs = false
          stripfol_select = n+sbsflist_offset
          PopulateStrips()
        end
      end
      lvar.stripbrowser.showlist = false
      lupd.update_stripbrowser = true

    elseif MOUSE_click(obj.sections[1352]) then

      if lvar.stripbrowser.showlist == true then
        lvar.stripbrowser.showlist = false
        lupd.update_stripbrowser = true
      end
      local minw, minh = math.floor(lvar.stripbrowser.minw), math.floor(lvar.stripbrowser.minh)

      local w,h = gfx.getimgdim(skin.star)
      local dx, dy = math.max(math.floor((lvar.stripbrowser.imgw-minw)/2),math.floor(5*pnl_scale)),
                     math.max(math.floor((lvar.stripbrowser.imgh-minh)/2),math.floor(5*pnl_scale))
      local x = math.floor(mouse.mx - (obj.sections[1352].x +dx+15)) % (lvar.stripbrowser.imgw+10)
      local y = math.floor(mouse.my - (obj.sections[1352].y +dy+5) + h/2) % (lvar.stripbrowser.imgh+10)

      if x >= minw/2-w/2 and x <= minw/2+w/2
         and y > 4 and y <= 15 then

        local x = math.floor((mouse.mx - obj.sections[1352].x)/(obj.sections[1352].w/lvar.stripbrowser.xnum))
        local y = math.floor((mouse.my - obj.sections[1352].y)/(obj.sections[1352].h/lvar.stripbrowser.ynum))
        local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page

        local n = x + (y*lvar.stripbrowser.xnum) + offset
        lvar.stripbrowser.select = n

          
        if (lvar.stripbrowser.search == true and strip_search[n+1])
           or (lvar.stripbrowser.favs == true and lvar.stripbrowser.search ~= true and strip_favs[n+1]) 
           or (lvar.stripbrowser.favs ~= true and lvar.stripbrowser.search ~= true and strip_files[n]) then
          local fn
          if lvar.stripbrowser.search == true then
            fn = strip_search[n+1]
          elseif lvar.stripbrowser.favs == true then
            fn = strip_favs[n+1]
          else
            fn = strip_folders[stripfol_select].fn..'/'..strip_files[n].fn
          end

          if InFavs(fn) then
            RemoveFav(fn)
          else
            strip_favs[#strip_favs+1] = fn
          end
        end
        lupd.update_stripbrowser = true

      elseif mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then

        if lvar.livemode == 0 or (lvar.stripbrowser.fullscreen) then
          if lvar.stripbrowser.select then
            loadstrip = nil
            local fn
            if lvar.stripbrowser.favs == true then
              fn = strip_favs[lvar.stripbrowser.select+1]
            else
              if strip_files[lvar.stripbrowser.select] then
                fn = strip_folders[stripfol_select].fn..'/'..strip_files[lvar.stripbrowser.select].fn
              end
            end
            if fn then
              if settings_stripautosnap == true or show_striplayout == false or stripgallery_view > 0 or lvar.stripbrowser.fullscreen then
                
                local mp = InsStrip(fn)
                if lvar.stripbrowser.fullscreen then
                  if mp then
                    SetShowSB(false)
                    MixMode_Swipe((lvar.centrepos or 0), mp, true)
                  else
                    SetShowSB(false)
                  end
                end
              end
            end
          end
        end

      else
        
        if not lvar.stripbrowser.fullscreen then
          loadstrip = nil
          local x = math.floor((mouse.mx - obj.sections[1352].x)/(obj.sections[1352].w/lvar.stripbrowser.xnum))
          local y = math.floor((mouse.my - obj.sections[1352].y)/(obj.sections[1352].h/lvar.stripbrowser.ynum))
          local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page
  
          local n = x + (y*lvar.stripbrowser.xnum) + offset
          lvar.stripbrowser.select = n
  
          lupd.update_stripbrowser = true
          if (lvar.stripbrowser.search == true and strip_search[n+1]) or
             (lvar.stripbrowser.search ~= true and lvar.stripbrowser.favs == true and strip_favs[n+1]) or
             (lvar.stripbrowser.search ~= true and lvar.stripbrowser.favs ~= true and strip_files[n]) then
  
            if show_striplayout == false and stripgallery_view == 0 then
              mouse.context = contexts.sb_dragstrip
              local fn
              if lvar.stripbrowser.search == true then
                fn = paths.strips_path..string.match(strip_search[n+1],'(.+)%.strip')..'.png'
              elseif lvar.stripbrowser.favs == true then
                fn = paths.strips_path..string.match(strip_favs[n+1],'(.+)%.strip')..'.png'
              else
                fn = paths.strips_path..strip_folders[stripfol_select].fn..'/'..string.match(strip_files[n].fn,'(.+)%.strip')..'.png'
              end
              local img = 980
              if reaper.file_exists(fn) then
                gfx.loadimg(img, fn)
              else
                img = skin.sbicon
              end
              local pw = lvar.stripbrowser.minw
              local ph = lvar.stripbrowser.minh
              local w,h = gfx.getimgdim(img)
              local scale = math.min(pw/w,ph/h)
  
              local drags
              if lvar.livemode >= 1 then
                drags = DragSwitcher_Ext(nil, nil, true)
              end
              --if drags then
                sb_drag = {x = mouse.mx, y = mouse.my, img = img, scale = scale, w = w, h = h,
                           xoff = math.floor((w*scale)/2), yoff = math.floor((h*scale)/2),
                           alpha = 0, drags = drags, fn = fn, showpop = lvar.showpop}
              
              --end
            end
          end
        else
          loadstrip = nil
          local x = math.floor((mouse.mx - obj.sections[1352].x)/(obj.sections[1352].w/lvar.stripbrowser.xnum))
          local y = math.floor((mouse.my - obj.sections[1352].y)/(obj.sections[1352].h/lvar.stripbrowser.ynum))
          local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page
  
          local n = x + (y*lvar.stripbrowser.xnum) + offset
          lvar.stripbrowser.select = n
  
          lupd.update_stripbrowser = true
        end
        
      end

    elseif MOUSE_click_RB(obj.sections[1352]) then

      local x = math.floor((mouse.mx - obj.sections[1352].x)/(obj.sections[1352].w/lvar.stripbrowser.xnum))
      local y = math.floor((mouse.my - obj.sections[1352].y)/(obj.sections[1352].h/lvar.stripbrowser.ynum))
      local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page

      local n = x + (y*lvar.stripbrowser.xnum) + offset
      lvar.stripbrowser.select = n

      if mouse.shift or not lvar.stripbrowser.favs then
        lupd.update_stripbrowser = true
        lupd = GUI_draw(obj, gui)
        gfx.update()

        lvar.openmenu = {func = SBMenu_RB}

      else
        lupd.update_stripbrowser = true
        if (not lvar.stripbrowser.search and lvar.stripbrowser.favs == true and strip_favs[n+1]) then
          movefav = table.copy(strip_favs)
          movefav_n = table.copy(strip_favs_n)
          lvar.stripbrowser.moveselect = n
          mouse.context = contexts.sb_movefav
        end
      end
    end

    mouse.mx = mx
    mouse.my = my

    return noscroll
    
  end

  function A_Click_M0_SampleManager(rt, noscroll)

    noscroll = true
    mx,my = mouse.mx, mouse.my
    mouse.mx = mouse.mx - obj.sections[1300].x
    mouse.my = mouse.my - obj.sections[1300].y

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[rs5k_select]

    if mouse.my < butt_h*pnl_scale then
      if mouse.RB then
        SetShowSampleManager(false)
      elseif mouse.LB then
        mouse.context = contexts.move_smwin
        movesmwin = {dx = mouse.mx, dy = mouse.my}
      end

    elseif MOUSE_click(obj.sections[1310])  then

      mouse.context = contexts.resize_smwin
      smwinrsz = {mx = mx, my = my, w = smwin.w, h = smwin.h, x = obj.sections[1300].x, y = obj.sections[1300].y, sc_w = obj.sections[1300].w, sc_h = obj.sections[1300].h}

    elseif MOUSE_click(obj.sections[1311])  then

      mouse.context = contexts.resize_smwinv
      smwinrsz = {my = my, h = smwin.h, y = obj.sections[1300].y, sc_h = obj.sections[1300].h}

    elseif MOUSE_click(obj.sections[1303]) then

      local rsdata
      if smshowfavs then
        rsdata = samplefavs
      else
        rsdata = ctl.rsdata
      end

      local msbh = obj.sections[1303].h
      local p1 = 1 / #rsdata.samples
      local sbh = math.ceil(F_limit(p1*SM_butt_cnt * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(smlist_offset * p2)

      sby = math.min(sby,--[[obj.sections[1303].y+]]msbh-sbh-1)

      if mouse.my >= obj.sections[1303].y + sby and mouse.my <= obj.sections[1303].y + sby+sbh then

        if SM_butt_cnt < #rsdata.samples then
          mouse.context = contexts.scrollsamples
          scrollsamps = {y = mouse.my-obj.sections[1303].y, lo = smlist_offset}
          lupd.update_samplemanager = true
        else
          smlist_offset = 0
        end

      elseif mouse.my < obj.sections[1303].y + sby then

      elseif mouse.my > obj.sections[1303].y + sby+sbh then

      end

    elseif MOUSE_click(obj.sections[1302]) then
      local v = math.floor((mouse.my - obj.sections[1302].y) / tb_butt_h)+1 + smlist_offset
      local rsdata
      if smshowfavs then
        rsdata = samplefavs
      else
        rsdata = ctl.rsdata
      end
      if v <= #rsdata.samples then
        local starw, starh = gfx.getimgdim(skin.star)

        if mouse.mx < obj.sections[1302].w-starw then
          if smshowfavs then
            v = rsdata.samples[v].idx
          end
          sample_select = v
          lupd.update_samplemanager = true
          --if ctl.rsdata.samples[v].fn then
            ctl.oval = ctl.val
            ctl.val = (v-1) / lvar.maxsamples
            A_SetParam(strip,page,rs5k_select,ctl)
            SetCtlDirty(rs5k_select)
            lupd.update_ctls = true
          --end
        else
          if rsdata.samples[v].fn then
            rsdata.samples[v].fav = not (rsdata.samples[v].fav or false)
            --PopSampleFavIdx()
            lupd.update_samplemanager = true
          end
        end
      end

    elseif MOUSE_click(obj.sections[1304]) then

      if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
        gfx.dest = 909
        gfx.x = mouse.mx - obj.sections[1304].x + lvar.kb.offset
        gfx.y = mouse.my - obj.sections[1304].y + lvar.kb.wkey_h
        local r,_,_ = gfx.getpixel()

        lvar.kb.kstart = r*255
        lvar.kb.kend = r*255

        GUI_DrawKeyboardOverlay(obj, gui)
        lupd.update_samplemanager = true

        gfx.dest = 1

        --Set plugin params
        --local ctl = strips[tracks[track_select].strip][page].controls[rs5k_select]
        local trn = ctl.tracknum or strips[strip].track.tracknum
        local track = GetTrack(trn)
        local fxnum = ctl.fxnum
        local pstart = 3
        local pend = 4
        reaper.TrackFX_SetParam(track,fxnum,pstart,lvar.kb.kstart/128)
        reaper.TrackFX_SetParam(track,fxnum,pend,lvar.kb.kend/128)

      elseif mouse.shift then
        gfx.dest = 909
        gfx.x = mouse.mx - obj.sections[1304].x + lvar.kb.offset
        gfx.y = mouse.my - obj.sections[1304].y + lvar.kb.wkey_h
        local r,_,_ = gfx.getpixel()

        lvar.kb.kend = r*255
        if not lvar.kb.kstart then
          lvar.kb.kstart = r*255
        end
        if lvar.kb.kstart > lvar.kb.kend then
          local ke = lvar.kb.kend
          lvar.kb.kend = lvar.kb.kstart
          lvar.kb.kstart = ke
        end
        GUI_DrawKeyboardOverlay(obj, gui)
        lupd.update_samplemanager = true

        gfx.dest = 1

        --Set plugin params
        --local ctl = strips[tracks[track_select].strip][page].controls[rs5k_select]
        local trn = ctl.tracknum or strips[strip].track.tracknum
        local track = GetTrack(trn)
        local fxnum = ctl.fxnum
        local pstart = 3
        local pend = 4
        reaper.TrackFX_SetParam(track,fxnum,pstart,lvar.kb.kstart/128)
        reaper.TrackFX_SetParam(track,fxnum,pend,lvar.kb.kend/128)

      else
        mouse.context = contexts.scrollkeyb
        scrollkeyb = {x = mouse.mx-obj.sections[1304].x, lo = lvar.kb.offset}
      end

    elseif MOUSE_click_RB(obj.sections[1304]) then

      gfx.dest = 909
      gfx.x = mouse.mx - obj.sections[1304].x + lvar.kb.offset
      gfx.y = mouse.my - obj.sections[1304].y + lvar.kb.wkey_h
      local r,_,_ = gfx.getpixel()

      lvar.rs.pitch = (r*255)-72
      local v = 0.5 - (lvar.rs.pitch*(1/160))

      local trn = ctl.tracknum or strips[strip].track.tracknum
      local track = GetTrack(trn)
      local fxnum = ctl.fxnum
      reaper.TrackFX_SetParam(track,fxnum,15,v)

      GUI_DrawKeyboardOverlay(obj, gui)
      lupd.update_samplemanager = true

    elseif MOUSE_click(obj.sections[1305]) then

      RSMenuOut(mx,my)

    elseif MOUSE_click(obj.sections[1306]) then

      local fol, fil = RS5k_GetSample()
      if fol and fil then

        local sidx = #ctl.rsdata.samples+1
        ctl.rsdata.samples[sidx] = {fol = fol,
                                    fn = fil}
        ctl.rsdata.samplesidx[fol..fil] = sidx
        lupd.update_samplemanager = true
        smlist_offset = sidx - SM_butt_cnt

      end

    elseif MOUSE_click(obj.sections[1307]) then

      if sample_select then
        local fol, fil = RS5k_GetSample()
        if fol and fil then

          local sidx = sample_select
          if ctl.rsdata.samples[sidx] and ctl.rsdata.samples[sidx].fn then
            ctl.rsdata.samplesidx[ctl.rsdata.samples[sidx].fol..ctl.rsdata.samples[sidx].fn] = nil
          end
          ctl.rsdata.samples[sidx] = {fol = fol,
                                      fn = fil}
          ctl.rsdata.samplesidx[fol..fil] = sidx
          lupd.update_samplemanager = true
          ctl.oval = ctl.val
          ctl.val = (sample_select-1) / lvar.maxsamples
          A_SetParam(strip,page,rs5k_select,ctl)
          SetCtlDirty(rs5k_select)
          lupd.update_ctls = true

        end
      end

    elseif MOUSE_click(obj.sections[1308]) then

      if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
        if sample_select then

          if ctl.rsdata.samples[sample_select] and ctl.rsdata.samples[sample_select].fn then
            ctl.rsdata.samplesidx[ctl.rsdata.samples[sample_select].fol..ctl.rsdata.samples[sample_select].fn] = nil
            ctl.rsdata.samples[sample_select].fn = nil
          end

          lupd.update_samplemanager = true
          ctl.oval = ctl.val
          ctl.val = (sample_select-1) / lvar.maxsamples
          A_SetParam(strip,page,rs5k_select,ctl)
          SetCtlDirty(rs5k_select)
          lupd.update_ctls = true
        end
      end

    elseif MOUSE_click(obj.sections[1309]) then

      smshowfavs = not (smshowfavs or false)
      smlist_offset = 0
      if smshowfavs == true then
        PopSampleFavIdx()
      end
      lupd.update_samplemanager = true

    elseif MOUSE_click(obj.sections[1301]) then

      if not ctl.rsdata.samplefolder then
        RS5k_LoadFolder(strip, page, rs5k_select, false)
        smlist_offset = 0
        lupd.update_samplemanager = true

      else
        mstr = 'Rescan Folder||Load Folder|Load Folder (+subfolders)'
        gfx.x = mx
        gfx.y = my
        local res = gfx.showmenu(mstr)
        if res > 0 then

          if res == 1 then
            RS5k_RescanFolder(strip, page, rs5k_select)
          elseif res == 2 then
            RS5k_LoadFolder(strip, page, rs5k_select, false)
            smlist_offset = 0
          elseif res == 3 then
            RS5k_LoadFolder(strip, page, rs5k_select, true)
            smlist_offset = 0
          end
          lupd.update_samplemanager = true

        end
      end

    elseif MOUSE_click_RB(obj.sections[1301]) then

      local t = ''
      if not ctl.rsdata.samplefolder then
        t = '#'
      end
      mstr = t..'Rescan Folder||Load Folder|Load Folder (+subfolders)'
      gfx.x = mx
      gfx.y = my
      local res = gfx.showmenu(mstr)
      if res > 0 then

        if res == 1 then
          RS5k_RescanFolder(strip, page, rs5k_select)
        elseif res == 2 then
          RS5k_LoadFolder(strip, page, rs5k_select, false)
          smlist_offset = 0
        elseif res == 3 then
          RS5k_LoadFolder(strip, page, rs5k_select, true)
          smlist_offset = 0
        end
        lupd.update_samplemanager = true

      end

    end

    mouse.mx = mx
    mouse.my = my

    return noscroll
    
  end

  function A_Click_M0_TopBar(rt, noscroll)



    return noscroll
    
  end

  function A_Click_M0_Sidebar(rt, noscroll)



    return noscroll
    
  end

  function ScrollTCP2(tr)

    local hwnd = reaper.JS_Window_GetFocus()
    if not tr then
      tr = reaper.GetSelectedTrack2(0,0,true)
    end
    if tr then
      local tcp_y = reaper.GetMediaTrackInfo_Value(tr, 'I_TCPY')
      local hwnd = reaper.GetMainHwnd()
      local cwin2 = reaper.JS_Window_FindChildByID(hwnd, 1000)
      if cwin2 then      
        local retval, position, pageSize, min, max, trackPos = reaper.JS_Window_GetScrollInfo(cwin2, 'SB_VERT')      
        reaper.JS_Window_SetScrollPos(cwin2, 'SB_VERT', position + tcp_y)
      end
    end
    if hwnd then
      reaper.JS_Window_SetFocus(hwnd)
    end
    
  end
  
  function A_Click_M0_TrBtns(rt, noscroll)

    if MOUSE_click_RB(obj.sections[5041]) then
      TrackSetListMenu(mouse.mx,mouse.my)

    elseif MOUSE_click(obj.sections[5041]) then
      if not mouse.shift then
        FolderTrackListMenu(mouse.mx,mouse.my)
      else
        TrackSetListMenu(mouse.mx,mouse.my)
      end

    elseif MOUSE_click_RB(obj.sections[5000]) then

      local ar = ''
      if lvar.dm_autorefresh then
        ar = '!'
      end
      local mstr = 'Clear saved dynamic mode data||'..ar..'Auto refresh page'
      gfx.x = mouse.mx
      gfx.y = mouse.my
      local res = gfx.showmenu(mstr)
      if res > 0 then
        if res == 1 then
          if reaper.MB("Are you sure you wish to clear saved data?\n\nIndividual strips containing multiple FX plugins will need to be rebuilt manually!"
                       , 'Clear Saved Data', 4) == 6 then
          
            lvar.stripstore = nil
            lvar.snapstore = nil
            DM_RefreshPage()
          end
          
        elseif res == 2 then
          lvar.dm_autorefresh = not lvar.dm_autorefresh
        end
      end

    elseif MOUSE_click_RB(obj.sections[5006]) then

      local trn = lvar.dynamicmode_trn
      if trn then
        local track = GetTrack(trn)
        if track then
          local _, trnm = reaper.GetTrackName(track)
          local mstr
          if lvar.dm_backtrack then
            local pt1,pt2,pt3,pt4 = '','','',''
            if lvar.dm_backtrack.page == 1 then
              pt1 = '!'
            elseif lvar.dm_backtrack.page == 2 then
              pt2 = '!'
            elseif lvar.dm_backtrack.page == 3 then
              pt3 = '!'
            elseif lvar.dm_backtrack.page == 4 then
              pt4 = '!'
            end
            mstr = "Set '"..trnm.."' as return track||#Set return track page:|"..pt1.."Page 1|"..pt2.."Page 2|"..pt3.."Page 3|"..pt4.."Page 4||Clear return track"
          else
            mstr = "Set '"..trnm.."' as return track||#Set return track page:|#Page 1|#Page 2|#Page 3|#Page 4"
          end
          gfx.x = mouse.mx
          gfx.y = mouse.my
          local res = gfx.showmenu(mstr)
          if res > 0 then
            if res == 1 then
              lvar.dm_backtrack = {trn = lvar.dynamicmode_trn, guid = lvar.dynamicmode_guid, page = 1}
              lupd.update_trbtns = true
            elseif res >= 3 and res <= 6 then
              local p = res - 2
              lvar.dm_backtrack.page = p
            elseif res == 7 then
              lvar.dm_backtrack = nil
              lupd.update_trbtns = true
            end
          end
        end
      end

    elseif MOUSE_click(obj.sections[5006]) then

      if lvar.dm_backtrack then
        local trn = lvar.dm_backtrack.trn
        if trn ~= -1 then
          local track = GetTrack(trn)
          if not track then
            trn = GetTRNfromGUID(lvar.dm_backtrack.guid)
            if trn then
              lvar.dm_backtrack.trn = trn
            end
          else
            --check guid
            if lvar.dm_backtrack.guid == GetTrackGUID(track) then
            else
              trn = GetTRNfromGUID(lvar.dm_backtrack.guid)
              if trn then
                lvar.dm_backtrack.trn = trn
              end
            end
          end
        end
        if trn then
          ChangeTrack2(trn, lvar.dm_backtrack.page, true)
        end
      elseif lvar.dm_ret_track then
        ChangeTrack2(lvar.dm_ret_track, lvar.dm_ret_page, true)
      end

    elseif obj.sections[5007] and MOUSE_click(obj.sections[5007]) then
      if not lvar.delayfunction.trbtnsglobalset_delay then
        SetGlobalPage()
        lvar.delayfunction.trbtnsglobalset_delay = reaper.time_precise() + 0.2
      end
    elseif MOUSE_click(obj.sections[5002]) then

      if not mouse.shift then
        local mr = math.min(lvar.trov_maxrows-1,lvar.dm_maxvistracks)
        lvar.trbtns_offs = math.max(F_limit(lvar.trbtns_offs - mr,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-mr),0)
        lupd.update_trbtns = true
      else
        local t = (lvar.dynamicmode_trn or 0) - 1
        if t < -1 then t = #tracks end
        local track = GetTrack(t)
        reaper.SetOnlyTrackSelected(track)
        DM_AddStrips()
      end

    elseif MOUSE_click(obj.sections[5003]) then

      if not mouse.shift then
        local mr = math.min(lvar.trov_maxrows-1,lvar.dm_maxvistracks)
        lvar.trbtns_offs = math.max(F_limit(lvar.trbtns_offs + mr,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-mr),0)
        lupd.update_trbtns = true
      else
        local t = (lvar.dynamicmode_trn or #tracks) + 1
        if t > #tracks then t = -1 end
        local track = GetTrack(t)
        reaper.SetOnlyTrackSelected(track)
        DM_AddStrips()
      end

    elseif (MOUSE_click(obj.sections[5005]) or MOUSE_click_RB(obj.sections[5005])) then
      if MOUSE_click(obj.sections[5005]) then
        local x = math.floor((mouse.mx - obj.sections[5005].x)/(obj.sections[5004].w+10))+1
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        local cnt = math.min(--[[(#dm_trackbtns+1),]] lvar.trov_maxrows, lvar.dm_maxvistracks+1)
        if x == cnt then
          local tbguididx = {}
          for i = 1, #dm_trackbtns do
            if dm_trackbtns[i].trn == -1 then
              tbguididx[-1] = true
            else
              tbguididx[dm_trackbtns[i].guid] = true
            end
          end

          if lvar.dm_tbidx > 0 --[[and lvar.dynamicmode_trn]] then
            for t = 0, reaper.CountSelectedTracks2(0,true)-1 do
              local tr = reaper.GetSelectedTrack2(0,t,true)
              local trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')
              local guid = GetTrackGUID(tr)
              if not (tbguididx[guid] or tbguididx[trn]) then
                if trn == -1 then
                  dm_trackbtns[#dm_trackbtns+1] = {guid = guid, trn = trn}
                else
                  dm_trackbtns[#dm_trackbtns+1] = {guid = guid, trn = trn-1}
                end
                lupd.update_surface = true
                lupd.update_trbtns = true
              end
            end

            --[[local fnd
            for i = 1, #dm_trackbtns do
              if dm_trackbtns[i].guid == lvar.dynamicmode_guid or (lvar.dynamicmode_trn == -1 and dm_trackbtns[i].trn == -1) then
                fnd = true
                break
              end
            end
            if not fnd then
              dm_trackbtns[#dm_trackbtns+1] = {guid = lvar.dynamicmode_guid, trn = lvar.dynamicmode_trn}
              lupd.update_surface = true
              lupd.update_trbtns = true
            end]]
          end

          --obj = PosTrBtns(obj)
          Repos5005()

        else
          local x = x + lvar.trbtns_offs
          if dm_trackbtns[x] then
            if not mouse.shift then
              if dm_trackbtns[x] then
                local tr = GetTrack(dm_trackbtns[x].trn)
                if tr then
                  if GetTrackGUID(tr) ~= dm_trackbtns[x].guid and dm_trackbtns[x].trn ~= -1 then
                    tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtns[x].guid)
                    if tr then
                      dm_trackbtns[x].trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                    end
                  end
                end
                if tr then
                  if not mouse.ctrl then
                    if dm_trackbtns[x].trn ~= lvar.dynamicmode_trn then
                      reaper.SetOnlyTrackSelected(tr)
                      DM_AddStrips()
                      ScrollTCP2(tr)
                      --reaper.Main_OnCommand(40913,0)
                      reaper.SetMixerScroll(tr)
                      
                      mouse.context = contexts.dm_selecttracks
                      lvar.dmsl = {x = x - lvar.trbtns_offs, delay = reaper.time_precise()+0.2}
                      
                    elseif dm_trackbtns[x].trn ~= -1 then
                      --solo/unsolo
                      lvar.trbtn_solo = true
                      --[[local solo = reaper.GetMediaTrackInfo_Value(tr, 'I_SOLO')
                      solo = 2-solo
                      reaper.CSurf_OnSoloChangeEx(tr, solo, true)]]

                      mouse.context = contexts.dm_selecttracks
                      lvar.dmsl = {x = x - lvar.trbtns_offs, delay = reaper.time_precise()+0.2}
                      --reaper.SetMediaTrackInfo_Value(tr, 'I_SOLO', solo)
                    end
                  else --ctrl
                    mouse.context = contexts.dm_selecttracks
                    lvar.dmsl = {x = x - lvar.trbtns_offs, delay = 0}
                  end
                end
              end
            else
              local idx
              for i = 1, #dm_trackbtns do
                --DBG(math.max(dm_trackbtns[i].trn-1,-1)..'  '..lvar.dynamicmode_trn)
                if dm_trackbtns[i].guid == lvar.dynamicmode_guid or (lvar.dynamicmode_trn == -1 and dm_trackbtns[i].trn == -1) then
                  idx = i
                  break
                end
              end
              if idx and idx ~= x then
                table.shift(dm_trackbtns,idx,x)
                lvar.dm_trackbtns[lvar.dm_tbidx] = dm_trackbtns
                lupd.update_trbtns = true
              end
            end
          end
        end
      else --right-click
        local x = math.floor((mouse.mx - obj.sections[5005].x)/(obj.sections[5004].w+10))+1
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        if x == math.min(lvar.trov_maxrows,lvar.dm_maxvistracks+1) or x == #dm_trackbtns + 1 then
          local pm = ''
          if lvar.trbtns_meters then
            pm = '!'
          end
          local mstr = 'Max Visible Tracks ('..string.format('%i',lvar.dm_maxvistracks)..')||'..pm..'Show Peak Meters||Set Peak Meter Color'
          gfx.x, gfx.y = mouse.mx, mouse.my
          local res = gfx.showmenu(mstr)
          if res then
            if res == 1 then
              local retval, val = reaper.GetUserInputs('Max Mixer Tracks',1,'Enter Maximum:','')
              if retval and tonumber(val) then
                lvar.dm_maxvistracks = tonumber(val)
                obj = PosTrBtns(obj)
                lupd.update_trbtns = true
              end
            elseif res == 2 then
              lvar.trbtns_meters = not lvar.trbtns_meters
              lupd.update_trbtns = true
            elseif res == 3 then
              local retval, c = reaper.GR_SelectColor(_,ConvertColorString(lvar.trbtns_pkcolor))
              if retval ~= 0 then
                if lvar.Mac_revcol then c = MacRevC(c) end
                lvar.trbtns_pkcolor = ConvertColor(c)
                lupd.update_trbtns = true
              end
            end
          end
        else
          if mouse.shift and lvar.dm_tbidx > 0 then
            x = x+lvar.trbtns_offs
            if dm_trackbtns[x] then
              local mstr = 'Clear'
              gfx.x, gfx.y = mouse.mx, mouse.my
              local res = gfx.showmenu(mstr)
              if res then
                if res == 1 then
                  local dm_tbs = {}
                  for i = 1, #dm_trackbtns do
                    if i ~= x then
                      dm_tbs[#dm_tbs+1] = dm_trackbtns[i]
                    end
                  end
                  lvar.dm_trackbtns[lvar.dm_tbidx] = dm_tbs
                  lupd.update_trbtns = true
                  Repos5005()
                  --obj = PosTrBtns(obj)
                  noscroll = true
                end
              end
            end
          else
            --mute/menu
            if dm_trackbtns[x] then
              local tr = GetTrack(dm_trackbtns[x].trn)
              if tr then
                if GetTrackGUID(tr) ~= dm_trackbtns[x].guid and dm_trackbtns[x].trn ~= -1 then
                  tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtns[x].guid)
                  if tr then
                    dm_trackbtns[x].trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                  end
                end
              end
              if tr then
                if lvar.trmix_show then

                  local x, y = reaper.GetMousePosition()
                  reaper.ShowPopupMenu('track_panel',x,y,nil,tr)
                  lupd.update_trbtns = true
                  --return selected track to previous

                  local tr2 = GetTrack(lvar.dynamicmode_trn)
                  reaper.SetOnlyTrackSelected(tr2)
                else
                  if dm_trackbtns[x].trn ~= -1 then
                    --mute/unmute
                    local mute = reaper.GetMediaTrackInfo_Value(tr, 'B_MUTE')
                    mute = 1-mute
                    reaper.SetMediaTrackInfo_Value(tr, 'B_MUTE', mute)
                  end
                end
              end
            end
          end
        end
      end
    end

    return noscroll
    
  end

  function A_Click_M0_TrMix(rt, noscroll)

    if lvar.analyzer.active and lvar.analyzer.showcontrols and MOUSE_click(obj.sections[5047]) then
    
      local p = mouse.my - obj.sections[5047].y - 5
      local c = math.floor((p)/30)+1
      local idx = lvar.analyzer.pos+1
      local ctls = lvar.analyzer.controls[idx]
      if ctls and ctls[c] then

        local tr = Analyzer_GetTrack()
        if tr then
          local param = ctls[c].param
          local val = reaper.TrackFX_GetParamNormalized(tr,idx-1,param)
          lvar.draganalyzercontrol = {param = param, val = val, my = mouse.my, tr = tr, sens = ctls[c].sens or 240}
          mouse.context = contexts.analyzerctl
        end
      end

    elseif MOUSE_click(obj.sections[5080]) then

      mouse.context = contexts.mixer_drag
      
      local sz = lvar.trbtns_size
      
      panelw = (obj.sections[10].w - (lvar.trov_maxrows*(sz+10)))/2
              
      lvar.mdrag = {mx = mouse.mx, osz = math.max(lvar.trmix_panelsz,panelw), dir = 1}
      lupd.update_trbtns = true

    elseif MOUSE_click(obj.sections[5081]) then

      mouse.context = contexts.mixer_drag
      
      local sz = lvar.trbtns_size
      
      panelw = (obj.sections[10].w - (lvar.trov_maxrows*(sz+10)))/2
              
      lvar.mdrag = {mx = mouse.mx, osz = math.max(lvar.trmix_panelsz,panelw), dir = -1}
      lupd.update_trbtns = true
      
    elseif mouse.mx < obj.sections[5040].x+obj.sections[5040].w then

      local my = mouse.my - obj.sections[5027].y
      if my < 10 then

        mouse.context = contexts.resize_mixer
        lvar.mixresize = {oh = lvar.trmix_h, offs = my, my = mouse.my}

      else
        local mx, my = mouse.mx, mouse.my
        mouse.mx = mx - obj.sections[5040].x
        mouse.my = my - obj.sections[5040].y
        local offs = lvar.dm_btnpnl_page*lvar.trmix_btnpnl_cols
  
        local sz = (lvar.trmixbtns_size+10)
        local col = lvar.trmix_btnpnl_cols - math.floor(mouse.mx/sz) + offs
        local col2 = math.floor(mouse.mx/sz)
        local row = math.floor(mouse.my/sz)+1
        local idx = lvar.dm_btnpnlidx
  
        if mouse.LB then
          if not lvar.dm_btnpnl then
            lvar.dm_btnpnl = {}
          end
          if not lvar.dm_btnpnl[idx] then
            lvar.dm_btnpnl[idx] = {}
          end
          if not lvar.dm_btnpnl[idx][row] then
            lvar.dm_btnpnl[idx][row] = {}
          end
          if lvar.dm_btnpnl[idx][row][col] then
  
            TSM_Trigger() 
  
            HighlightBox2(obj.sections[5040].x+col2*sz,obj.sections[5040].y+(row-1)*sz,sz-10,sz-10, lvar.dm_btnpnl[idx][row][col].rgb, lvar.btnflashtime)
  
            local actdata = lvar.dm_btnpnl[idx][row][col]
            --DBG(actdata.commid)
            if tonumber(actdata.commid) then
              reaper.Main_OnCommand(tonumber(actdata.commid), -1)
              --DBG('A '..actdata.commid)
            else
              reaper.Main_OnCommand(reaper.NamedCommandLookup(actdata.commid), -1)
              --DBG('B '..actdata.commid)
            end
  
          else
  
            TSM_Trigger()
  
            if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
              local commid, desc = GetActionInfoFromList()
              if desc then
                local ndesc = string.gsub(desc,'Script: ','')
                lvar.dm_btnpnl[idx][row][col] = {desc = desc, commid = commid, ndesc = ndesc}
                lupd.update_trbtns = true
              end
            end
          end
        elseif mouse.RB then
          if lvar.dm_btnpnl and lvar.dm_btnpnl[idx] and lvar.dm_btnpnl[idx][row] and lvar.dm_btnpnl[idx][row][col] then
  
            BtnPnl_Menu(idx,row,col,lvar.dm_btnpnl[idx][row][col],mx,my)
          
          else
  
            BtnPnl_Menu(idx,row,col,nil,mx,my)
          
          end
        end
        mouse.mx, mouse.my = mx, my
      end
      
    elseif not lvar.analyzer.active or (mouse.mx >= obj.sections[5005].x + obj.sections[5005].w - (obj.sections[5025].w+10)) or mouse.my - obj.sections[5027].y < 10 then

      --TRACK MIXER
      local my = mouse.my - obj.sections[5027].y
      if my < 10 then

        mouse.context = contexts.resize_mixer
        lvar.mixresize = {oh = lvar.trmix_h, offs = my, my = mouse.my}

      else
        if mouse.mx >= obj.sections[5005].x and mouse.mx <= obj.sections[5005].x + obj.sections[5005].w - (obj.sections[5025].w+10) then
          local track_x = math.floor((mouse.mx - obj.sections[5027].x) / (obj.sections[5025].w+10))+1+lvar.trbtns_offs
          local mx = mouse.mx - obj.sections[5005].x -(((track_x-lvar.trbtns_offs)-1) * (lvar.trbtns_size+10)) --8
          --DBG(mx..'  '..track_x)
          if lvar.dm_trackbtns[lvar.dm_tbidx][track_x] and lvar.dm_trackbtns[lvar.dm_tbidx][track_x].vol_normscale then
            --local mx, my = mouse.mx, mouse.my
            local vpos = obj.sections[5026].y+obj.sections[5026].h - math.floor(lvar.dm_trackbtns[lvar.dm_tbidx][track_x].vol_normscale*obj.sections[5026].h)
            local ktop = vpos - math.floor(skin.sliderknb_h/2)
            if mx >= obj.sections[5028].x and mx <= obj.sections[5028].x+obj.sections[5028].w and my >= obj.sections[5028].y and my <= obj.sections[5028].y+obj.sections[5028].h then

              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
                if dm_trackbtn then
                  local tr = GetTrack(dm_trackbtn.trn)
                  if tr then
                    if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                      tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                      if tr then
                        dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                      end
                    end
                  end
                  if tr then
                    trctls_table[2].func(tr, 0, false)
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix2 = true
                  end
                end
              else
                mouse.context = contexts.mixer_pan
                lvar.mixpan_drag = {offs = my-obj.sections[5028].y, tb = track_x, pan = lvar.dm_trackbtns[lvar.dm_tbidx][track_x].pan_norm}
              end

            elseif mx >= obj.sections[5026].x and mx <= obj.sections[5026].x+obj.sections[5026].w and (obj.sections[5026].h >= 90 and my >= ktop and my <= ktop+skin.sliderknb_h) then
              --track fader
              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
                if dm_trackbtn then
                  local tr = GetTrack(dm_trackbtn.trn)
                  if tr then
                    if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                      tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                      if tr then
                        dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                      end
                    end
                  end
                  if tr then
                    trctls_table[1].func(tr, 1, false)
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix2 = true
                  end
                end
              else
                --reaper.Undo_BeginBlock2(0)
                mouse.context = contexts.mixer_vol
                lvar.mixvol_drag = {snd = false, offs = vpos - my, tb = track_x, vol = lvar.dm_trackbtns[lvar.dm_tbidx][track_x].vol_normscale}
              end

            --elseif obj.sections[5026].h >= 90 and my >= obj.sections[5026].y and my <= obj.sections[5026].y+obj.sections[5026].h then

            elseif mx >= obj.sections[5029].x and mx <= obj.sections[5029].x+(obj.sections[5029].w*2)+2 and my >= obj.sections[5029].y and my <= obj.sections[5029].y+obj.sections[5029].h then

              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  reaper.Track_GetPeakHoldDB(tr, 0, true)
                  reaper.Track_GetPeakHoldDB(tr, 1, true)
                end
              end

            elseif mx >= obj.sections[5070].x and mx <= obj.sections[5070].x+obj.sections[5070].w and my >= obj.sections[5070].y and my <= obj.sections[5070].y+obj.sections[5070].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    local v = 1-reaper.GetMediaTrackInfo_Value(tr,'I_RECARM')
                    reaper.CSurf_OnRecArmChangeEx(tr, v, true)
                    
                    mouse.context = contexts.dmtrprm_swipe
                    lvar.dmtrprm_swipe = {val = v, otherval = 1-v, param = 'I_RECARM', x = track_x-lvar.trbtns_offs, delay = reaper.time_precise()+0.1}
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix = true

                  elseif mouse.RB then
                    if mouse.shift then
                      local x, y = reaper.GetMousePosition()
                      --reaper.ShowPopupMenu('',x,y,nil,tr)
                    else
                      local x, y = reaper.GetMousePosition()
                      reaper.ShowPopupMenu('track_input',x,y,nil,tr)
                    end
                  end
                end
              end

            elseif mx >= obj.sections[5073].x and mx <= obj.sections[5073].x+obj.sections[5073].w and my >= obj.sections[5073].y and my <= obj.sections[5073].y+obj.sections[5073].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    local v = 1-reaper.GetMediaTrackInfo_Value(tr,'B_MUTE')
                    reaper.CSurf_OnMuteChangeEx(tr, v, true)
                    
                    mouse.context = contexts.dmtrprm_swipe
                    lvar.dmtrprm_swipe = {val = v, otherval = 1-v, param = 'B_MUTE', x = track_x-lvar.trbtns_offs, delay = reaper.time_precise()+0.1}
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix = true

                  elseif mouse.RB then

                  end
                end
              end

            elseif mx >= obj.sections[5074].x and mx <= obj.sections[5074].x+obj.sections[5074].w and my >= obj.sections[5074].y and my <= obj.sections[5074].y+obj.sections[5074].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    local v = 2-reaper.GetMediaTrackInfo_Value(tr,'I_SOLO')
                    reaper.CSurf_OnSoloChangeEx(tr, v, true)
                    
                    mouse.context = contexts.dmtrprm_swipe
                    lvar.dmtrprm_swipe = {val = v, otherval = 2-v, param = 'I_SOLO', x = track_x-lvar.trbtns_offs, delay = reaper.time_precise()+0.1}
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix = true

                  elseif mouse.RB then

                  end
                end
              end

            elseif mx >= obj.sections[5071].x and mx <= obj.sections[5071].x+obj.sections[5071].w and my >= obj.sections[5071].y and my <= obj.sections[5071].y+obj.sections[5071].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    local v = 1-reaper.GetMediaTrackInfo_Value(tr,'I_FXEN')
                    reaper.SetMediaTrackInfo_Value(tr,'I_FXEN',v)
                    
                    mouse.context = contexts.dmtrprm_swipe
                    lvar.dmtrprm_swipe = {val = v, otherval = 1-v, param = 'I_FXEN', x = track_x-lvar.trbtns_offs, delay = reaper.time_precise()+0.1}                      
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix = true

                  elseif mouse.RB then

                  end
                end
              end
            elseif mx >= obj.sections[5072].x and mx <= obj.sections[5072].x+obj.sections[5072].w and my >= obj.sections[5072].y and my <= obj.sections[5072].y+obj.sections[5072].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    local v = 1-reaper.GetMediaTrackInfo_Value(tr,'B_PHASE')
                    reaper.SetMediaTrackInfo_Value(tr,'B_PHASE',v)
                    
                    mouse.context = contexts.dmtrprm_swipe
                    lvar.dmtrprm_swipe = {val = v, otherval = 1-v, param = 'B_PHASE', x = track_x-lvar.trbtns_offs, delay = reaper.time_precise()+0.1}                                            
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = track_x
                    lupd.update_trmix = true
                    
                  elseif mouse.RB then

                  end
                end
              end

            elseif mx >= obj.sections[5075].x and mx <= obj.sections[5075].x+obj.sections[5075].w and my >= obj.sections[5075].y and my <= obj.sections[5075].y+obj.sections[5075].h then
              local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][track_x]
              if dm_trackbtn then
                local tr = GetTrack(dm_trackbtn.trn)
                if tr then
                  if mouse.LB then
                    if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                      reaper.SetMediaTrackInfo_Value(tr,'B_MAINSEND',1-reaper.GetMediaTrackInfo_Value(tr,'B_MAINSEND'))
                    end
                  elseif mouse.RB then
                    local x, y = reaper.GetMousePosition()
                    reaper.ShowPopupMenu('track_routing',x,y,nil,tr)
                  end
                end
              end

            --[[elseif (obj.sections[5026].h < 90 and my >= obj.sections[5026].y-skin.sliderknb_h/2 and my <= obj.sections[5026].y+skin.sliderknb_h/2) then

              mouse.context = contexts.mixer_vol2
              lvar.mixvol_drag = {offs = my-(obj.sections[5026].y-skin.sliderknb_h/2), tb = track_x, vol = lvar.dm_trackbtns[lvar.dm_tbidx][track_x].vol_normscale}
              ]]
            end
          end

        elseif mouse.mx >= obj.sections[5005].x + obj.sections[5005].w - (obj.sections[5025].w+10) and mouse.mx <= obj.sections[5005].x + obj.sections[5005].w then

          local mx, my = mouse.mx, mouse.my
          mouse.mx, mouse.my = mouse.mx - obj.sections[5005].x, mouse.my - obj.sections[5025].y
          if MOUSE_click(obj.sections[5009]) then
            lvar.trmix_sndpnl_show = lvar.trmix_sndpnl_show + 1
            if lvar.trmix_sndpnl_show > 2 then
              lvar.trmix_sndpnl_show = 0
            end
            lupd.update_trbtns = true
          elseif MOUSE_click_RB(obj.sections[5009]) then
            lvar.trmix_sndpnl_show = lvar.trmix_sndpnl_show - 1
            if lvar.trmix_sndpnl_show < 0 then
              lvar.trmix_sndpnl_show = 2
            end
            lupd.update_trbtns = true
          elseif MOUSE_click(obj.sections[5010]) then
            tfxo_listpos = 0
            tfxorder = TrackFXOrder_Read()
            tfxreorder = TrackFXOrder_Read()
            if tfxorder then
              show_trackfxorder = true
              --lupd.update_gfx = true
              lupd.update_trackfxorder = true
              lupd.update_trbtns = true
              mouse.context = contexts.dummy
            end
          elseif MOUSE_click(obj.sections[5011]) then

            --if mouse.lastLBclicktime and not ((rt-mouse.lastLBclicktime) < 0.5) then
            if mouse.shift then
              lvar.analyzer.pos = lvar.analyzer.pos + 1
              if lvar.analyzer.pos >= #lvar.analyzer.mod then
                lvar.analyzer.pos = 0
              end
              DM_ShowAnalyzer(true)
              lupd.update_trbtns = true
            else
              DM_ShowAnalyzer(not lvar.analyzer.active)
              lupd.update_trbtns = true
            end

          elseif MOUSE_click_RB(obj.sections[5011]) then

            DM_AnalyzerMenu(mx, my)

          elseif lvar.trmix_sizebtn and MOUSE_click(obj.sections[5012]) then
            
            mouse.context = contexts.mixer_drag
                  
            local sz = lvar.trbtns_size
            
            panelw = (obj.sections[10].w - (lvar.trov_maxrows*(sz+10)))/2
                    
            lvar.mdrag = {mx = mx, osz = math.max(lvar.trmix_panelsz,panelw), dir = -1}
            lupd.update_trbtns = true
          end
          mouse.mx, mouse.my = mx, my

        elseif lvar.trmix_sndpnl_show > 0 and mouse.mx >= obj.sections[5030].x and mouse.mx <= obj.sections[5030].x + obj.sections[5030].w then

          local snd_idx = math.floor((mouse.mx - obj.sections[5030].x) / (lvar.sndpnl_cwidth+10)) + lvar.trmix_sndpnl_offs
          local tr = GetTrack(lvar.dynamicmode_trn)
          if tr then
            local hwcnt, scnt = 0
            if lvar.trmix_sndpnl_show == 1 then
              hwcnt = reaper.GetTrackNumSends(tr, 1)
              scnt = reaper.GetTrackNumSends(tr, 0) + reaper.GetTrackNumSends(tr, 1)
            else
              scnt = reaper.GetTrackNumSends(tr, -1)
            end
            if snd_idx <= scnt-1 then

              local vpos = obj.sections[5031].y+obj.sections[5031].h - math.floor(lvar.trmix_sndpnl_data[snd_idx].vol_normscale*obj.sections[5031].h)
              local ktop = vpos - math.floor(skin.sliderknb_h/2)
              local tr = GetTrack(lvar.dynamicmode_trn)
              local cat = 0
              local snd_idx2 = snd_idx
              local snd_idx3 = snd_idx
              if lvar.trmix_sndpnl_show == 1 then 
                if snd_idx < hwcnt then
                  cat = 1
                else
                  snd_idx2 = snd_idx - hwcnt
                end
              else
                cat = -1
                snd_idx3 = -snd_idx
              end
              if my < obj.sections[5032].y then

                if mouse.LB then
                  reaper.SetTrackSendInfo_Value(tr, cat, snd_idx2, 'B_MUTE', 1-reaper.GetTrackSendInfo_Value(tr, cat, snd_idx2, 'B_MUTE'))
                  lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = snd_idx
                  lupd.update_trmix = true
                  reaper.Undo_BeginBlock2(0)
                  reaper.Undo_EndBlock2(0,"Send Mute/Unmute",-1)
                else
                  local mstr = 'Remove Send'
                  if lvar.trmix_sndpnl_show == 2 then
                    mstr = 'Remove Receive'
                  end
                  gfx.x = mouse.mx
                  gfx.y = mouse.my
                  local res = gfx.showmenu(mstr)
                  if res > 0 then
                    if res == 1 then
                      reaper.RemoveTrackSend(tr, cat, snd_idx2)
                      lupd.update_trmix = true
                    end
                  end
                end
              elseif my >= obj.sections[5032].y and my <= obj.sections[5032].y+obj.sections[5032].h then

                if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                  local tr = GetTrack(lvar.dynamicmode_trn)
                  --[[if tr then
                    if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                      tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                      if tr then
                        dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                      end
                    end
                  end]]
                  if tr then
                    reaper.SetTrackSendUIPan(tr, snd_idx3, 0, 0)
                    lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = snd_idx
                    lupd.update_trmix = true
                  end
                else
                  mouse.context = contexts.sndpnl_pan
                  lvar.mixpan_drag = {offs = my-obj.sections[5032].y, tb = snd_idx, pan = lvar.trmix_sndpnl_data[snd_idx].pan_norm}
                end

              elseif my >= ktop and my <= ktop+skin.sliderknb_h then
                --send fader

                if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                  local tr = GetTrack(lvar.dynamicmode_trn)
                  --[[if tr then
                    if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                      tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                      if tr then
                        dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                      end
                    end
                  end]]
                  if tr then
                    reaper.SetTrackSendUIVol(tr, snd_idx3, 1, 0)
                    lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = snd_idx
                    lupd.update_trmix = true
                  end
                else
                  --DBG('a')
                  mouse.context = contexts.sndpnl_vol
                  lvar.mixvol_drag = {snd = true, offs = vpos - my, tb = snd_idx, vol = lvar.trmix_sndpnl_data[snd_idx].vol_normscale}
                end

              elseif my >= obj.sections[5031].y and my <= obj.sections[5031].y+obj.sections[5031].h then



              end


            else
              --Drag Send
              mouse.context = contexts.sndpnl_drag
              lvar.trmix_snddrag = {x = mx, y = my}
            end
          end


        elseif not (lvar.trmix_sndpnl_show > 0) and mouse.mx >= obj.sections[5042].x and mouse.mx <= obj.sections[5042].x + obj.sections[5042].w then
          local mx, my = mouse.mx, mouse.my
          mouse.mx = mx - obj.sections[5042].x
          mouse.my = my - obj.sections[5042].y
          local offs = lvar.dm_btnpnl_page*lvar.trmix_btnpnl2_cols

          local sz = (lvar.trmixbtns_size+10)
          local col = math.floor(mouse.mx/sz)+1+offs
          local row = math.floor(mouse.my/sz)+1
          --DBG(col..'  '..row)
          local idx = lvar.dm_btnpnl2idx

          if mouse.LB then
            if not lvar.dm_btnpnl then
              lvar.dm_btnpnl = {}
            end
            if not lvar.dm_btnpnl[idx] then
              lvar.dm_btnpnl[idx] = {}
            end
            if not lvar.dm_btnpnl[idx][row] then
              lvar.dm_btnpnl[idx][row] = {}
            end
            if lvar.dm_btnpnl[idx][row][col] then

              TSM_Trigger()

              HighlightBox2(obj.sections[5042].x+(col-1)*sz,obj.sections[5042].y+(row-1)*sz,sz-10,sz-10, lvar.dm_btnpnl[idx][row][col].rgb, lvar.btnflashtime)

              local actdata = lvar.dm_btnpnl[idx][row][col]
              if tonumber(actdata.commid) then
                reaper.Main_OnCommand(tonumber(actdata.commid), -1)
              else
                reaper.Main_OnCommand(reaper.NamedCommandLookup(actdata.commid), -1)
              end

            else

              TSM_Trigger()

              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                local commid, desc = GetActionInfoFromList()
                if desc and desc ~= '' then
                  local ndesc = string.gsub(desc,'Script: ','')
                  lvar.dm_btnpnl[idx][row][col] = {desc = desc, commid = commid, ndesc = ndesc}
                  lupd.update_trbtns = true
                else
                  OpenMsgBox(1, 'No action selected.', 1)
                end
              end
            end
          elseif mouse.RB then
            if lvar.dm_btnpnl and lvar.dm_btnpnl[idx] and lvar.dm_btnpnl[idx][row] and lvar.dm_btnpnl[idx][row][col] then

              BtnPnl_Menu(idx,row,col,lvar.dm_btnpnl[idx][row][col],mx,my)

            else
  
              BtnPnl_Menu(idx,row,col,nil,mx,my)
        
            end
          end
          mouse.mx, mouse.my = mx, my
        end
          --mouse.mx, mouse.my = mx, my
      end

    elseif lvar.analyzer.active and (MOUSE_click(obj.sections[5046]) or MOUSE_click_RB(obj.sections[5046])) then

      if lvar.analyzer.pos == 0 then
        local my = mouse.my - obj.sections[5046].y
        if my < 25 then
          local mx = mouse.mx - obj.sections[5046].x
          local w = (obj.sections[5048].w / (lvar.freqcnt+1))
          local p = math.floor(mx / w)
          if lvar.freq[p] then
            if mouse.LB then
              if mouse.shift or (mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
                local atr = Analyzer_GetTrack()
                if atr then
                  Analyzer_Link(lvar.dynamicmode_trn,atr,p)
                  lupd.update_analyzertracks = true
                  lupd.update_trmix = true
                end
              else
                local atr = Analyzer_GetTrack()
                if atr then
                  local v = reaper.TrackFX_GetParamNormalized(atr,0,12+p)
                  v = 1-v
                  reaper.TrackFX_SetParamNormalized(atr,0,12+p,v)
                  if v == 1 then
                    lvar.freq[p].active = true
                  else
                    lvar.freq[p].active = false
                  end
                  lupd.update_analyzertracks = true
                  lupd.update_trmix = true
                end
              end
            else
              local atr = Analyzer_GetTrack()
              if atr then
                local vv = reaper.TrackFX_GetParamNormalized(atr,0,12+p)
                if not lvar.freqsolo or (vv == 0) then

                  if not lvar.freqsolo_mem then
                    lvar.freqsolo_mem = {}
                    for i = 0, lvar.freqcnt+1 do
                      lvar.freqsolo_mem[i] = reaper.TrackFX_GetParamNormalized(atr,0,12+i)
                    end
                  end
                  for i = 0, lvar.freqcnt+1 do
                    if i ~= p then
                      reaper.TrackFX_SetParamNormalized(atr,0,12+i,0)
                    end
                  end
                  reaper.TrackFX_SetParamNormalized(atr,0,12+p,1)
                  lvar.freqsolo = p
                else
                  lvar.freqsolo = nil

                  for i = 0, lvar.freqcnt+1 do
                    local v = 1
                    if lvar.freqsolo_mem and lvar.freqsolo_mem[i] then
                      v = lvar.freqsolo_mem[i]
                    end
                    reaper.TrackFX_SetParamNormalized(atr,0,12+i,v)
                  end
                  lvar.freqsolo_mem = nil
                end
                lupd.update_analyzertracks = true
                lupd.update_trmix = true
              end
            end
          end
        else
          local tr = Analyzer_GetTrack()
          local idx = lvar.analyzer.pos
          if tr then
            local param = 8
            local w = obj.sections[5046].w
            local mx = math.max(0,mouse.mx - obj.sections[5046].x)

            local zm = (reaper.TrackFX_GetParamNormalized(tr,idx,7))*24 + 1
            local ox = reaper.TrackFX_GetParamNormalized(tr,idx,param)
            --local offx = math.ceil(ox*((w*zm)-w));
            local zm2 = ((w)*zm);
            offx = math.ceil(ox*zm2 - w/2);
            offx = math.max(offx,0);
            offx = math.min(offx,(w)*zm-w);
            local val = (mx+offx)/(w*zm)
            reaper.TrackFX_SetParamNormalized(tr,idx,param,val)
            lupd.update_analyzerctls = true
            lupd.update_trmix = true

          end
        end
      end
    end

    return noscroll
    
  end

  function A_Click_M0_Snapshot(rt, noscroll)

    A_Run_SnapshotsWin(rt)
    noscroll = true

    return noscroll
    
  end

  function A_Click_M0_fSnapshot(rt, noscroll)

    if show_xysnapshots == true then
    
      if MOUSE_click_RB(obj.sections[180]) then
        show_xysnapshots = false
        RedrawGUIBitmap()
        lupd.update_surface = true
      end

      local snapmx, snapmy = mouse.mx, mouse.my
      mouse.mx = mouse.mx - obj.sections[180].x
      mouse.my = mouse.my - obj.sections[180].y

      if --[[mouse.context == nil and]] MOUSE_click(obj.sections[182]) then
        mouse.context = contexts.resizefsnapwindow
        resizesnapwin = {origh = obj.sections[180].h,
                         offy = mouse.my}

      elseif --[[mouse.context == nil and]] MOUSE_click(obj.sections[181]) then
        if snapshots and snapshots[tracks[track_select].strip] then
          local i = math.floor((mouse.my-obj.sections[181].y)/butt_h)

          if i == 0 then
            local ix = math.floor((mouse.mx-obj.sections[181].x)/(obj.sections[180].w/2))
            if ix == 0 then
              fssoffset = fssoffset-FSS_butt_cnt
              if fssoffset < 0 then fssoffset = 0 end
            else
              if fsstype_select == 1 then
                fssoffset = F_limit(fssoffset+FSS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select]-FSS_butt_cnt))
              elseif fsstype_select > 1 then
                fssoffset = F_limit(fssoffset+FSS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select].snapshot-FSS_butt_cnt))
              end
            end
            lupd.update_ctls = true
            lupd.update_fsnaps = true
          else
            if snapshots and snapshots[tracks[track_select].strip] then
              local maxss
              if fsstype_select == 1 then
                maxss = #snapshots[tracks[track_select].strip][page][fsstype_select]
              else
                maxss = #snapshots[tracks[track_select].strip][page][fsstype_select].snapshot
              end

              if fssoffset+i <= maxss then
                fss_select = fssoffset+i

                if xysnap_select == 1 then
                  strips[tracks[track_select].strip][page].controls[xy_select].xydata.snapa = fss_select
                elseif xysnap_select == 2 then
                  strips[tracks[track_select].strip][page].controls[xy_select].xydata.snapb = fss_select
                elseif xysnap_select == 3 then
                  strips[tracks[track_select].strip][page].controls[xy_select].xydata.snapc = fss_select
                elseif xysnap_select == 4 then
                  strips[tracks[track_select].strip][page].controls[xy_select].xydata.snapd = fss_select
                end

                g_savedirty = true
                show_xysnapshots = false
                RedrawGUIBitmap()
                lupd.update_surface = true
              end
            end
          end
        end
      end

      mouse.mx = snapmx
      mouse.my = snapmy
      noscroll = true

    elseif show_fsnapshots == true then

      if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
        show_fsnapshots = false
        lupd.update_surface = true
        RedrawGUIBitmap()
      elseif --[[mouse.context == nil and]] MOUSE_click_RB(obj.sections[180]) then
        show_fsnapshots = false
        lupd.update_surface = true
        RedrawGUIBitmap()
      end

      local snapmx, snapmy = mouse.mx, mouse.my
      mouse.mx = mouse.mx - obj.sections[180].x
      mouse.my = mouse.my - obj.sections[180].y

      if --[[mouse.context == nil and]] MOUSE_click(obj.sections[182]) then
        mouse.context = contexts.resizefsnapwindow
        resizesnapwin = {origh = obj.sections[180].h,
                         offy = mouse.my}

      elseif --[[mouse.context == nil and]] MOUSE_click(obj.sections[181]) then
        if snapshots and snapshots[tracks[track_select].strip] then
          local i = math.floor((mouse.my-obj.sections[181].y)/butt_h)

          if i == 0 then
            local ix = math.floor((mouse.mx-obj.sections[181].x)/(obj.sections[180].w/2))
            if ix == 0 then
              fssoffset = fssoffset-FSS_butt_cnt
              if fssoffset < 0 then fssoffset = 0 end
            else
              if fsstype_select == 1 then
                fssoffset = F_limit(fssoffset+FSS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select]-FSS_butt_cnt))
              elseif fsstype_select > 1 then
                fssoffset = F_limit(fssoffset+FSS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select].snapshot-FSS_butt_cnt))
              end
            end
            lupd.update_ctls = true
            lupd.update_fsnaps = true
          else
            if snapshots and snapshots[tracks[track_select].strip] then
              local maxss
              if fsstype_select == 1 then
                maxss = #snapshots[tracks[track_select].strip][page][fsstype_select]
              else
                maxss = #snapshots[tracks[track_select].strip][page][fsstype_select].snapshot
              end

              if fssoffset+i <= maxss then
                fss_select = fssoffset+i
                Snapshot_Set(tracks[track_select].strip, page, fsstype_select, fss_select)
                SetCtlDirty(fss_ctl)
                lupd.update_ctls = true --to update snapshot ctls
                lupd.update_fsnaps = true
                if sstype_select == fsstype_select then
                  ss_select = fss_select
                  lupd.update_snaps = true
                end

                if strips[tracks[track_select].strip][page].controls[fss_ctl].param_info.paramnum == 1 then
                  show_fsnapshots = false
                  lupd.update_surface = true
                  RedrawGUIBitmap()
                end
              end
            end
          end
        end
      end

      mouse.mx = snapmx
      mouse.my = snapmy
      noscroll = true
    end

    return noscroll
    
  end

  function A_Click_M0_Modulators(rt, noscroll)

    noscroll = true
    if show_fsnapshots == true or show_xysnapshots then
      show_fsnapshots = false
      show_xysnapshots = false
      lupd.update_surface = true
      RedrawGUIBitmap()
    end

    if modulators[mod_select] then

      local mx, my = mouse.mx, mouse.my
      mouse.mx = mouse.mx - obj.sections[1100].x
      mouse.my = mouse.my - obj.sections[1100].y

      local m = modulators[mod_select]
      local barw = ((obj.sections[1101].w-2) / m.steps)
      xywh = {x = obj.sections[1101].x,
              y = obj.sections[1101].y,
              w = barw * m.steps,
              h = obj.sections[1101].h}

      if MOUSE_click(xywh) then

        if mouse.ctrl and mouse.shift then
          lvar.modnudge = {mx = mx, barw = barw}
          mouse.context = contexts.mod_nudge
        else
          mouse.context = contexts.mod_draw
          moddraw = {offs = offs, barw = barw}
        end
        
      elseif MOUSE_click_RB(obj.sections[1101]) then

        ModMenu(mx, my)

      elseif MOUSE_click(obj.sections[1123]) then
        settings_moddock = not settings_moddock
        if settings_moddock == false then
          if modwinsz.h < modwin.minh then
            modwinsz.h = modwin.minh
          end
          modwinsz.minimized = false
        end
        obj = GetObjects()
        lupd.update_gfx = true
        lupd.update_lfoedit = true
        RedrawGUIBitmap()

      elseif MOUSE_click(obj.sections[1115]) and modwinsz.minimized ~= true then

        mod_select = mod_select - 1
        if mod_select < 1 then
          mod_select = #modulators
        end
        lupd.update_gfx = true

      elseif MOUSE_click(obj.sections[1116]) and modwinsz.minimized ~= true then

        mod_select = mod_select + 1
        if mod_select > #modulators then
          mod_select = 1
        end
        lupd.update_gfx = true

      elseif MOUSE_click_RB(obj.sections[1117]) and modwinsz.minimized ~= true then
        show_modass = not show_modass
        if show_modass == true then
          lvar.modass = PopModAssObj()
          if lvar.modass then
            lvar.modass.offset = 0
          end
        else

        end
        lupd.update_gfx = true
        RedrawGUIBitmap()

      elseif MOUSE_click(obj.sections[1117]) and modwinsz.minimized ~= true then

        if not mouse.ctrl then
          show_modass = false
          RedrawGUIBitmap()
          if show_striplayout == false then
            mouse.context = contexts.dragmod
            dragmod = {x = mouse.mx, y = mouse.my}
          end
          lupd.update_surface = true
        else
          lvar.modass = PopModAssObj()
          if lvar.modass then
            lvar.modass.offset = 0
          end
          show_modass = true
          RedrawGUIBitmap()
          lupd.update_gfx = true
        end

      elseif MOUSE_click(obj.sections[1118]) and modwinsz.minimized ~= true then

        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.20 then
          local m = modulators[mod_select]
          if m then
            if m.targets and #m.targets > 0 then
              for t = #m.targets, 1, -1 do
                if m.targets[t].strip == tracks[track_select].strip and m.targets[t].page == page then
                  SetCtlDirty(m.targets[t].ctl)
                end
                local ctl
                if m.targets[t].dm_guid then
                  if m.targets[t].dm_guid == lvar.dynamicmode_guid then
                    ctl = strips[tracks[track_select].strip][page].controls[m.targets[t].ctl]
                  else
                    ctl = lvar.stripstore[m.targets[t].dm_guid].controls[m.targets[t].ctl]
                  end
                else
                  ctl = strips[m.targets[t].strip][m.targets[t].page].controls[m.targets[t].ctl]
                end

                Mod_RemoveAssign(m.targets[t].strip, m.targets[t].page, m.targets[t].ctl, m.targets[t].dm_guid)
                if ctl then
                  ctl.mod = nil
                end
              end
              lupd.update_sidebar = true
              lupd.update_lfoedit = true
              lupd.update_surface = true
              lupd.update_ctls = true
            end
          end
        end

      elseif MOUSE_click(obj.sections[1111])  then

        if modwinsz and modwinsz.minimized ~= true then
          mouse.context = contexts.modwin_resize
          modwinrsz = {mx = mx, my = my, w = modwinsz.w, h = modwinsz.h}
        end

      elseif MOUSE_click(obj.sections[1112]) then

        if settings_moddock == true then
          mouse.context = contexts.modwin_resize2
          modwinrsz = {mx = mx, my = my, w = modwinsz.w, h = modwinsz.h}
        else
          mouse.context = contexts.modwin_move
          modwinmv = {mx = mx, my = my, x = modwinsz.x, y = modwinsz.y}
        end

      elseif MOUSE_click_RB(obj.sections[1112]) then
        if modwinsz.minimized == true then
          modwinsz.h = modwinsz.oh
          modwinsz.minimized = false

          --modwinsz.resize = true
          --obj = GetObjects()
          lupd.update_lfoedit = true
          lupd.update_gfx = true

        else
          modwinsz.oh = modwinsz.h
          modwinsz.h = gui.winsz.pnltit
          modwinsz.minimized = true

        end
        modwinsz.resize = true

        if settings_sbdock == true and lvar.stripbrowser.dockpos == 1 then
          --HACKY - FIX
          SBWin_CheckSize()
          obj = GetObjects()
          obj = GetObjects()
          lupd.update_gfx = true
        end
        obj = GetObjects()
        lupd.update_lfoedit = true
        lupd.update_surface = true


      elseif MOUSE_click(obj.sections[1102]) then

        local os = m.steps
        m.stepsmult = math.min(m.stepsmult + 1,#lvar.divmult_table)
        if mouse.shift == false then
          if m.stepsmult == 5 or m.stepsmult == 6 or m.stepsmult == 7 then
            m.stepsmult = 8
          elseif m.stepsmult == 3 then
            m.stepsmult = 4
          end
        end
        m.steps = (m.div * lvar.divmult_table[m.stepsmult])
        if os ~= m.steps then
          local d = {}
          local cnt = #m.data
          if not mouse.ctrl then
            for i = 1, cnt do
              d[i*2-1] = m.data[i]
              if m.interpolate == true then
                if m.data[i+1] then
                  d[i*2] = m.data[i] + ((m.data[i+1] - m.data[i])/2)
                else
                  d[i*2] = m.data[i] + ((m.data[1] - m.data[i])/2)
                end
              else
                d[i*2] = m.data[i]
              end
            end
            if m.steps > cnt*2 then
              local v = m.data[cnt*2]
              for i = cnt*2+1, m.steps do
                d[i] = v
              end
            end
          else
            for i = 1, m.steps do
              d[i] = m.data[i] or 0.5
            end
          end
          m.data = d
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click_RB(obj.sections[1102]) then

        local os = m.steps
        m.stepsmult = math.max(m.stepsmult - 1,1)
        if mouse.shift == false then
          if m.stepsmult == 5 or m.stepsmult == 6 or m.stepsmult == 7 then
            m.stepsmult = 4
          elseif m.stepsmult == 3 then
            m.stepsmult = 2
          end
        end
        m.steps = (m.div * lvar.divmult_table[m.stepsmult])
        if os ~= m.steps then
          local d = {}
          if not mouse.ctrl then
            for i = 1, m.steps do
              d[i] = m.data[i*2-1] or 0.5
            end
          else
            for i = 1, m.steps do
              d[i] = m.data[i] or 0.5
            end
          end
          m.data = d
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1104]) then

        m.syncv = math.min(m.syncv + 1,#lvar.sync_table)
        lupd.update_lfoedit = true

      elseif MOUSE_click_RB(obj.sections[1104]) then

        m.syncv = math.max(m.syncv - 1,12)
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1105]) then

        m.interpolate = not m.interpolate
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1108]) then

        mouse.context = contexts.modoffset_slider
        modoffs = {x = obj.sections[1100].x + obj.sections[1108].x,
                   y = obj.sections[1100].y + obj.sections[1108].y,
                   w = obj.sections[1108].w,
                   h = obj.sections[1108].h,
                   val = m.offset}
        modoffs.yoff = -(my - (modoffs.y+modoffs.h/2))
        oms = mouse.shift

      elseif MOUSE_click(obj.sections[1109]) then

        mouse.context = contexts.modmin_slider
        modoffs = {x = obj.sections[1100].x + obj.sections[1109].x,
                   y = obj.sections[1100].y + obj.sections[1109].y,
                   w = obj.sections[1109].w,
                   h = obj.sections[1109].h,
                   val = m.min,
                   odiff = m.max-m.min}
        modoffs.yoff = -(my - (modoffs.y+modoffs.h/2))
        oms = mouse.shift
        omc = mouse.ctrl

      elseif MOUSE_click(obj.sections[1110]) then

        mouse.context = contexts.modmax_slider
        modoffs = {x = obj.sections[1100].x + obj.sections[1110].x,
                   y = obj.sections[1100].y + obj.sections[1110].y,
                   w = obj.sections[1110].w,
                   h = obj.sections[1110].h,
                   val = m.max,
                   odiff = m.max-m.min}
        modoffs.yoff = -(my - (modoffs.y+modoffs.h/2))
        oms = mouse.shift
        omc = mouse.ctrl

      elseif MOUSE_click(obj.sections[1107]) then

        m.div = math.min(m.div + 1,12)
        m.steps = (m.div * lvar.divmult_table[m.stepsmult])
        local dcnt = #m.data
        if m.steps > dcnt then
          local d = {}
          local v = m.data[dcnt]
          for i = 1, m.steps do
            if m.data[i] then
              d[i] = m.data[i]
            else
              d[i] = v
            end
          end
          m.data = d
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1113]) then
        local min = m.min
        local max = m.max
        --DBG(max..'  '..min)
        for i = 1, #m.data do
          if m.mode >= 2 then
            maxx = takeswitch_max
            if m.mode == 3 then
              maxx = lvar.maxsamples
            end
            m.data[i] = math.floor((math.random() * ((max-min)+1/maxx))*maxx)/maxx + min
          else
            m.data[i] = ((math.random() * (max-min)) + min)
          end
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1114]) then

        if tonumber(m.mode) == nil then
          m.mode = 1
        else
          m.mode = ((m.mode+1) % (#lvar.lfomode_table)) + 1
          --DBG(m.mode)
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click_RB(obj.sections[1114]) then

        if m.targets then
          local max = 0
          local mmx
          for t = 1,#m.targets do
            if m.targets[t].targettype == 1 then
              if strips[m.targets[t].strip] and strips[m.targets[t].strip][m.targets[t].page].controls[m.targets[t].ctl] then
                local ctl = strips[m.targets[t].strip][m.targets[t].page].controls[m.targets[t].ctl]
                if ctl.ctlcat == ctlcats.takeswitcher then
                  if ctl.iteminfo then
                    max = math.max(ctl.iteminfo.numtakes)
                    mmx = takeswitch_max
                  end
                elseif ctl.ctlcat == ctlcats.rs5k then
                  if ctl.rsdata then
                    max = #ctl.rsdata.samples
                    mmx = lvar.maxsamples-1
                  end
                end
              end
            end
          end
          if max > 1 then
            m.max = (max-1)/mmx
            m.min = 0
          end
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click_RB(obj.sections[1107]) then

        m.div = math.max(m.div - 1,3)
        m.steps = (m.div * lvar.divmult_table[m.stepsmult])
        local dcnt = #m.data
        if m.steps > dcnt then
          local d = {}
          local v = m.data[#m.data]
          for i = 1, m.steps do
            if m.data[i] then
              d[i] = m.data[i]
            else
              d[i] = v
            end
          end
          m.data = d
        end
        lupd.update_lfoedit = true

      elseif MOUSE_click(obj.sections[1106]) then

        m.active = not m.active
        Mod_SetTargetsDirty(mod_select)
        lupd.update_lfoedit = true

      end

      mouse.mx, mouse.my = mx, my

    end

    return noscroll
    
  end

  function A_Click_M0_Mutate(rt, noscroll)

    local mutate_settings = lvar.mutate_settings
    
    noscroll = true
    mx,my = mouse.mx, mouse.my
    mouse.mx = mouse.mx - obj.sections[1120].x
    mouse.my = mouse.my - obj.sections[1120].y

    xywh = {x = 0, y = 0, w = obj.sections[1120].w, h = gui.winsz.pnltit * pnl_scale}
    if MOUSE_click(xywh) then
      mouse.context = contexts.move_mutatewin
      movemutatewin = {dx = mouse.mx, dy = mouse.my}

    elseif MOUSE_click_RB(xywh) then
      show_mutate = false
      lupd.update_surface = true
      RedrawGUIBitmap()

    elseif MOUSE_click(obj.sections[1121]) then
      mouse.context = contexts.mutate_amt
      mutateamt = {pos = mutate_settings.mutate_max, yoff = my-(obj.sections[1121].y+obj.sections[1121].h/2)}

    elseif MOUSE_click(obj.sections[1122]) then
      mutate_settings.dir = mutate_settings.dir + 1
      if mutate_settings.dir > 2 then
        mutate_settings.dir = 0
      end
      lupd.update_mutate = true

    elseif MOUSE_click_RB(obj.sections[1122]) then
      mutate_settings.dir = mutate_settings.dir - 1
      if mutate_settings.dir < 0 then
        mutate_settings.dir = 2
      end
      lupd.update_mutate = true
    end

    mouse.mx = mx
    mouse.my = my

    return noscroll
    
  end

  function A_Click_M0_Random(rt, noscroll)

    noscroll = true
    mx,my = mouse.mx, mouse.my
    mouse.mx = mouse.mx - obj.sections[1130].x
    mouse.my = mouse.my - obj.sections[1130].y
    
    xywh = {x = 0, y = 0, w = obj.sections[1130].w, h = gui.winsz.pnltit * pnl_scale}
    if MOUSE_click(xywh) then
      mouse.context = contexts.move_randomwin
      moverandomwin = {dx = mouse.mx, dy = mouse.my}
    
    elseif MOUSE_click_RB(xywh) then
      show_randomopts = false
      if randopts_selectctl then
        SetCtlDirty(randopts_selectctl)
        randopts_selectctl = nil
        lupd.update_ctls = true
      end
      lupd.update_surface = true
      RedrawGUIBitmap()
      
    elseif MOUSE_click(obj.sections[1131]) then
    
      randomopts_select.useadv = not randomopts_select.useadv
      lupd.update_randomopts = true
      lupd.update_surface = true
    
    elseif MOUSE_click(obj.sections[1132]) then
    
      randomopts_select.snapshotsonly = not randomopts_select.snapshotsonly
      lupd.update_randomopts = true
      lupd.update_surface = true
    
    elseif MOUSE_click(obj.sections[1133]) then
    
      RandomOpts_ParamMenu(mx, my)
    
    elseif MOUSE_click(obj.sections[1134]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      local lgtype
      if lg and randomopts_select.linkgrps[lg] then
        lgtype = randomopts_select.linkgrps[lg].type
      end
    
      if lgtype ~= 2 and lgtype ~= 3 then
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
          OpenEB(201,'Please enter value for min:',randomopts_select.ctls[p].min)
        else
          mouse.context = contexts.lg_min
          draglg = {pos = randomopts_select.ctls[p].min, yoff = my-(obj.sections[1134].y+obj.sections[1134].h/2), shift = mouse.shift}
        end
      end
    
    elseif MOUSE_click(obj.sections[1135]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      local lgtype
      if lg and randomopts_select.linkgrps[lg] then
        lgtype = randomopts_select.linkgrps[lg].type
      end
    
      if lgtype ~= 2 and lgtype ~= 3 then
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
          OpenEB(202,'Please enter value for max:',randomopts_select.ctls[p].max)
        else
          mouse.context = contexts.lg_max
          draglg = {pos = randomopts_select.ctls[p].max, yoff = my-(obj.sections[1135].y+obj.sections[1135].h/2), shift = mouse.shift}
        end
      end
    
    elseif MOUSE_click(obj.sections[1137]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
    
      if not lg then
        mouse.context = contexts.lg_probability
        draglg = {pos = randomopts_select.ctls[p].rprob, yoff = my-(obj.sections[1137].y+obj.sections[1137].h/2)}
      end
    
    elseif MOUSE_click(obj.sections[1138]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      local lgtype
      if lg and randomopts_select.linkgrps[lg] then
        lgtype = randomopts_select.linkgrps[lg].type
      end
    
      if not lgtype or lgtype == 1 then
        mouse.context = contexts.lg_bias
        draglg = {pos = randomopts_select.ctls[p].bias, yoff = my-(obj.sections[1138].y+obj.sections[1138].h/2)}
      end
    
    elseif MOUSE_click(obj.sections[1139]) then
      local p = randomopts_select.param
      local rctl = randomopts_select.ctls[p]
      if rctl then
        local lg = rctl.linkgrp
        if lg and randomopts_select.linkgrps[lg].type == 4 then
          rctl.inverted = not (rctl.inverted or false)
          lupd.update_randomopts = true
        end
      end
      
    elseif MOUSE_click(obj.sections[1140]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      local lgtype
      if lg and randomopts_select.linkgrps[lg] then
        lgtype = randomopts_select.linkgrps[lg].type
      end
    
      if not lgtype or lgtype == 1 then
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
          --if randomopts_select.ctls[p] then
            OpenEB(203,'Please enter value for range:',randomopts_select.ctls[p].amount*100)
          --end
        else
          mouse.context = contexts.lg_range
          draglg = {pos = randomopts_select.ctls[p].amount, yoff = my-(obj.sections[1140].y+obj.sections[1140].h/2), shift = mouse.shift}
        end
      end
    
    elseif MOUSE_click(obj.sections[1146]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      local lgtype
      if lg and randomopts_select.linkgrps[lg] then
        lgtype = randomopts_select.linkgrps[lg].type
      end
    
      if not lgtype or lgtype == 1 or lgtype == 4 then
        mouse.context = contexts.lg_wild
        draglg = {pos = randomopts_select.ctls[p].wild *10, yoff = my-(obj.sections[1146].y+obj.sections[1146].h/2)}
      end
    
    elseif MOUSE_click(obj.sections[1144]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      if lg and randomopts_select.linkgrps[lg] then
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
          if randomopts_select.linkgrps[lg].type == 4 then
            OpenEB(200,'Please enter value for range:',randomopts_select.linkgrps[lg].X*100)
          end
        else
          --if randomopts_select.linkgrps[lg] and randomopts_select.linkgrps[lg].type <= 3 then
            mouse.context = contexts.lg_X
            draglg = {pos = randomopts_select.linkgrps[lg].X, yoff = my-(obj.sections[1144].y+obj.sections[1144].h/2), shift = mouse.shift}
          --end
        end
      end
    
    elseif MOUSE_click(obj.sections[1136]) then
    
      local p = randomopts_select.param
    
      randomopts_select.ctls[p].linkgrp = (randomopts_select.ctls[p].linkgrp or 0) + 1
      RandomOpts_LG_INIT()
      lupd.update_randomopts = true
    
    elseif MOUSE_click_RB(obj.sections[1136]) then
    
      local p = randomopts_select.param
    
      randomopts_select.ctls[p].linkgrp = math.max((randomopts_select.ctls[p].linkgrp or 0) - 1,0)
      if randomopts_select.ctls[p].linkgrp == 0 then
        randomopts_select.ctls[p].linkgrp = nil
      else
        RandomOpts_LG_INIT()
      end
      lupd.update_randomopts = true
    
    elseif MOUSE_click(obj.sections[1147]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      if not lg or randomopts_select.linkgrps[lg] and randomopts_select.linkgrps[lg].type == 1 then
        randomopts_select.ctls[p].snap = not (randomopts_select.ctls[p].snap or false)
        lupd.update_randomopts = true
      end
    
    elseif MOUSE_click(obj.sections[1148]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      if lg and randomopts_select.linkgrps[lg] and randomopts_select.linkgrps[lg].type == 4 then
        randomopts_select.linkgrps[lg].snap = not (randomopts_select.linkgrps[lg].snap or false)
        lupd.update_randomopts = true
      end
    
    elseif MOUSE_click(obj.sections[1143]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      if lg and randomopts_select.linkgrps[lg] then
        randomopts_select.linkgrps[lg].type = math.min(randomopts_select.linkgrps[lg].type + 1,#lvar.linkgrp_table)
        lupd.update_randomopts = true
      end
    
    elseif MOUSE_click_RB(obj.sections[1143]) then
    
      local p = randomopts_select.param
      local lg = randomopts_select.ctls[p].linkgrp
      if lg and randomopts_select.linkgrps[lg] then
        randomopts_select.linkgrps[lg].type = math.max(randomopts_select.linkgrps[lg].type - 1,1)
        lupd.update_randomopts = true
      end
    
    elseif MOUSE_click(obj.sections[1145]) then
    
      if mouse.mx < obj.sections[1145].x+obj.sections[1145].w/2 then
        randomopts_select.param = randomopts_select.param - 1
      else
        randomopts_select.param = randomopts_select.param + 1
      end
      randomopts_select.param = F_limit(randomopts_select.param,1,#randomopts_select.ctls)
      lupd.update_randomopts = true
    
    end
    
    mouse.mx = mx
    mouse.my = my

    return noscroll
    
  end

  function A_Click_M0_MidiOut(rt, noscroll)



    return noscroll
    
  end

  function A_Click_M0_TFXOrder(rt, noscroll)



    return noscroll
    
  end

  function A_Click_M0_Settings(rt, noscroll)



    return noscroll
    
  end

  function A_Click_M0_Dropdown(rt, noscroll)



    return noscroll
    
  end

  function A_Click_M0_ModAss(rt, noscroll)

    noscroll = A_Run_ModAss(noscroll, rt)

    return noscroll
    
  end

  function A_Click_M0_Fullscreen1(rt, noscroll)

    if snap_edit_mode then
      noscroll = A_Run_SnapEdit(noscroll, rt)
    elseif macro_edit_mode then
      noscroll = A_Run_MacroEdit(noscroll, rt)
    elseif show_eqcontrol then
      noscroll = A_Run_EQControl(noscroll, rt)
    end
    
    return noscroll
    
  end

  function A_Click_M0_Fullscreen2(rt, noscroll)

    noscroll = A_Run_PinMatrix(noscroll, rt)
    
    return noscroll
    
  end

  ------------------------
  --- M0 MOUSE WHEEL
  ------------------------
  
  function A_Wheel_M0_StripSurface(rt, noscroll, v)

    return noscroll
  
  end
  
  function A_Wheel_M0_Sidebar(rt, noscroll, v)
    
    if MOUSE_over(obj.sections[500]) then
    
      if mode0_submode == 0 then
        if hideunusedtracks == true then
          tlist_offset = F_limit(tlist_offset - v, 0, #tracksused_idx)
        else
          tlist_offset = F_limit(tlist_offset - v, 0, #tracks+1)
        end
      elseif mode0_submode == 1 then
        if LBX_CTL_TRACK_INF then
          fdlist_offset = F_limit(fdlist_offset - v, 0, lvar.LBX_FB_CNT*LBX_CTL_TRACK_INF.count -1)
        end
      elseif mode0_submode == 2 then
        mdlist_offset = F_limit(mdlist_offset - v, 0, #modulators-1)
      end
      lupd.update_sidebar = true
    
      gfx.mouse_wheel = 0
    end
  
    return noscroll  
    
  end
  
  function A_Wheel_M0_StripBrowser(rt, noscroll, v)

    local mx, my = mouse.mx, mouse.my
    mouse.mx, mouse.my = mouse.mx - obj.sections[1350].x, mouse.my - obj.sections[1350].y

    if lvar.stripbrowser.showlist == true and MOUSE_over(obj.sections[1351]) then
      local bcnt = math.floor(obj.sections[1351].h/(butt_h*pnl_scale))-1

      sbsflist_offset = F_limit(sbsflist_offset - v,0,math.max(#strip_folders - bcnt +1,0))
      lupd.update_stripbrowser = true

    elseif MOUSE_over(obj.sections[1353]) then
      local sel
      if lvar.stripbrowser.favs == true then
        sel = -1
      else
        sel = stripfol_select
      end

      sel = F_limit(sel - v, -1, #strip_folders)
      if sel == -1 then
        lvar.stripbrowser.favs = true
        lvar.delayfunction.stripbrowser_reload_delay = reaper.time_precise() + 0.2
      elseif strip_folders[sel] then
        lvar.stripbrowser.favs = false
        stripfol_select = sel
        lvar.delayfunction.stripbrowser_reload_delay = reaper.time_precise() + 0.2
      end
      
      lupd.update_stripbrowser = true

    elseif lvar.sb_folbtn_c > 1 and MOUSE_over(obj.sections[1358]) and lvar.sb_folbtn_show then

      lvar.sb_folbtn_offs = F_limit(lvar.sb_folbtn_offs - v*lvar.sb_folbtn_c, 0, #strip_folders-lvar.sb_folbtn_c+2)
      lupd.update_stripbrowser = true

    elseif MOUSE_over(obj.sections[1352]) then
      if mouse.shift ~= true then
        local perpage = lvar.stripbrowser.xnum * lvar.stripbrowser.ynum
        local max
        if lvar.stripbrowser.search == true then
          max = math.floor((#strip_search-1) / perpage)
        elseif lvar.stripbrowser.favs == true then
          max = math.floor((#strip_favs-1) / perpage)
        else
          max = math.floor(#strip_files / perpage)
        end
        if v > 0 then v = 1 else v = -1 end
        lvar.stripbrowser.page = F_limit(lvar.stripbrowser.page - v,0,max)
        --DBG('page '..lvar.stripbrowser.page..'   mousewheel  '..gfx.mouse_wheel..'  max  '.. max)
        GUI_DrawSB_Strips(obj, gui)
        lupd.update_stripbrowser = true
      else
        if mouse.ctrl then
          lvar.stripbrowser.tsz = F_limit((lvar.stripbrowser.tsz or 0) + v,-5,5)
          lupd.update_stripbrowser = true
        else
          lvar.reloadsbimages = true
          lvar.stripbrowser.minw = math.max(lvar.stripbrowser.minw + v*5, 60)
          lvar.stripbrowser.minh = math.floor(lvar.stripbrowser.minw * 3/4)
          lvar.stripbrowser.minw = math.floor(lvar.stripbrowser.minw)
          lvar.stripbrowser.page = 0
          lupd.update_stripbrowser = true
          obj = PosStripBrowser(obj)
        end
      end
    end
    mouse.mx, mouse.my = mx, my
    gfx.mouse_wheel = 0
    
    return noscroll
      
  end

  function A_Wheel_M0_TrBtns(rt, noscroll, v)

    if not mouse.shift and (MOUSE_over(obj.sections[5005])) then
      local mx = mouse.mx - obj.sections[5005].x
      
      local mr = math.min(lvar.trov_maxrows-1,lvar.dm_maxvistracks)
      if mouse.ctrl then
        p = math.max(F_limit(lvar.trbtns_offs - v,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-(mr)),0)
      else
        p = math.max(F_limit(lvar.trbtns_offs - v*mr,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-(mr)),0)
      end
      if p ~= lvar.trbtns_offs then
        lvar.trbtns_offs = p
        lupd.update_trbtns = true
      end
      gfx.mouse_wheel = 0
    
    elseif mouse.shift and (MOUSE_over(obj.sections[4999])) then
    
      p = F_limit(lvar.trbtns_size + v*4,80,160)
      if p ~= lvar.trbtns_size then
        lvar.trbtns_size = p
        Repos5005()
        SetSurfaceSize2(obj)
        lupd.update_trbtns = true
        lupd.update_surface = true
      end
      gfx.mouse_wheel = 0
    end
    
    return noscroll
  
  end

  function A_Wheel_M0_TrMix(rt, noscroll, v)

    if not mouse.shift and not lvar.analyzer.active and mouse.mx >= obj.sections[5005].x and mouse.mx <= obj.sections[5005].x + obj.sections[5005].w then
      local mx = mouse.mx - obj.sections[5005].x
      
      local mr = math.min(lvar.trov_maxrows-1,lvar.dm_maxvistracks)
      if mouse.ctrl then
        p = math.max(F_limit(lvar.trbtns_offs - v,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-(mr)),0)
      else
        p = math.max(F_limit(lvar.trbtns_offs - v*mr,0,#lvar.dm_trackbtns[lvar.dm_tbidx]-(mr)),0)
      end
      if p ~= lvar.trbtns_offs then
        lvar.trbtns_offs = p
        lupd.update_trbtns = true
      end
      gfx.mouse_wheel = 0
        
    elseif not mouse.shift and MOUSE_over(obj.sections[5027]) then
      
      local mx = mouse.mx - obj.sections[5005].x
      if MOUSE_over(obj.sections[5027]) and lvar.analyzer.active then
        if lvar.analyzer.pos == 0 then
          mx = mx - lvar.trbtns_size-20
          if mx > 0 and mx < obj.sections[5005].w - (lvar.trbtns_size+10)*2 - 10 then
            local tr = Analyzer_GetTrack()
            local idx = lvar.analyzer.pos
            if tr then
              local param = 7
              local val = reaper.TrackFX_GetParamNormalized(tr,idx,param)
              val = F_limit(val + v*0.02,0,1)
              reaper.TrackFX_SetParamNormalized(tr,idx,param,val)
              lupd.update_analyzerctls = true
              lupd.update_trmix = true
    
            end
          end
        end
        gfx.mouse_wheel = 0
      end
    
    elseif not mouse.shift and (lvar.trmix_sndpnl_show > 0 and MOUSE_over(obj.sections[5030])) then

      local tr = GetTrack(lvar.dynamicmode_trn)
      if tr then

        local scnt
        if lvar.trmix_sndpnl_show == 1 then
          scnt = reaper.GetTrackNumSends(tr, 0) + reaper.GetTrackNumSends(tr, 1)
        else
          scnt = reaper.GetTrackNumSends(tr, -1)
        end
        lvar.trmix_sndpnl_offs = math.max(math.min(lvar.trmix_sndpnl_offs - v,scnt-lvar.sndpnl_maxrows+1),0)
        lupd.update_trbtns = true
      end
      gfx.mouse_wheel = 0


    elseif (MOUSE_over(obj.sections[5043]) or (not (lvar.trmix_sndpnl_show > 0) and MOUSE_over(obj.sections[5044]))) then

      if mouse.shift then
        p = F_limit(lvar.trmixbtns_size + v*4,80,160)
        if p ~= lvar.trmixbtns_size then
          lvar.trmixbtns_size = p
          Repos5005()
          SetSurfaceSize2(obj)
          lupd.update_trbtns = true
          lupd.update_surface = true
        end
      else
        lvar.dm_btnpnl_page = F_limit(lvar.dm_btnpnl_page - v,0,15)
        lupd.update_trbtns = true
      end

      gfx.mouse_wheel = 0
    
    end
    
    return noscroll
  
  end
  
  function A_Wheel_M0_Snapshot(rt, noscroll, v)
    
    if snapshots and snapshots[tracks[track_select].strip] and
       snapshots[tracks[track_select].strip][page][sstype_select] then
      if sstype_select == 1 then
        ssoffset = F_limit(ssoffset - v, 0, #snapshots[tracks[track_select].strip][page][sstype_select]-1)
      elseif sstype_select > 1 then
        ssoffset = F_limit(ssoffset - v, 0, #snapshots[tracks[track_select].strip][page][sstype_select].snapshot-1)
      end
      lupd.update_snaps = true
    end
    gfx.mouse_wheel = 0
    
    return noscroll
  
  end

  function A_Wheel_M0_AddStripDialog(rt, noscroll, v)

    if lvar.fxdata then
      local fxdata = lvar.fxdata
      if MOUSE_over(obj.sections[4001]) then
        afxdialogS_offset = F_limit(afxdialogS_offset - v, 0, #fxdata-1)
      elseif MOUSE_over(obj.sections[4002]) then
        afxdialogT_offset = F_limit(afxdialogT_offset - v, 0, #fxdata.tfxi)
      end
      lupd.update_surface = true
    end
    gfx.mouse_wheel = 0
    
    return noscroll
  
  end

  function A_Wheel_M0_fSnapshot(rt, noscroll, v)

    if snapshots and snapshots[tracks[track_select].strip] and
       snapshots[tracks[track_select].strip][page][fsstype_select] then
      if fsstype_select == 1 then
        fssoffset = F_limit(fssoffset - v, 0, #snapshots[tracks[track_select].strip][page][fsstype_select]-1)
      elseif fsstype_select > 1 then
        fssoffset = F_limit(fssoffset - v, 0, #snapshots[tracks[track_select].strip][page][fsstype_select].snapshot-1)
      end
      lupd.update_fsnaps = true
    end
    gfx.mouse_wheel = 0
    
    return noscroll
  
  end
  
  function A_Wheel_M0_TemplateChooser(rt, noscroll, v)

    local p = F_limit(lvar.template_strips_offs - v,0,#lvar.template_strips)
    if p ~= lvar.template_strips_offs then
      lvar.template_strips_offs = p
      lupd.update_tchooser = true
    end
    gfx.mouse_wheel = 0

    return noscroll

  end
  
  function A_Wheel_M0_SampleManager(rt, noscroll, v)
  
    local xywh_sm = {x = obj.sections[1300].x+obj.sections[1302].x,
                  y = obj.sections[1300].y+obj.sections[1302].y,
                  w = obj.sections[1302].w,
                  h = obj.sections[1302].h}
    local xywh_sm2 = {x = obj.sections[1300].x+obj.sections[1304].x,
                  y = obj.sections[1300].y+obj.sections[1304].y,
                  w = obj.sections[1304].w,
                  h = obj.sections[1304].h}
  
    if MOUSE_over(xywh_sm2) then
      lvar.kb.offset = F_limit(lvar.kb.offset - v*20,0,lvar.kb.wkey_w*lvar.kb.wkeys - obj.sections[1304].w)
      lupd.update_samplemanager = true
      gfx.mouse_wheel = 0
    
    elseif MOUSE_over(xywh_sm) then
      local ctl = strips[tracks[track_select].strip][page].controls[rs5k_select]
      local rsdata
      if smshowfavs then
        rsdata = samplefavs
      else
        rsdata = ctl.rsdata
      end
      if ctl and SM_butt_cnt < #rsdata.samples then
        smlist_offset = F_limit(smlist_offset - v*3, 0, #rsdata.samples-SM_butt_cnt)
      else
        smlist_offset = 0
      end
      lupd.update_samplemanager = true
      gfx.mouse_wheel = 0
    end
    
    return noscroll
  
  end
  
  function A_Wheel_M0_ModAss(rt, noscroll, v)
  
    local butt_h = math.floor(butt_h*pnl_scale)+2
    local but_cy = math.max(math.floor(obj.sections[1127].h / butt_h),1)
    local cnt = #lvar.modass
    local mcnt = cnt % but_cy
    lvar.modass.offset = F_limit(lvar.modass.offset + (-v*but_cy),0,lvar.modass.count-(mcnt+1))
    gfx.mouse_wheel = 0
    lupd.update_surface = true    
  
    return noscroll
    
  end

  function A_Wheel_M0_Fullscreen1(rt, noscroll)

    if snap_edit_mode then
      noscroll = A_Run_SnapEdit(noscroll, rt)
    elseif macro_edit_mode then
      noscroll = A_Run_MacroEdit(noscroll, rt)
    elseif show_eqcontrol then
      noscroll = A_Run_EQControl(noscroll, rt)
    end

    return noscroll
    
  end
  
  function A_Wheel_M0_Fullscreen2(rt, noscroll)
  
    noscroll = A_Run_PinMatrix(noscroll, rt)
    
    return noscroll
    
  end
  
  function SK2Data_ReadSlots()
    local t = {}
    local tidx = {}
    local fcount = tonumber(reaper.GetExtState('SK2DATA_SLOTS', 'COUNT'))

    if tracks[track_select].strip and strips[tracks[track_select].strip] then
      local idx = {}
      local ctls = strips[tracks[track_select].strip][page].controls
      for c = 1, #ctls do
        if ctls[c].ctlcat == ctlcats.sk2ctl then
          if tonumber(ctls[c].param_info.paramidx) then
            idx[tonumber(ctls[c].param_info.paramidx)] = c
          end
        end
      end
      
      if fcount then
        for i = 1, fcount+1 do
          local pfx = string.format('%i',i-1)
          
          t[i-1] = {lmode = tonumber(reaper.GetExtState('SK2DATA_SLOTS', pfx..'_LMODE')) or -1, 
                    name = reaper.GetExtState('SK2DATA_SLOTS', pfx..'_NAME'),
                    map = reaper.GetExtState('SK2DATA_SLOTS', pfx..'_MAPTYPE') or ''}
          tidx[t[i-1].map..'|'..t[i-1].name] = i-1
          if idx[i-1] then
            ctls[idx[i-1]].param = t[i-1].lmode
            ctls[idx[i-1]].param_info.paramname = ' '
            ctls[idx[i-1]].param_info.paramstr = t[i-1].name
            ctls[idx[i-1]].dirty = true
            SetCtlDirty(idx[i-1])
          end
        
        end
      end
    end
    reaper.DeleteExtState('SK2DATA_SLOTS', 'DIRTY', true)
    return t, tidx
  end

  function SK2Data_ReadAssign()
    --local rt = reaper.time_precise()

    local t = {}
    local fcount = tonumber(reaper.GetExtState('SK2DATA_SLOTS', 'COUNT'))
    
    if tracks[track_select].strip and strips[tracks[track_select].strip] then
      local idx = {}

      local ctls = strips[tracks[track_select].strip][page].controls
      for c = 1, #ctls do
        if ctls[c].ctlcat == ctlcats.sk2ctl then
          ctls[c].val = 0
          if tonumber(ctls[c].param_info.paramidx) then
            idx[tonumber(ctls[c].param_info.paramidx)] = c
          end
        end
      end
      
      if fcount then
        for i = 1, fcount+1 do
          local pfx = string.format('%i',i-1)
          
          t[i-1] = {active = tonumber(reaper.GetExtState('SK2DATA_ASSIGN', pfx..'_ACTIVE')) or 0,
                    name = reaper.GetExtState('SK2DATA_ASSIGN', pfx..'_NAME') or '',
                    sscolor = reaper.GetExtState('SK2DATA_ASSIGN', pfx..'_SSCOLOR'),
                    btype = tonumber(reaper.GetExtState('SK2DATA_ASSIGN', pfx..'_BTYPE')) or 4}
          --DBG('z'..i..'  - '..tostring(t[i-1].active))
          if idx[i-1] then
            ctls[idx[i-1]].dval = ''
            ctls[idx[i-1]].ctlname_override = t[i-1].name
            ctls[idx[i-1]].dirty = true
            if t[i-1].active == 1 then
              ctls[idx[i-1]].alpha_override = nil
            else
              ctls[idx[i-1]].alpha_override = 0.2
            end
            SetCtlDirty(idx[i-1])
          end
          --reaper.DeleteExtState('SK2DATA_ASSIGN', pfx..'_FXSLOT', true)
        end
      end
      lupd.update_surface = true
      --really need this update gfx - but it slows a bit - problem with ww text not blanking area --maybe fixed?
    end
    reaper.SetExtState('SK2DATA_ASSIGN', 'DIRTY', 0, false)
    --DBG(reaper.time_precise()-rt)
    return t
  end
  
  function A_Run_Mode0(noscroll, rt)

    local contexts = contexts
    local mouse = mouse
    local lvar = lvar
    local lupd = lupd

    if mouse.context == nil and lvar.sk2lock then
      reaper.DeleteExtState('SK2DATA_ASSIGN', 'LOCK', true)
      --reaper.gmem_write(lvar.gm_fb.fadertouch+lvar.sk2lock, 0)
      lvar.sk2lock = nil
    end
    if tonumber(reaper.GetExtState('SK2DATA_SLOTS', 'DIRTY')) == 1 or not lvar.sk2data_slots then
      lvar.sk2data_slots, lvar.sk2data_slotsidx = SK2Data_ReadSlots()
    end
    if tonumber(reaper.GetExtState('SK2DATA_ASSIGN', 'DIRTY')) == 1  or not lvar.sk2data_assign then
      lvar.sk2data_assign = SK2Data_ReadAssign()
      UpdateControlValues3(nil, ctls_upd, ctls_orr)
    end
    
    --[[if lvar.sk2overlay_active == 1 then
      MonitorSK2Links()
    end]]
    if xPnl.HUD.visible and #lvar.paramhud > 0 then
      local del
      local ft = 1
      local cnt = #lvar.paramhud
      for i = 1, cnt do
        local ph = lvar.paramhud[i]
        if rt > ph.timeout then
          lvar.paramhud[i] = nil
          del = true
        elseif rt > ph.timeout - ft then
          lvar.paramhud[i].alpha = ((ph.timeout-rt)/ft)
        end
      end
      if del then
        local ncnt = 0
        local ntab = {}
        local ntab_idx = {}
        for i = 1, cnt do
          local ph = lvar.paramhud[i]
          if ph then
            ncnt = ncnt + 1
            ntab[ncnt] = ph
            local idxx = GetHUDIdx(ph.ctl)
            ntab_idx[idxx] = ncnt
          end
        end
        lvar.paramhud = ntab
        lvar.paramhud_idx = ntab_idx
        xPnl.HUD.updategui = true
      end
    end
    
    if lvar.livemode == 2 then

      if lvar.saveanalactive and lvar.trbtns_show and lvar.trmix_show then
        DM_ShowAnalyzer(true)
        lupd.update_trbtns = true
        lvar.saveanalactive = nil
      end

      if lvar.analyzer.active == true then
        --lvar.analyzer.anwin = reaper.JS_Window_Find(lvar.analyzer.title[1], true)

        --[[if lvar.analyzer_track_unmute_timer and reaper.time_precise() > lvar.analyzer_track_unmute_timer then
          lvar.analyzer_track_unmute_timer = nil
          local tr = Analyzer_GetTrack()
          if tr then
            reaper.SetMediaTrackInfo_Value(tr, 'B_MUTE', 0)
          end
        end]]

        local anwin = lvar.analyzer.anwin --reaper.JS_Window_Find(lvar.analyzer.title, true)
        local lbxwin = lvar.analyzer.lbxwin --reaper.JS_Window_Find('- LBX Stripper -', true)
        if anwin and lbxwin and reaper.ValidatePtr(lvar.analyzer.anwinplug[lvar.analyzer.pos+1], "HWND") and reaper.ValidatePtr(anwin, "HWND") then
          --DBG(reaper.JS_Window_GetTitle(reaper.JS_Window_GetParent(lvar.analyzer.anwinplug)))
          local style = reaper.JS_Window_GetLong(anwin, 'EXSTYLE')
          local focwin = reaper.JS_Window_GetForeground()
          --DBG(reaper.JS_Window_GetParent(focwin))
          local tm = 0x00000008
          if focwin == anwin then
            reaper.JS_Window_SetFocus(lbxwin)
          else
            --DBG(tostring(focwin)..'  '..tostring(lbxwin))
            if focwin == lbxwin or focwin == lvar.analyzer.anwinparent or reaper.JS_Window_GetParent(focwin) == lvar.analyzer.anwinparent then
              if style and (style & tm) ~= tm then
                --reaper.JS_Window_SetZOrder(anwin, 'TOPMOST', anwin)
                reaper.JS_Window_SetPosition(anwin,0,0,0,0,'TOPMOST','NOMOVE,NOSIZE,NOACTIVATE')
                --if lvar.oldfoc then
                --reaper.JS_Window_SetPosition(focwin,0,0,0,0,'NOTOPMOST','NOMOVE,NOSIZE,NOACTIVATE')
                --end
                --reaper.JS_Window_SetFocus(lbxwin)
                --DBG('top')
              end
            else
              if style and (style & tm) == tm then
                --reaper.JS_Window_SetZOrder(anwin, 'NOTOPMOST')
                --reaper.JS_Window_SetZOrder(anwin, 'INSERTAFTER', focwin)
                --reaper.JS_Window_SetPosition(focwin,0,0,0,0,'TOPMOST','NOMOVE,NOSIZE,NOACTIVATE')
                --lvar.oldfoc = focwin
                reaper.JS_Window_SetPosition(anwin,0,0,0,0,'NOTOPMOST,'..tostring(focwin),'NOMOVE,NOSIZE,NOACTIVATE')
                reaper.JS_Window_SetPosition(lbxwin,0,0,0,0,'BOTTOM','NOMOVE,NOSIZE,NOACTIVATE')
                --reaper.JS_Window_SetFocus(focwin)
                --DBG('notop')
              end
            end
          end

          local xywh = obj.sections[5046]
          local eh
          local h_off = 0
          if lvar.analyzer.pos == 0 then
            h_off = 15
          end
          if lvar.trmix_show then
            eh = xywh.h - h_off
          else
            eh = 0
          end
          if lvar.analyzer.type == 1 then
            local retval, sl, st, sr, sb = reaper.JS_Window_GetClientRect(lbxwin)
            local retval, l, t, r, b = reaper.JS_Window_GetClientRect(anwin)
            local retval, pl, pt, pr, pb = reaper.JS_Window_GetClientRect(lvar.analyzer.anwinplug[lvar.analyzer.pos+1])
            local ax = sl+xywh.x
            local ay = st+xywh.y + h_off
            if l ~= ax or t ~= ay or r-l ~= xywh.w or b-t ~= eh and (not lvar.mixerscroll_time or lvar.mixerscroll_open == false) then
              reaper.JS_Window_SetPosition(anwin, ax, ay, xywh.w, eh)
            end
            if pl ~= ax or pt ~= ay-25 or pr-pl ~= xywh.w or pb-pt ~= eh+25 then
              reaper.JS_Window_SetPosition(lvar.analyzer.anwinplug[lvar.analyzer.pos+1], ax, ay-25, xywh.w, eh+25) --, 'BOTTOM')
            end
          else

          end
        else
          if not anwin or not reaper.ValidatePtr(anwin, "HWND") then
            --start background script
            reaper.Main_OnCommand(reaper.NamedCommandLookup(lvar.analyzer.script),-1)
            lvar.analyzer.anwin = reaper.JS_Window_Find(lvar.analyzer.title[1], true)
            --DBG(lvar.analyzer.anwin)
          else
            lvar.analyzer.active = false
            lupd.update_trbtns = true
          end
        end
      end

      if lvar.dm_refresh_timer and rt > lvar.dm_refresh_timer then
        lvar.dm_refresh_timer = nil
        lupd.update_trbtns = true
      end

      --Auto trbtns
      if lvar.dm_tbidx == lvar.trbtns_autoidx then
        --lvar.dm_tbidx = lvar.trbtns_autoidx
        if lvar.dm_trackbtns[lvar.dm_tbidx] then
          --monitor
          local trcnt = reaper.CountTracks(0)
          if trcnt ~= lvar.otrackcount then
            DM_TrBtns_Auto()
            lvar.otrackcount = trcnt
          else
            local trmon = lvar.dm_trackmon
            --local t = reaper.time_precise()
            local rr = 100
            local trcnt = reaper.CountTracks(0)-1
            lvar.dm_trackmon_rrpos = lvar.dm_trackmon_rrpos or 0
            if lvar.dm_trackmon_rrpos > trcnt then
              lvar.dm_trackmon_rrpos = 0
            end
            for tt = 0, rr do
              local t = tt + lvar.dm_trackmon_rrpos
              
              if t <= trcnt then
                local tr = reaper.GetTrack(0, t)
                local vis = reaper.IsTrackVisible(tr, true)
                local guid = GetTrackGUID(tr)
                local _, name = reaper.GetTrackName(tr)
                if trmon[t].trn ~= t or 
                   trmon[t].guid ~= guid or
                   trmon[t].vis ~= vis then
                  DM_TrBtns_Auto()
                  lupd.update_trbtns = true
                  break
                elseif trmon[t].name ~= name then
                  trmon[t].name = name
                  lupd.update_trbtns = true
                end
              else
                break
              end
            end
            lvar.dm_trackmon_rrpos = lvar.dm_trackmon_rrpos + rr
            
            --DBG(reaper.time_precise()-t)
            
            --[[local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
            local cnt = math.min(#dm_trackbtns, lvar.trov_maxrows)
            if cnt > 0 then
              for tb2 = 1, cnt do
                local tb = tb2 + lvar.trbtns_offs
                if dm_trackbtns[tb] then
                  local tr = GetTrack(dm_trackbtns[tb].trn)
                  if GetTrackGUID(tr) ~= dm_trackbtns[tb].guid then
                    DM_TrBtns_Auto()
                    lupd.update_trbtns = true
                    break            
                  elseif reaper.GetTrackName(tr) ~= dm_trackbtns[tb].name then
                    dm_trackbtns[tb].name = reaper.GetTrackName(tr)
                    lupd.update_trbtns = true
                  end
                else
                  break
                end
              end
            end]]
          end
        else
          DM_TrBtns_Auto()
        end
      end

      if lvar.mixerscroll_time then

        local pos = math.max((lvar.mixerscroll_time-reaper.time_precise())/lvar.mst,0)
        --DBG(pos)
        local pos2 = pos
        if lvar.mixerscroll_open then
          pos2 = 1-pos
        end
        lvar.trmix_h = pos2*lvar.trmix_seth
        lvar.mixerscroll_y = obj.sections[4999].y - lvar.trmix_h
        lvar.mixerscroll_h = obj.sections[4999].y - lvar.mixerscroll_y

        --gfx.blit(825,1,0,0,0,obj.sections[5024].w,h,obj.sections[5024].x,y)
        lvar.trmix_show = true
        local r
        if pos == 0 then
          lvar.mixerscroll_time = nil
          lvar.trmix_h = lvar.trmix_seth
          lupd.update_trbtns = true
          --lupd.update_gfx = true
          local trh = 0
          if lvar.mixerscroll_open then
            lvar.trmix_show = true
            trh = lvar.trmix_h
          else
            lvar.trmix_show = false
          end
          r = MixMode_FindClosestRow(obj.sections[10].h + trh)
        end
        SetSurfaceSize2(obj)
        if pos == 0 then
          obj = PosTrBtns(obj)
          MixMode_Swipe_Pop(1, nil, r)
        end
        --DBG(obj.sections[10].h)

        --[[local mmov = 0
        if lvar.mmov_show then
          mmov = lvar.mmov_vsize
        end]]
        --Repos5001()
        if pos == 0 then
          --Repos5005()
        end

        --lupd.update_trbtns = true
        lupd.update_trbtns = true
        lupd.update_surface = true


      elseif lvar.trmix_show then
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        if dm_trackbtns then
          local cnt = math.min(#dm_trackbtns, lvar.trov_maxrows)
          if cnt > 0 then
  
            lvar.trmix_dirty = {}
  
            for tb2 = 1, cnt do
  
              local tb = tb2 + lvar.trbtns_offs
              if dm_trackbtns[tb] then
                local tr = GetTrack(dm_trackbtns[tb].trn)
                --[[if tr then
  
                end]]
                if tr then
  
                  local r, vol, pan = trctls_table[1].funcget(tr)
                  local phs = reaper.GetMediaTrackInfo_Value(tr, 'B_PHASE')
                  local rec = reaper.GetMediaTrackInfo_Value(tr, 'I_RECARM')
                  local fxb = reaper.GetMediaTrackInfo_Value(tr, 'I_FXEN')
                  local mas = reaper.GetMediaTrackInfo_Value(tr, 'B_MAINSEND')
                  if rec ~= dm_trackbtns[tb].recarm or
                     fxb ~= dm_trackbtns[tb].fxbyp or
                     phs ~= dm_trackbtns[tb].phase or
                     mas ~= dm_trackbtns[tb].master then
                    dm_trackbtns[tb].vol = vol
                    dm_trackbtns[tb].pan = pan
                    dm_trackbtns[tb].phase = phs
                    dm_trackbtns[tb].recarm = rec
                    dm_trackbtns[tb].fxbyp = fxb
                    dm_trackbtns[tb].master = mas
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = tb
                    lupd.update_trmix = true
                  elseif vol ~= dm_trackbtns[tb].vol or pan ~= dm_trackbtns[tb].pan then
                    dm_trackbtns[tb].vol = vol
                    dm_trackbtns[tb].pan = pan
                    lvar.trmix_dirty[#lvar.trmix_dirty+1] = tb
                    lupd.update_trmix2 = true
                  end
                end
              end
            end
          end
        end
        
        if lvar.trmix_sndpnl_show > 0 then
          local tr = GetTrack(lvar.dynamicmode_trn)
          if tr then
            --DBG(lvar.trmix_sndpnl_data)
            local trmix_sndpnl_data = lvar.trmix_sndpnl_data
            if trmix_sndpnl_data then
              local cnt = lvar.sndpnl_maxrows
              local scnt, funcVolPan, funcMute, funcName
              if lvar.trmix_sndpnl_show == 1 then
                scnt = reaper.GetTrackNumSends(tr, 0) + reaper.GetTrackNumSends(tr, 1)
                funcVolPan = reaper.GetTrackSendUIVolPan
                funcMute = reaper.GetTrackSendUIMute
                funcName = reaper.GetTrackSendName
              else
                scnt = reaper.GetTrackNumSends(tr, -1)
                funcVolPan = reaper.GetTrackReceiveUIVolPan
                funcMute = reaper.GetTrackReceiveUIMute
                funcName = reaper.GetTrackReceiveName
              end
              for tb2 = 0, cnt-1 do

                local tb = tb2 + lvar.trmix_sndpnl_offs
                if trmix_sndpnl_data[tb] and tb <= scnt-1 then
                  local r, t = funcName(tr, tb, '')
                  local r, vol, pan = funcVolPan(tr, tb)
                  local r, mute = funcMute(tr, tb)
                  if vol ~= trmix_sndpnl_data[tb].vol or
                     pan ~= trmix_sndpnl_data[tb].pan or
                     mute ~= trmix_sndpnl_data[tb].mute or
                     t ~= trmix_sndpnl_data[tb].name then
                    trmix_sndpnl_data[tb].vol = vol
                    trmix_sndpnl_data[tb].pan = pan
                    trmix_sndpnl_data[tb].mute = mute
                    trmix_sndpnl_data[tb].name = t

                    lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = tb
                    lupd.update_trmix = true
                  end

                elseif trmix_sndpnl_data[tb] and (trmix_sndpnl_data[tb].name or '') ~= '' then

                  trmix_sndpnl_data[tb].name = t
                  lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = tb
                  lupd.update_trmix = true
                end
              end
            end
          end
        end

        if #lvar.btnpnl_update > 0 then
          for idx = 1, #lvar.btnpnl_update do
            local uptab = lvar.btnpnl_update[idx]
            for i = 1, #uptab do
              local btntab = uptab[i]
              local commid = btntab.tab.commid
              local v
              if tonumber(commid) then
                v = reaper.GetToggleCommandStateEx(0, commid)
              else
                v = reaper.GetToggleCommandStateEx(0, reaper.NamedCommandLookup(commid))
              end
              if v ~= -1 and v ~= btntab.tab.val then
                btntab.tab.val = v
                GUI_DrawTrackBtnPanel_BtnUpdate(obj, gui, btntab.iidx, btntab.box, btntab.cols, btntab.rows, btntab.idx, btntab.dir, btntab.col, btntab.row)
                lupd.update_trmix = true
                if idx == 1 then
                  lvar.btnpnl_dirty = true
                else
                  lvar.btnpnl2_dirty = true
                end
              end
            end
          end
        end
      end

      local seltr = reaper.GetSelectedTrack2(0,0, true)
      if seltr and (lvar.dynamicmode_trn == nil or (seltr ~= GetTrack(math.max(lvar.dynamicmode_trn,-1)) and reaper.CountSelectedTracks2(0,true) < 2)) then

        DM_AddStrips()

      elseif not seltr and lvar.dynamicmode_trn then

        lvar.dynamicmode_trn = nil
        lvar.dynamicmode_guid = nil
        DM_AddStrips()

      elseif lvar.dynamicmode_trn then
        --DBG(lvar.dynamicmode_trn)
        local seltr = GetTrack(lvar.dynamicmode_trn)
        if seltr then
          local strip = tracks[track_select].strip
          local fxstr = ''
          local fxcnt = reaper.TrackFX_GetCount(seltr)
          if lvar.dm_refreshfx and strips[strip] then
  
            --local strip = tracks[track_select].strip
            local fxcnt = reaper.TrackFX_GetCount(seltr)
            strips[strip][page].fxcnt = fxcnt
  
            local fxguid = {}
  
            for fx = 0, fxcnt-1 do
              local guid = reaper.TrackFX_GetFXGUID(seltr,fx)
              --if guid ~= lvar.analyzer.guid then
                fxguid[#fxguid+1] = guid
              --end
            end
            strips[strip][page].fxstr = table.concat(fxguid,'')
            lvar.dm_refreshfx = nil
  
          elseif not lvar.dm_refresh then
            if strips[strip] then
              --DBG(#strips[strip][page].controls)
              --DBG(fxcnt..'  '..tostring(strips[strip][page].fxcnt))
              if fxcnt ~= strips[strip][page].fxcnt then
                lvar.dm_refresh = true
                if lvar.dm_autorefresh then
                  DM_RefreshPage()
                end
                lupd.update_surface = true
              else
                --DBG('gg')
                local fxguid = {}
                for fx = 0, fxcnt-1 do
                  local guid = reaper.TrackFX_GetFXGUID(seltr,fx)
                  --if guid ~= lvar.analyzer.guid then
                    fxguid[#fxguid+1] = guid
                  --end
                end
                fxstr = table.concat(fxguid,'')
                if fxstr ~= strips[strip][page].fxstr then
                  lvar.dm_refresh = true
                  if lvar.dm_autorefresh then
                    DM_RefreshPage()
                  end
                  lupd.update_surface = true
                end
              end
            end
          end
        end
      end

      if lvar.trbtns_show then
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        if dm_trackbtns then
          local cnt = math.min(--[[#dm_trackbtns,]] lvar.trov_maxrows-1, lvar.dm_maxvistracks)
          for i = 1, cnt do
            local x = i+lvar.trbtns_offs
            if dm_trackbtns[x] then
              local tr = GetTrack(dm_trackbtns[x].trn)
              if tr then
                local solo = reaper.GetMediaTrackInfo_Value(tr, 'I_SOLO')
                if solo ~= dm_trackbtns[x].solo then
                  dm_trackbtns[x].solo = solo
                  lupd.update_trbtns = true
                end
                local mute = reaper.GetMediaTrackInfo_Value(tr, 'B_MUTE')
                if mute ~= dm_trackbtns[x].mute then
                  dm_trackbtns[x].mute = mute
                  lupd.update_trbtns = true
                end
                local col = reaper.GetMediaTrackInfo_Value(tr, 'I_CUSTOMCOLOR')
                if col ~= dm_trackbtns[x].col then
                  dm_trackbtns[x].col = col
                  lupd.update_trbtns = true
                end              
              end
            end
          end
        end
      end

    end

    if lvar.TSM_active == true and mouse.context == nil then
      --local tt = reaper.time_precise()
      local smx, smy = reaper.GetMousePosition()
      if not lvar.TSM_StripperHwnd then
        lvar.TSM_StripperHwnd = reaper.JS_Window_Find('- LBX Stripper -',true)
      end
      if lvar.TSM_StripperHwnd then
        local retval, l, t, r, b = reaper.JS_Window_GetRect(lvar.TSM_StripperHwnd)
        --DBG(l..'  '..t..'  '..r..'  '..b..' mouse '..smx..'  '..smy)
        if smx >= l and smx <= r and smy >= t and smy <= b then
          if (mouse.LB and lvar.MOStripper ~= true) then
            lvar.TSM_MOver = true
          else
          --DBG('over')
            --lvar.TSM_Timer = 0
            lvar.MOStripper = true
          end
        else
          lvar.MOStripper = false
          lvar.TSM_LegalMP = {x = smx, y = smy}
          local hwnd = reaper.JS_Window_GetFocus()
          if hwnd and hwnd ~= lvar.TSM_StripperHwnd then
            lvar.TSM_FocusHwnd = hwnd
          end
        end
      end
      --DBG(reaper.time_precise()-tt)
    end

    if surface_offset.targetmixy or surface_offset.targetmixx then
      MixMode_Swiping()
    elseif lvar.popswipe then
      MixMode_Swiping_Pop()
    end
    if lvar.popalpha then
      local t = math.min((reaper.time_precise() - lvar.popalpha.st)/(lvar.popalpha.et-lvar.popalpha.st),1)
      if lvar.popalpha.showpop == true then
        lvar.popalpha.alpha = t*1
      else
        lvar.popalpha.alpha = 1-(t*1)
      end
      lupd.update_surface = true
      if t == 1 then
        lvar.popalpha = nil
      end
    end

    if striplayout_mt then
      striplayout_mp = 1-(((striplayout_mt-reaper.time_precise()))/striplayout_mtime)
      if striplayout_mp >= 1 then
        striplayout_mp = 1
        striplayout_mt = nil
      else
        striplayout_mp = macScale(4,striplayout_mp)
      end
      lupd.update_surface = true

    elseif stripgallery_swipemt then
      stripgallery_swipe.mp = 1-(((stripgallery_swipemt-reaper.time_precise()))/striplayout_mtime)
      if stripgallery_swipe.mp >= 1 then
        stripgallery_swipe.mp = 1
        stripgallery_swipemt = nil
        stlay_data.xpos = stripgallery_swipe.xend
        strips[tracks[track_select].strip][page].xpos = stripgallery_swipe.xend
        GUI_DrawCtlBitmap2()
      else
        stripgallery_swipe.mp = macScale(3,stripgallery_swipe.mp)
      end
      lupd.update_surface = true
    end

    if settings_touchFB == true and mouse.LB then
      touch_trigger = true
      DrawMD(gui, obj)
    end
    if (touch_trigger == true and not mouse.LB) then -- or (mididelay and reaper.time_precise() >= mididelay) then
      if mu_mmsg and (midi1st or mouse.LB) then
        SendMIDIMsg(mu_mmsg.midiout, mu_mmsg.val, true)
        midi1st = nil
      end

      if not mouse.LB then
        mu_mmsg = nil
        touch_trigger = false
        lupd.update_surface = true
        lvar.delayfunction.touch_timer = reaper.time_precise()+0.2
        mididelay = nil
      else
        mididelay = reaper.time_precise()+0.2
      end
    end

    --local guibmp, full_screen, lrn_mode
    --[[if gfx.mouse_wheel ~= 0 then

      full_screen = snap_edit_mode or macro_edit_mode or show_pinmatrix or show_eqcontrol         
      lrn_mode = snaplrn_mode or macro_lrn_mode
    
      local v = gfx.mouse_wheel/lvar.mousewheel_div
      gfx.dest = guibitmap
      gfx.x = mouse.mx
      gfx.y = mouse.my
      local r,g,b = gfx.getpixel()
      local rgb = (r*255) + ((g*255) << 8) + ((b*255) << 16)
      if not lvar.guibmp then
        RedrawGUIBitmap2()
      end
      guibmp = lvar.guibmp[lvar.guibmp.idx[rgb] ] 
      --DBG(rgb)       
      if guibmp then
        if guibmp.wheel0 --[ [and not full_screen] ] and not lrn_mode then
          noscroll = guibmp.wheel0(rt, noscroll, v)
        --elseif guibmp.wheel0_fs and full_screen then
        --  noscroll = guibmp.wheel0_fs(rt, noscroll, v)        
        else--if not full_screen then
          gfx.mouse_wheel = 0
        end
      end
          
    end]]

    local skip
    if insertstrip then

      A_Run_InsertStrip()
      skip = true

    --[[elseif show_eqcontrol == true then

      noscroll = A_Run_EQControl(noscroll, rt)
      skip = true

    elseif show_pinmatrix == true then

      noscroll = A_Run_PinMatrix(noscroll, rt)
      skip = true

    elseif macro_edit_mode == true and macro_lrn_mode == false then

      noscroll = A_Run_MacroEdit(noscroll, rt)
      skip = true]]

    --elseif snap_edit_mode == true and snaplrn_mode ~= true then

    --  noscroll = A_Run_SnapEdit(noscroll, rt)
    --  skip = true

    elseif lvar.show_templatechooser then

      noscroll = true
      if MOUSE_click(obj.sections[5050]) then
        A_Run_TemplateChooser(noscroll, rt)
      elseif MOUSE_click(obj.sections[10]) then
        if lvar.show_templatechooser then
          lvar.show_templatechooser = nil
          RedrawGUIBitmap()
        end
        lvar.dm_editmode_data_tmp = nil
        lupd.update_surface = true
        
      elseif MOUSE_over(obj.sections[5050]) then
        local my = mouse.my-obj.sections[5050].y-5
        local butt_h = butt_h*pnl_scale
        local p = math.floor((my-butt_h) / lvar.tempchooser.th)

        if p ~= lvar.tempchooser.sel then
          lvar.tempchooser.sel = p
          lupd.update_tchooser = true
        end
      else
        if lvar.tempchooser.sel then
          lvar.tempchooser.sel = nil
          lupd.update_tchooser = true
        end
      end
      skip = true
      --navigate = false
    end

    if mouse.context == nil then
      if show_modass == true and (MOUSE_click(obj.sections[1125]) or MOUSE_click_RB(obj.sections[1125])) then
  
        noscroll = A_Run_ModAss(noscroll, rt)
        skip = true
        
      elseif lvar.show_addstripdialog and (MOUSE_click(obj.sections[4000]) or MOUSE_click_RB(obj.sections[4000])) then
  
        noscroll = A_RunAddStrip(noscroll, rt)
        skip = true
        
      elseif morph_puw and settings_showmorphpop and (MOUSE_click(morph_puw) or MOUSE_click_RB(morph_puw)) then
  
        noscroll, mouse.context = A_Run_MorphPU(noscroll, rt)
        skip = true
      elseif lvar.sk2_buttonhold then

        local ctl = lvar.sk2_buttonhold.ctl
        if ctl then
          local i = tonumber(ctl.param_info.paramidx)
          if i then
            reaper.gmem_write(lvar.gm_fb.fader_val +i,0)
          end
        end
        lvar.sk2_buttonhold = nil
        
      elseif lvar.sk2drag then
        --drop sk2 ctl drag
        if MOUSE_over(obj.sections[10]) then
          local strip = tracks[track_select].strip
          local c = GetControlAtXY(strip, page, mouse.mx, mouse.my)
          if c then
            
            local tgt_i = tonumber(strips[strip][page].controls[c].param_info.paramidx)
            local tgt_s = tonumber(lvar.sk2drag.ctl.param_info.paramidx)
            if tgt_i and tgt_s and tgt_i ~= tgt_s then
              --DBG('ts '..tgt_s..'  '..tgt_i)
              reaper.SetExtState(REMSCRIPT, 'REMOTE_CTL', 'SK2_ASSIGN_SWAP', false)
              reaper.SetExtState(REMSCRIPT, 'REMOTE_DATA', string.format('%i',tgt_s)..','..string.format('%i',tgt_i), false)
            end
          end
        end
        lvar.sk2drag = nil
        --lupd.update_gfx = true
        --SK2Data_ReadAssign()
      end
    end
    
    -----------------
    local guibmp, full_screen, lrn_mode
    if not mouse.context and not skip then
      if MC() or gfx.mouse_wheel ~= 0 then
        --if not guibmp then

          full_screen = snap_edit_mode or macro_edit_mode or show_pinmatrix or show_eqcontrol         
          lrn_mode = snaplrn_mode or macro_lrn_mode
          
          gfx.dest = guibitmap
          gfx.x = mouse.mx
          gfx.y = mouse.my
          local r,g,b = gfx.getpixel()
          local rgb = math.floor(((r*255) + ((g*255) << 8) + ((b*255) << 16))+0.5)
          if not lvar.guibmp then
            RedrawGUIBitmap2()
          end
          if not full_screen and rgb >= lvar.xPnlOffset and rgb <= lvar.xPnlOffset + #xPnlIdx then
            
            local o = rgb - lvar.xPnlOffset
            local xpnl = xPnlIdx[o]
            if xpnl and xpnl.visible then
              if gfx.mouse_wheel == 0 and xpnl.onclick then
                xpnl:onclick(mouse.mx-xpnl.x,mouse.my-xpnl.y)
                noscroll = true
              elseif gfx.mouse_wheel ~= 0 and xpnl.onwheel then
                xpnl:onwheel(mouse.mx-xpnl.x,mouse.my-xpnl.y)
                noscroll = true
              end
            end
          else
            local guibmp = lvar.guibmp[lvar.guibmp.idx[rgb]]
            --DBG('rgb '..rgb)          
            --DBG('fidx '..tostring(lvar.guibmp.idx[rgb]))
            if guibmp then
              if gfx.mouse_wheel ~= 0 then
                local v = mousewheel_val()
                if guibmp.wheel0 and not lrn_mode then
                  noscroll = guibmp.wheel0(rt, noscroll, v)
                else
                  gfx.mouse_wheel = 0 
                end
              else
                if guibmp.func0 --[[and not full_screen]] and not lrn_mode then
                  noscroll = guibmp.func0(rt, noscroll)
                elseif guibmp.func0_lrn and lrn_mode then
                  noscroll = guibmp.func0_lrn(rt, noscroll)
                end
              end
            end
          end
        --[[else
          if guibmp.func0 and not lrn_mode then
            noscroll = guibmp.func0(rt, noscroll)
          elseif guibmp.func0_lrn and lrn_mode then
            noscroll = guibmp.func0_lrn(rt, noscroll)
          end
        end]]
      end
    end

    if macro_edit_mode then
      A_Run_MacroEdit2(noscroll, rt)
    elseif show_eqcontrol then
      A_Run_EQControl2(rt, noscroll)
    end

    if not mouse.context then



    if --[[mouse.context == nil and]] snaplrn_mode == true then

      A_Run_SnapshotsLearn()

    elseif macro_lrn_mode == true then

      A_Run_MacroLearn()

    elseif show_striplayout == true then

      noscroll = A_Run_StripLayout(noscroll, rt)

    elseif lvar.stripctlbox.idx and not mouse.ctrl then

      noscroll, xclicked = A_Run_AltStripFuncs(noscroll, rt)

      if not xclicked and mouse.LB and not mouse.last_LB then
        local strip = tracks[track_select].strip
        local c = GetControlAtXY(strip, page, mouse.mx, mouse.my)
        if c then
          local ctl = strips[strip][page].controls[c]
          if mouse.shift then
            ctl.ctllock = not (ctl.ctllock or false)
            SetCtlDirty(lvar.stripctlbox.ctl.ctl)
            lupd.update_ctls = true
          else
            if ctl.ctlcat == ctlcats.fxparam or
               ctl.ctlcat == ctlcats.fxoffline then
              OpenFXGUI(ctl)
            end
          end
        end
        noscroll = true
      end

    elseif mouse.alt and mouse.shift and not mouse.altlatch and not mouse.LB and not mouse.RB and lvar.livemode == 0 and MOUSE_over(obj.sections[10]) then

      CreateStripCB()

    --elseif lvar.livemode == 2 and lvar.trbtns_show and lvar.trmix_show and (MOUSE_click(obj.sections[5024]) or MOUSE_click_RB(obj.sections[5024])) then

      
    --elseif lvar.analyzer.active and MOUSE_click(obj.sections[5027]) then

    elseif lvar.livemode == 2 and mode == 0 and MOUSE_click(obj.sections[5000]) then

      c = nil
      noscroll = true
      --[[gfx.dest = -1
      f_Get_SSV(gui.color.red)]]
      --gfx.rect(obj.sections[5000].x,obj.sections[5000].y,obj.sections[5000].w,obj.sections[5000].h,0)
      HighlightBox(obj.sections[5000].x,obj.sections[5000].y,obj.sections[5000].w,obj.sections[5000].h, gui.color.red, lvar.btnflashtime)

      --GUI_DrawButton(gui,'REFRESH',obj.sections[5000],-2,gui.color.white,true,nil,nil,4)
      --lupd = GUI_draw(obj, gui)
      --gfx.update()
      DM_RefreshPage()

    --elseif --[[mouse.context == nil and]] lvar.livemode == 2 and lvar.trbtns_show and (MOUSE_click(obj.sections[4999]) or MOUSE_click_RB(obj.sections[4999])) then

      
    elseif lvar.trbtn_solo then

      lvar.trbtn_solo = nil
      local tr = GetTrack(lvar.dynamicmode_trn)
      if tr then
        local solo = reaper.GetMediaTrackInfo_Value(tr, 'I_SOLO')
        solo = 2-solo
        reaper.CSurf_OnSoloChangeEx(tr, solo, true)
      end
      
    elseif track_select == LBX_GTRACK and MOUSE_click(obj.sections[5007]) then
      if not lvar.delayfunction.trbtnsglobalset_delay then
        SetGlobalPage()
      end

    --elseif --[[mouse.context == nil and]] (MOUSE_click(obj.sections[10]) or MOUSE_click_RB(obj.sections[10]) or gfx.mouse_wheel ~= 0) then

      

    end

    end --not mouse.context
    --------------------

    if not (mouse.alt and mouse.shift) and lvar.stripctlbox.idx then
      lvar.stripctlbox = {}
      lupd.update_surface = true
    end

    if mouse.context then

      if mouse.context == contexts.mixer_vol then

        local tb = lvar.mixvol_drag.tb
        local nv = 1-F_limit(
                     (mouse.my + lvar.mixvol_drag.offs - (obj.sections[5024].y + obj.sections[5026].y)) / obj.sections[5026].h,0,1)
        local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][tb]
        if nv ~= lvar.mixvol_drag.vol then
          lvar.mixvol_drag.vol = nv
          if dm_trackbtn then
           local tr = GetTrack(dm_trackbtn.trn)
            if tr then
              if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                if tr then
                  dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                end
              end
            end
            if tr then
              local val = DenormalizeValue(trctls_table[1].min,trctls_table[1].max,ctlScale(lvar.trmix_vscale,nv))
              trctls_table[1].func(tr, val, false)
              lvar.trmix_dirty[#lvar.trmix_dirty+1] = tb
              lupd.update_trmix2 = true
            end
          end
        end

      elseif mouse.context == contexts.mixer_pan then

        local tb = lvar.mixpan_drag.tb
        local nv = F_limit( lvar.mixpan_drag.pan -
                     ((mouse.my - lvar.mixpan_drag.offs - (obj.sections[5024].y + obj.sections[5028].y)) / 120),0,1)
        local dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][tb]
        if nv ~= lvar.mixpan_drag.pan then
          --lvar.mixpan_drag.pan = nv
          if dm_trackbtn then
           local tr = GetTrack(dm_trackbtn.trn)
            if tr then
              if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                if tr then
                  dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                end
              end
            end
            if tr then
              local val = DenormalizeValue(trctls_table[2].min,trctls_table[2].max,nv)
              trctls_table[2].func(tr, val, false)
              lvar.trmix_dirty[#lvar.trmix_dirty+1] = tb
              lupd.update_trmix2 = true
            end
          end
        end

      elseif mouse.context == contexts.sndpnl_vol then
        local tb = lvar.mixvol_drag.tb
        local nv = 1-F_limit(
                     (mouse.my + lvar.mixvol_drag.offs - (obj.sections[5024].y + obj.sections[5031].y)) / obj.sections[5031].h,0,1)
        local trmix_sndpnl_data = lvar.trmix_sndpnl_data[tb]
        if nv ~= lvar.mixvol_drag.vol then
          lvar.mixvol_drag.vol = nv
          if trmix_sndpnl_data then
           local tr = GetTrack(lvar.dynamicmode_trn)
            --[[if tr then
              if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                if tr then
                  dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                end
              end
            end]]
            if tr then
              local val = DenormalizeValue(trsends_mmtable[1].min,trsends_mmtable[1].max,ctlScale(lvar.trmix_vscale,nv))
              --trsends_mmtable[1].func(tr, tb, val, false)
              if lvar.trmix_sndpnl_show == 1 then
                reaper.CSurf_OnSendVolumeChange(tr, tb, val, false)
              else
                reaper.CSurf_OnRecvVolumeChange(tr, tb, val, false)
              end
              --reaper.SetTrackSendUIVol(tr, tb, val, 0)
              lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = tb
              lupd.update_trmix = true
            end
          end
        end

      elseif mouse.context == contexts.sndpnl_pan then

        local tb = lvar.mixpan_drag.tb
        local nv = F_limit( lvar.mixpan_drag.pan -
                     ((mouse.my - lvar.mixpan_drag.offs - (obj.sections[5024].y + obj.sections[5032].y)) / 120),0,1)
        local trmix_sndpnl_data = lvar.trmix_sndpnl_data[tb]
        if nv ~= lvar.mixpan_drag.pan then
          --lvar.mixpan_drag.pan = nv
          if trmix_sndpnl_data then
           local tr = GetTrack(lvar.dynamicmode_trn)
            --[[if tr then
              if GetTrackGUID(tr) ~= dm_trackbtn.guid and dm_trackbtn.trn ~= -1 then
                tr = reaper.BR_GetMediaTrackByGUID(0, dm_trackbtn.guid)
                if tr then
                  dm_trackbtn.trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
                end
              end
            end]]
            if tr then
              local val = DenormalizeValue(trsends_mmtable[2].min,trsends_mmtable[2].max,nv)
              if lvar.trmix_sndpnl_show == 1 then
                reaper.CSurf_OnSendPanChange(tr, tb, val, false)
              else
                reaper.CSurf_OnRecvPanChange(tr, tb, val, false)
              end
              --reaper.SetTrackSendUIPan(tr, tb, val, 0)
              lvar.trmix_sndpnl_dirty[#lvar.trmix_sndpnl_dirty+1] = tb
              lupd.update_trmix = true
            end
          end
        end

      elseif mouse.context == contexts.sndpnl_drag then

        lvar.trmix_snddrag.x = mouse.mx
        lvar.trmix_snddrag.y = mouse.my

        local mx, my = mouse.mx - obj.sections[5005].x, mouse.my - obj.sections[5005].y
        if mx > 0 and my > 0 and mx < obj.sections[5005].w-lvar.trbtns_size-10 and my < obj.sections[5005].h then
          local idx = math.floor(mx / (lvar.trbtns_size+10))+1
          dm_trackbtn = lvar.dm_trackbtns[lvar.dm_tbidx][idx+lvar.trbtns_offs]
          --DBG(tostring(dm_trackbtn)..'  '..idx..'  '..lvar.trbtns_offs..'   '..tostring(lvar.trmix_snddrag.target))
          if dm_trackbtn and lvar.trmix_snddrag.target ~= idx+lvar.trbtns_offs then
            local tr = GetTrack(dm_trackbtn.trn)
            if tr then
              lvar.trmix_snddrag.target = idx+lvar.trbtns_offs
              local r, n = reaper.GetTrackName(tr,'')
              lvar.trmix_snddrag.tgtname = n
            end
          else
            --lvar.trmix_snddrag.tgtname = ''
            --lvar.trmix_snddrag.target = nil
          end
        else
          lvar.trmix_snddrag.tgtname = ''
          lvar.trmix_snddrag.target = nil
        end

      elseif mouse.context == contexts.dmtrprm_swipe then
      
        local x = math.floor((mouse.mx - obj.sections[5005].x)/(obj.sections[5004].w+10))+1
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        local cnt = math.min(--[[(#dm_trackbtns+1),]] lvar.trov_maxrows, lvar.dm_maxvistracks+1)
        local x = F_limit(x,1,cnt-1)
        if x ~= lvar.dmtrprm_swipe.lastx then
          lvar.dmtrprm_swipe.delay = reaper.time_precise()+0.05
        end
        lvar.dmtrprm_swipe.lastx = x
        
        if rt > lvar.dmtrprm_swipe.delay then
          lvar.dmtrprm_swipe.minx = math.min(lvar.dmtrprm_swipe.minx or math.huge,x,lvar.dmtrprm_swipe.x)
          lvar.dmtrprm_swipe.maxx = math.max(lvar.dmtrprm_swipe.maxx or -1,x,lvar.dmtrprm_swipe.x)
        
          local snum, enum
          if x > lvar.dmtrprm_swipe.x then
            snum = lvar.dmtrprm_swipe.x
            enum = x
          else
            snum = x
            enum = lvar.dmtrprm_swipe.x
          end
          reaper.PreventUIRefresh(1)
          for xx = lvar.dmtrprm_swipe.minx, lvar.dmtrprm_swipe.maxx do
            local x = xx + lvar.trbtns_offs
            if dm_trackbtns[x] then
            
              local tr = GetTrack(dm_trackbtns[x].trn)
              if tr then
                if xx >= snum and xx <= enum then
                  if dm_trackbtns[x].trn == -1 and (lvar.dmtrprm_swipe.param == 'B_MUTE' or lvar.dmtrprm_swipe.param == 'I_SOLO') then
                  else
                    if reaper.GetMediaTrackInfo_Value(tr, lvar.dmtrprm_swipe.param) ~= lvar.dmtrprm_swipe.val then
                      reaper.SetMediaTrackInfo_Value(tr,lvar.dmtrprm_swipe.param,lvar.dmtrprm_swipe.val)
                      lvar.trmix_dirty[#lvar.trmix_dirty+1] = x
                      lupd.update_trmix = true
                    end
                  end
                else
                  if dm_trackbtns[x].trn == -1 and (lvar.dmtrprm_swipe.param == 'B_MUTE' or lvar.dmtrprm_swipe.param == 'I_SOLO') then
                  else
                    if reaper.GetMediaTrackInfo_Value(tr, lvar.dmtrprm_swipe.param) == lvar.dmtrprm_swipe.val then
                      reaper.SetMediaTrackInfo_Value(tr,lvar.dmtrprm_swipe.param,lvar.dmtrprm_swipe.otherval)
                      lvar.trmix_dirty[#lvar.trmix_dirty+1] = x
                      lupd.update_trmix = true
                    end              
                  end
                end
              end
            end
          end
          reaper.PreventUIRefresh(-1)
        end
          
      
      elseif mouse.context == contexts.dm_selecttracks then
      
        reaper.PreventUIRefresh(1)
        
        local x = math.floor((mouse.mx - obj.sections[5005].x)/(obj.sections[5004].w+10))+1
        local dm_trackbtns = lvar.dm_trackbtns[lvar.dm_tbidx]
        local cnt = math.min(--[[(#dm_trackbtns+1),]] lvar.trov_maxrows, lvar.dm_maxvistracks+1)
        local x = F_limit(x,1,cnt-1)
        if lvar.trbtn_solo and x ~= lvar.dmsl.x then
          lvar.trbtn_solo = nil
        end
        if x ~= lvar.dmsl.lastx then
          lvar.dmsl.delay = reaper.time_precise()+0.05
        end
        lvar.dmsl.lastx = x
        if rt > lvar.dmsl.delay then
          local snum, enum
          lvar.dmsl.minx = math.min(lvar.dmsl.minx or math.huge,x,lvar.dmsl.x)
          lvar.dmsl.maxx = math.max(lvar.dmsl.maxx or -1,x,lvar.dmsl.x)
          if x > lvar.dmsl.x then
            snum = lvar.dmsl.x
            enum = x
          else
            snum = x
            enum = lvar.dmsl.x
          end
          for xx = lvar.dmsl.minx, lvar.dmsl.maxx do
            local x = xx + lvar.trbtns_offs
            if dm_trackbtns[x] then
            
              local tr = GetTrack(dm_trackbtns[x].trn)
              if tr then
                --DBG(x..'  '..snum..'  '..enum..'  '..lvar.dmsl.minx..'  '..lvar.dmsl.maxx)
                if xx >= snum and xx <= enum then
                  if not reaper.IsTrackSelected(tr) then
                    reaper.SetMediaTrackInfo_Value(tr,'I_SELECTED',1)
                    lupd.update_trbtns = true
                  end
                else
                  if reaper.IsTrackSelected(tr) then
                    reaper.SetMediaTrackInfo_Value(tr,'I_SELECTED',0)
                    lupd.update_trbtns = true
                  end                
                end
              end
            end
          end
        end
        reaper.PreventUIRefresh(-1)
        
      elseif mouse.context == contexts.resize_mixer then

        local dy = lvar.mixresize.my-mouse.my

        local offs = 0
        if show_lfoedit and settings_moddock then
          offs = obj.sections[1100].h
        end
        if show_stripbrowser and settings_sbdock and lvar.stripbrowser.dockpos == 1 then
          offs = offs + obj.sections[1350].h
        end
        local max = gfx1.main_h - (lvar.trbtns_size+10) - offs - topbarheight

        lvar.trmix_h = math.min(math.max(lvar.mixresize.oh + dy,lvar.trmix_minh),max)
        lvar.trmix_seth = math.max(lvar.trmix_h,lvar.trmix_minh)
        if lvar.trmix_h ~= lvar.mixresize.oh2 then
          lvar.mixresize.oh2 = lvar.trmix_h
          SetSurfaceSize2(obj)
          obj = PosTrBtns(obj)

          --lupd.update_trbtns = true
          lupd.update_mixer = true
          lupd.update_surface = true
        end

      elseif mouse.context == contexts.mixer_drag then

        local dx = lvar.mdrag.mx-mouse.mx
        if dx ~= lvar.mdrag.odx then
          lvar.mdrag.odx = dx
          lvar.trmix_panelsz = lvar.mdrag.osz - (dx*lvar.mdrag.dir)
          obj = PosTrBtns(obj)

          lupd.update_trbtns = true
          lupd.update_surface = true
                  
        end
        
      elseif mouse.context == contexts.analyzerctl then

        local nv = F_limit(lvar.draganalyzercontrol.val - ((mouse.my - lvar.draganalyzercontrol.my)/lvar.draganalyzercontrol.sens),0,1)

        if nv ~= lvar.draganalyzercontrol.ov then
          lvar.draganalyzercontrol.ov = nv
          local param = lvar.draganalyzercontrol.param
          local idx = lvar.analyzer.pos
          reaper.TrackFX_SetParamNormalized(lvar.draganalyzercontrol.tr,idx,param,nv)
          lupd.update_analyzerctls = true
          lupd.update_trmix = true

        end

      elseif mouse.context == contexts.draglasso then
        if math.abs(lasso.l - mouse.mx) > 10 or math.abs(lasso.t - mouse.my) > 10 then
          lasso.r = mouse.mx
          lasso.b = mouse.my

          Lasso_Select(false)
          lupd.update_surface = true
        end

      elseif mouse.context == contexts.sliderctlxy then

        local val = MOUSE_slider_S_alt(ctlxywh,mouse.slideoff,mouse.slideoffh)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]

          if ctl then
            if oms ~= mouse.shift then
              oms = mouse.shift
              ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
              mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
              mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
              if lvar.hidecursordrag == true then
                mouse.oy = mouse.smy
                mouse.ox = mouse.smx
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            else
              if mouse.shift then
                local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
                if mult == 0 then mult = settings_defknobsens.fine end
                if ctl.ctltype ~= 11 then
                  val = ctlpos + ((0-val)*2)*mult
                else
                  val = ctlpos - ((0-val)*2)*mult
                end
              else
                local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
                if mult == 0 then mult = settings_defknobsens.norm end
                if ctl.ctltype ~= 11 then
                  val = ctlpos + (0-val)*mult
                else
                  val = ctlpos - (0-val)*mult
                end
              end
              if val < 0 then val = 0 end
              if val > 1 then val = 1 end
              local val2 = ctlScale(ctl.scalemode, val)
              if val2 ~= octlval or ctl.ctltype == 12 then
                ctl.oval = ctl.val
                ctl.val = val2
                A_SetParam(strip,page,trackfxparam_select,ctl)
                SetCtlDirty(trackfxparam_select)
                octlval = val2
                lupd.update_ctls = true

                if lvar.hidecursordrag == true then
                  if lvar.hidecursor then
                    reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                    lvar.hidecursor = nil
                  end
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                  ctlpos = val
                end
              else
                if lvar.hidecursordrag == true then
                  if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                    reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                    lvar.hidecursor = nil
                  end
                  ctlpos = val
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                end
              end
            end
          end
        end

      elseif mouse.context == contexts.sliderctl then

        local val = MOUSE_slider_S(ctlxywh,mouse.slideoff)

        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]

          if ctl then
            if oms ~= mouse.shift then
              oms = mouse.shift
              ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
              mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
              if lvar.hidecursordrag == true then
                mouse.oy = mouse.smy
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            else
              if mouse.shift then
                local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
                if mult == 0 then mult = settings_defknobsens.fine end
                if ctl.ctltype ~= 11 then
                  val = ctlpos + ((0.5-val)*2)*mult
                else
                  val = ctlpos - ((0.5-val)*2)*mult
                end
              else
                local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
                if mult == 0 then mult = settings_defknobsens.norm end
                if ctl.ctltype ~= 11 then
                  val = ctlpos + (0.5-val)*mult
                else
                  val = ctlpos - (0.5-val)*mult
                end
              end
              if val < 0 then val = 0 end
              if val > 1 then val = 1 end
              local val2 = ctlScale(ctl.scalemode, val)
              if val2 ~= octlval or ctl.ctltype == 12 then
                ctl.oval = ctl.val
                ctl.val = val2
                A_SetParam(strip,page,trackfxparam_select,ctl)
                SetCtlDirty(trackfxparam_select)
                octlval = val2
                lupd.update_ctls = true
                if lvar.hidecursordrag == true then
                  if lvar.hidecursor then
                    reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                    lvar.hidecursor = nil
                  end
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                  ctlpos = val
                end
              else
                if lvar.hidecursordrag == true then
                  if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                    reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                    lvar.hidecursor = nil
                  end
                  ctlpos = val
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                end
              end
            end
          end
        end

      elseif mouse.context == contexts.sliderctl_h then
        local val = MOUSE_slider_S_horiz(ctlxywh,mouse.slideoff)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]

          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
            mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
            if lvar.hidecursordrag == true then
              mouse.ox = mouse.smx
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              if ctl.ctltype ~= 11 then
                val = ctlpos - ((0.5-val)*2)*mult
              else
                val = ctlpos + ((0.5-val)*2)*mult
              end
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              if ctl.ctltype ~= 11 then
                val = ctlpos - (0.5-val)*mult
              else
                val = ctlpos + (0.5-val)*mult
              end
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            local val2 = ctlScale(ctl.scalemode, val)
            if val2 ~= octlval or ctl.ctltype == 12 then
              ctl.oval = ctl.val
              ctl.val = val2
              A_SetParam(strip,page,trackfxparam_select,ctl)
              SetCtlDirty(trackfxparam_select)
              --ctl.dirty = true
              octlval = val2
              lupd.update_ctls = true
              if lvar.hidecursordrag == true then
                if lvar.hidecursor then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                ctlpos = val
              end
            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = val
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.sliderctl_t2 then

        local i = trackfxparam_select

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[trackfxparam_select]
        local scale = ctl.scale
        local ctly = ctlxywh.y

        local h = (ctl.hsc* lvar.zoom - ((slidt2.knbsz)*scale))

        local ci
        local my = mouse.my
        if lvar.livemode == 0 then
          if stripgallery_view > 0 then
            _, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
          end
          my = F_limit(my-ctly-slidt2.offs-math.floor((((slidt2.knbsz/lvar.zoom)*scale)/2)* lvar.zoom),0,h)

        else
          local xx, yy = TranslateMixCtlPos(i, slidt2.swid)
          my = F_limit(my - yy -slidt2.offs -math.floor((((slidt2.knbsz)*scale)/2)),0,h)
        end

        local v = 1-(my/h)
        v = ctlScale(ctl.scalemode, v)
        if v ~= octlval or ctl.ctltype == 12 then
          ctl.oval = ctl.val
          ctl.val = v
          A_SetParam(strip,page,trackfxparam_select,ctl)
          SetCtlDirty(trackfxparam_select)
          octlval = v
          lupd.update_ctls = true
        end

      elseif mouse.context == contexts.sliderctl_h_t2 then

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[trackfxparam_select]
        local scale = ctl.scale

        local w = ctlxywh.w-(slidt2.knbsz*scale)

        local ci
        local mx = mouse.mx
        if stripgallery_view > 0 then
          mx, _, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
        end

        mx = F_limit(mx-ctlxywh.x-slidt2.offs-math.floor((slidt2.knbsz*scale)/2),0,w)
        local v = (mx/w)
        v = ctlScale(ctl.scalemode, v)
        if v ~= octlval or ctl.ctltype == 12 then
          ctl.oval = ctl.val
          ctl.val = v
          A_SetParam(strip,page,trackfxparam_select,ctl)
          SetCtlDirty(trackfxparam_select)
          octlval = v
          lupd.update_ctls = true
        end

      elseif mouse.context == contexts.macsliderctl_t2 then

        local tfxp_s = trackfxparam_select
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[tfxp_s]
        local scale = ctl.scale

        local h = ctlxywh.h-(slidt2.knbsz*scale)

        local ci
        local my = mouse.my
        if stripgallery_view > 0 then
          _, my, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
        end

        my = F_limit(my-ctlxywh.y-slidt2.offs-math.floor((slidt2.knbsz*scale)/2),0,h)
        local v = 1-(my/h)
        v = ctlScale(ctl.scalemode, v)
        if v ~= octlval or ctl.ctltype == 12 then
          ctl.oval = ctl.val
          ctl.val = v
          A_SetParam(strip,page,tfxp_s,ctl)
          SetCtlDirty(tfxp_s)
          octlval = v
          lupd.update_ctls = true
          trackfxparam_select = tfxp_s
        end

      elseif mouse.context == contexts.macsliderctl_h_t2 then

        local tfxp_s = trackfxparam_select
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[tfxp_s]
        local scale = ctl.scale

        local w = ctlxywh.w-(slidt2.knbsz*scale)

        local ci
        local mx = mouse.mx
        if stripgallery_view > 0 then
          mx, _, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
        end

        mx = F_limit(mx-ctlxywh.x-slidt2.offs-math.floor((slidt2.knbsz*scale)/2),0,w)
        local v = (mx/w)
        v = ctlScale(ctl.scalemode, v)
        if v ~= octlval or ctl.ctltype == 12 then
          ctl.oval = ctl.val
          ctl.val = v
          A_SetParam(strip,page,tfxp_s,ctl)
          SetCtlDirty(tfxp_s)
          octlval = v
          lupd.update_ctls = true
          trackfxparam_select = tfxp_s
        end

      elseif mouse.context == contexts.macctlxy then

        local tfxp_s = trackfxparam_select
        local val = MOUSE_slider_S_alt(ctlxywh,mouse.slideoff,mouse.slideoffh)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[tfxp_s]

          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
            mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
            mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
            if lvar.hidecursordrag == true then
              mouse.ox = mouse.smx
              mouse.oy = mouse.smy
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end

          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              if ctl.ctltype ~= 11 then
                val = ctlpos + ((0-val)*2)*mult
              else
                val = ctlpos - ((0-val)*2)*mult
              end
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              if ctl.ctltype ~= 11 then
                val = ctlpos + (0-val)*mult
              else
                val = ctlpos - (0-val)*mult
              end
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            local val2 = ctlScale(ctl.scalemode, val)
            if val2 ~= octlval or ctl.ctltype == 12 then
              ctl.diff = val2 - ctl.val
              ctl.oval = ctl.val
              ctl.val = val2
              SetMacro(strip, page, tfxp_s, nil, lvar.magnetic_active)
              --ctl.dirty = true
              SetCtlDirty(tfxp_s)
              octlval = val2
              lupd.update_ctls = true

              trackfxparam_select = tfxp_s

              if lvar.hidecursordrag == true then
                if lvar.hidecursor then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                ctlpos = val
              end
            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = val
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.macctl then

        local tfxp_s = trackfxparam_select
        local val = MOUSE_slider_S(ctlxywh,mouse.slideoff)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[tfxp_s]

          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
            mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
            if lvar.hidecursordrag == true then
              mouse.oy = mouse.smy
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              if ctl.ctltype ~= 11 then
                val = ctlpos + ((0.5-val)*2)*mult
              else
                val = ctlpos - ((0.5-val)*2)*mult
              end
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              if ctl.ctltype ~= 11 then
                val = ctlpos + (0.5-val)*mult
              else
                val = ctlpos - (0.5-val)*mult
              end
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            local val2 = ctlScale(ctl.scalemode, val)
            if val2 ~= octlval or ctl.ctltype == 12 then
              ctl.diff = val2 - ctl.val
              ctl.oval = ctl.val
              ctl.val = val2
              --DBG('pp')
              SetMacro(strip, page, tfxp_s, nil, lvar.magnetic_active)
              --ctl.dirty = true
              SetCtlDirty(tfxp_s)
              octlval = val2
              lupd.update_ctls = true

              trackfxparam_select = tfxp_s

              if lvar.hidecursordrag == true then
                if lvar.hidecursor then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                ctlpos = val
              end
            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = val
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.macctl_h then

        local tfxp_s = trackfxparam_select
        local val = MOUSE_slider_S_horiz(ctlxywh,mouse.slideoff)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[tfxp_s]

          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = ctlScaleInv(ctl.scalemode, ctl.val)
            mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
            if lvar.hidecursordrag == true then
              mouse.ox = mouse.smx
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end

          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              if ctl.ctltype ~= 11 then
                val = ctlpos - ((0.5-val)*2)*mult
              else
                val = ctlpos + ((0.5-val)*2)*mult
              end
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              if ctl.ctltype ~= 11 then
                val = ctlpos - (0.5-val)*mult
              else
                val = ctlpos + (0.5-val)*mult
              end
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            local val2 = ctlScale(ctl.scalemode, val)
            if val2 ~= octlval or ctl.ctltype == 12 then
              ctl.diff = val2 - ctl.val
              ctl.oval = ctl.val
              ctl.val = val2
              SetMacro(strip, page, tfxp_s, nil, lvar.magnetic_active)
              --ctl.dirty = true
              SetCtlDirty(tfxp_s)
              octlval = val2
              lupd.update_ctls = true

              trackfxparam_select = tfxp_s

              if lvar.hidecursordrag == true then
                if lvar.hidecursor then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                ctlpos = val
              end
            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = val
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.dragcyclexy then
        local val = MOUSE_slider_S_alt(ctlxywh,mouse.slideoff,mouse.slideoffh)
        if val ~= nil then
          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
            mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
            mouse.slideoffh = ctlxywh.x+ctlxywh.w/2 - mouse.smx
            if lvar.hidecursordrag == true then
              mouse.ox = mouse.smx
              mouse.oy = mouse.smy
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              val = ctlpos + ((0-val)*2)*mult
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              val = ctlpos + (0-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            if val ~= octlval then
              local pos = F_limit(round(val*ctl.cycledata.statecnt),1,
                                  ctl.cycledata.statecnt)
              if pos ~= ctl.cycledata.pos then
                ctl.cycledata.pos = pos
                ctl.oval = ctl.val
                ctl.val = ctl.cycledata[pos].val
                A_SetParam(strip,page,trackfxparam_select,ctl)
                ctl.dirty = true
                SetCtlDirty(trackfxparam_select)

                if lvar.hidecursordrag == true then
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                  ctlpos = normalize(0, ctl.cycledata.statecnt,
                                 ctl.cycledata.pos)
                end
              end
              if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                lvar.hidecursor = nil
              end
              octlval = val
              lupd.update_ctls = true

            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.dragcycle then
        local val = MOUSE_slider_S(ctlxywh,mouse.slideoff)
        if val ~= nil then
          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
            mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.smy
            if lvar.hidecursordrag == true then
              mouse.oy = mouse.smy
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              val = ctlpos + ((0.5-val)*2)*mult
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              val = ctlpos + (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            if val ~= octlval then
              local pos = F_limit(round(val*ctl.cycledata.statecnt),1,
                                  ctl.cycledata.statecnt)
              if pos ~= ctl.cycledata.pos then
                ctl.cycledata.pos = pos
                ctl.oval = ctl.val
                ctl.val = ctl.cycledata[pos].val
                A_SetParam(strip,page,trackfxparam_select,ctl)
                ctl.dirty = true
                SetCtlDirty(trackfxparam_select)

                if lvar.hidecursordrag == true then
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                  ctlpos = normalize(0, ctl.cycledata.statecnt,
                                 ctl.cycledata.pos)
                end
              end
              if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                lvar.hidecursor = nil
              end
              octlval = val
              lupd.update_ctls = true

            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end

      elseif mouse.context == contexts.dragcycle_h then
        local val = MOUSE_slider_S_horiz(ctlxywh,mouse.slideoff)
        if val ~= nil then
          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[trackfxparam_select]
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
            mouse.slideoff = ctlxywh.x+ctlxywh.w/2 - mouse.smx
            if lvar.hidecursordrag == true then
              mouse.ox = mouse.smx
              reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
            end
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              val = ctlpos - ((0.5-val)*2)*mult
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              val = ctlpos - (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            if val ~= octlval then
              local pos = F_limit(round(val*ctl.cycledata.statecnt),1,
                                  ctl.cycledata.statecnt)
              if pos ~= ctl.cycledata.pos then
                ctl.cycledata.pos = pos
                ctl.oval = ctl.val
                ctl.val = ctl.cycledata[pos].val
                A_SetParam(strip,page,trackfxparam_select,ctl)
                ctl.dirty = true
                SetCtlDirty(trackfxparam_select)

                if lvar.hidecursordrag == true then
                  reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
                  ctlpos = normalize(0, ctl.cycledata.statecnt,
                                 ctl.cycledata.pos)
                end
              end
              if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                lvar.hidecursor = nil
              end
              octlval = val
              lupd.update_ctls = true

            else
              if lvar.hidecursordrag == true then
                if lvar.hidecursor and (mouse.smx ~= mouse.ox or mouse.smy ~= mouse.oy) then
                  reaper.JS_Mouse_SetCursor(lvar.cursor_invisible)
                  lvar.hidecursor = nil
                end
                ctlpos = normalize(0, ctl.cycledata.statecnt,
                               ctl.cycledata.pos)
                reaper.JS_Mouse_SetPosition(mouse.ox, mouse.oy)
              end
            end
          end
        end
      elseif mouse.context == contexts.hold then
      elseif mouse.context == contexts.mmov_dragh then
        Process_MMOV()
      elseif mouse.context == contexts.mmov_dragv then
        Process_MMOV()
      elseif mouse.context == contexts.switchdrag_ext2 then

        if mouse.RB then
          switchers[lvar.dragswitcher.selected].dragging = nil
          lvar.dragswitcher = nil
          oswid = nil
          mouse.context = nil
          lupd.update_surface = true
        else

          local strip = tracks[track_select].strip
          if lvar.livemode >= 1 and (lvar.showpop == true and not lvar.popout_autoarrange) and strips[strip][page].popidx and lvar.dragswitcher and strips[strip][page].popidx[lvar.dragswitcher.selected] then

            local x = mouse.mx-lvar.dragswitcher.offx
            local y = mouse.my-lvar.dragswitcher.offy
            local switchid = lvar.dragswitcher.selected
            local idx = strips[strip][page].popidx[switchid]
            strips[strip][page].pop[idx].x = x
            strips[strip][page].pop[idx].y = y
            --lupd.update_surface = true

          else
            if not mouse.ctrl then
              Surface_EdgeDrag()

              if mouse.mx ~= lvar.omx or mouse.my ~= lvar.omy then
                lvar.omx, lvar.omy = mouse.mx, mouse.my
                local strip = tracks[track_select].strip
                local ctls = strips[strip][page].controls

                if lvar.livemode >= 1 and (lvar.showpop == true and not lvar.popout_autoarrange) and strips[strip][page].popidx and not strips[strip][page].popidx[ctls[i].switcherid] then
                  lvar.dragswitcher.showpop = lvar.showpop
                  ShowPop(false)
                end

                local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)
                --DBG(stripidx..'  '..stripid)
                local stripids = lvar.dragswitcher.stripids
                local locs = lvar.dragswitcher.locs

                --DBG('stripids '..#stripids)
                --DBG('locs '..#locs)

                local dst_switchid
                if stripid and stripids then
                  dst_switchid = Switcher_GetTopLevelSwitcher(stripids[stripid])
                  if dst_switchid and switchers[lvar.dragswitcher.selected].extendid ~= switchers[dst_switchid].extendid then
                    dst_switchid = nil
                  end
                elseif c then
                  local ctl = ctls[c]
                  if ctl.ctlcat == ctlcats.switcher then
                    if switchers[ctl.switcherid].switchmode == 1 and
                       switchers[ctl.switcherid].extendmode == true and
                       switchers[ctl.switcherid].extendid == switchers[lvar.dragswitcher.selected].extendid then
                       dst_switchid = ctl.switcherid
                    end
                  end
                end
                local ob = lvar.dragswitcher.before

                local oldpos, newpos
                if dst_switchid then
                  oldpos = switchers[lvar.dragswitcher.selected].extendpos
                  newpos = switchers[dst_switchid].extendpos
                end

                if dst_switchid then
                  if lvar.showpop and lvar.popout_autoarrange then
                    local o10x = obj.sections[10].x
                    local pop = strips[strip][page].pop
                    --need to loop as not all strips may be visible
                    local pidx = strips[strip][page].popidx[dst_switchid]
                    local popp = pop[pidx]
                    
                    --[[for i = 1, #pop do
                      if dst_switchid == pop[i].swid then
                        popp = pop[i]
                        pidx = i
                        break
                      end
                    end]]
                    if popp then
                      local swdata = lvar.stripdim.swdata
                      local xp = mouse.mx - popp.x - o10x
                      local w = (swdata[dst_switchid].r - swdata[dst_switchid].l)*lvar.zoom
                      if oldpos == newpos - 1 then
                        lvar.dragswitcher.before = nil
                      elseif oldpos == newpos + 1 then
                        lvar.dragswitcher.before = true
                      elseif xp < w/2 then
                        lvar.dragswitcher.before = true
                      else
                        lvar.dragswitcher.before = nil
                      end
                      
                      --[[if popp.row then
                        lvar.popswipe_redrawforce = true
                        if popp.row ~= lvar.prsr and reaper.time_precise() > (lvar.popswipe_delay or 0) then
                          lvar.prsr = popp.row
                          lvar.popswipe_delay = reaper.time_precise() + 0.2
                          MixMode_Swipe_Pop(nil, false, popp.row)
                        end
                      end]]
                    end
                    lvar.dragswitcher.pop = popp
                    lvar.dragswitcher.popidx = pidx
                    
                  elseif oldpos == newpos - 1 then
                    lvar.dragswitcher.before = nil
                  elseif oldpos == newpos + 1 then
                    lvar.dragswitcher.before = true
                  else
                    if lvar.livemode == 0 then
                      local yy = mouse.my + surface_offset.y*lvar.zoom - obj.sections[10].y
                      if yy < locs[dst_switchid].t*lvar.zoom + math.floor(((locs[dst_switchid].b - locs[dst_switchid].t))/2)*lvar.zoom then
                        lvar.dragswitcher.before = true
                      else
                        lvar.dragswitcher.before = nil
                      end
                    else
                      --[[if lvar.showpop and lvar.popout_autoarrange then
                        local o10x = obj.sections[10].x
                        local pop = strips[strip][page].pop
                        local popp 
                        --need to loop as not all strips may be visible
                        local pidx
                        for i = 1, #pop do
                          if dst_switchid == pop[i].swid then
                            popp = pop[i]
                            pidx = i
                            break
                          end
                        end
                        if popp then
                          local swdata = lvar.stripdim.swdata
                          local xp = mouse.mx - popp.x - o10x
                          local w = (swdata[dst_switchid].r - swdata[dst_switchid].l)*lvar.zoom
                          if xp < w/2 then
                            lvar.dragswitcher.before = true
                          else
                            lvar.dragswitcher.before = nil
                          end
                        end
                        lvar.dragswitcher.pop = popp
                        lvar.dragswitcher.popidx = pidx
                      else]]
                        if lvar.mixmodedir == 0 then
                          local yy = mouse.my
                          local spos = lvar.spos[dst_switchid]
                          if spos then
                            if yy < spos.y + math.floor((spos.h*lvar.zoom)/2) then
                              lvar.dragswitcher.before = true
                            else
                              lvar.dragswitcher.before = nil
                            end
                          end
                        else
                          local xx = mouse.mx
                          local spos = lvar.spos[dst_switchid]
                          if spos then
                            if xx < spos.x + math.floor((spos.w*lvar.zoom)/2) then
                              lvar.dragswitcher.before = true
                            else
                              lvar.dragswitcher.before = nil
                            end
                          end
                        end
                      --end
                    end
                  end
                end
                lvar.dragswitcher.target = dst_switchid
                if dst_switchid and (dst_switchid ~= oswid or lvar.dragswitcher.before ~= ob) then
                  oswid = dst_switchid
                  --lvar.dragswitcher.target = dst_switchid
                  --lupd.update_surface = true
                end
                if lvar.dragswitcher.target ~= osdt or lvar.dragswitcher.before ~= osdb then
                  lupd.update_surface = true
                  osdt = lvar.dragswitcher.target
                  osdb = lvar.dragswitcher.before
                end
              end
              
              if lvar.livemode == 2 and lvar.showpop and lvar.popout_autoarrange then
                if gfx.mouse_wheel ~= 0 then
                  if gfx.mouse_wheel < 0 then
                    MixMode_Swipe_Pop(0, false)
                  else
                    MixMode_Swipe_Pop(1, false)
                  end
                  gfx.mouse_wheel = 0
                end
              end
              
              --DBG(lupd.update_surface)
            elseif mouse.ctrl then
              ShowPop(true, true)

            end
          end
          if lvar.livemode == 0 then
            lupd.update_surface = true
          end

        end

      elseif mouse.context == contexts.switchdrag_ext then

        Surface_EdgeDrag()
        lvar.switchdrag.x = mouse.mx
        lvar.switchdrag.y = mouse.my
        lvar.switchdrag.targetc = nil
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local ctl = GetControlAtXY(strip, page, mouse.mx, mouse.my)
        if ctl then
          if ctls[ctl].ctlcat == ctlcats.switcher and ctls[ctl].switcherid then
            local switchid = ctls[ctl].switcherid
            local extid = switchers[lvar.switchdrag.switchid].extendid
            if switchers[switchid].switchmode == 1 and switchers[switchid].extendmode == true and switchers[switchid].extendid == extid then
              lvar.switchdrag.targetc = ctl
              lvar.switchdrag.before = nil
              if lvar.mixmodedir == 0 then
                if mouse.my + surface_offset.y - obj.sections[10].y < ctls[ctl].y + math.floor(ctls[ctl].ctl_info.cellh/2) then
                  lvar.switchdrag.before = true
                end
              else
                if mouse.mx + surface_offset.x - obj.sections[10].x < ctls[ctl].x + math.floor(ctls[ctl].w/2) then
                  lvar.switchdrag.before = true
                end
              end
            end
          end
        end

        lupd.update_surface = true

      elseif mouse.context == contexts.dragxy then

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[xy_select]
        local xy_x, xy_y = 0,0
        if lvar.livemode == 0 then
          xy_x = F_limit((mouse.mx - obj.sections[10].x-12*lvar.zoom - ctl.x*lvar.zoom + surface_offset.x*lvar.zoom) / ((ctl.w-24)*lvar.zoom),0,1)
          xy_y = F_limit((mouse.my - obj.sections[10].y-12*lvar.zoom - ctl.y*lvar.zoom + surface_offset.y*lvar.zoom) / ((ctl.ctl_info.cellh - 58)*lvar.zoom),0,1)
        else
          --local _, _, swid = TranslateMixPos(mouse.mx, mouse.my, xy_select)
          local swid = lvar.xyswid
          local xx, yy = TranslateMixCtlPos(xy_select, swid)
          xy_x = F_limit((mouse.mx - xx-12*lvar.zoom) / ((ctl.w-24)*lvar.zoom),0,1)
          xy_y = F_limit((mouse.my - yy-12*lvar.zoom) / ((ctl.ctl_info.cellh - 58)*lvar.zoom),0,1)
          --DBG(xx..'  '..yy)
        end
        if xy_x ~= ctl.xydata.x or
           xy_y ~= ctl.xydata.y then
          ctl.xydata.x = xy_x
          ctl.xydata.y = xy_y
          XY_Set(strip,page,ctl.param,xy_select)
          ctl.dirty = true
          lupd.update_ctls = true
        end

      elseif mouse.context == contexts.morph_puw_slider then

        local i = puwdata.i
        if morph_data[i] then
          local val = MOUSE_slider_horiz2(puwdata,puwdata.x+puwdata.xoff)
          if val ~= nil then
            local p
            if oms ~= mouse.shift then
              oms = mouse.shift
              puwdata.pos = morph_data[i].p
              puwdata.xoff = mouse.mx-morph_puw.x
              p = morph_data[i].p
            else
              if mouse.shift then
                val = val * 0.1
              end

              if morph_data[i].dir ~= 1 then
                p = F_limit(puwdata.pos + val,0,1)
              else
                p = 1-F_limit(puwdata.pos + val,0,1)
              end
            end
            if p ~= morph_data[i].op then
              morph_data[i].p = p
              morph_data[i].paused = morph_data[i].morph_time-(morph_data[i].morph_time*(morph_data[i].p)) -- morph_data[i].paused

              morph_data[i].manual = true
              lupd.update_snapmorph = true
              morph_data[i].op = morph_data[i].p
            end
          end
        end

      elseif mouse.context == contexts.infoctl_click then

        --if lvar.infoclick.active == true or reaper.time_precise() > lvar.infoclick.t + 0.3 then
        if lvar.infoclick.active == true or mouse.my < lvar.infoclick.my-5 or mouse.my > lvar.infoclick.my+5 then
          lvar.infoclick.active = true
          if mouse.my ~= lvar.omy or mouse.mx ~= lvar.omx then
            --lupd.update_surface = true
            lvar.omx = mouse.mx
            lvar.omy = mouse.my
          end
        end
      
      elseif mouse.context == contexts.lv_dragstrip then
      
        noscroll, xclicked = A_Run_AltStripFuncs(noscroll, rt)
        
        --[[if lvar.stripctlbox.overstrip then 
        
          local gs = settings_gridsize
          if mouse.shift then
            gs = 1
          end
          local dx, dy = (mouse.mx - cbdragstrip.mx), (mouse.my - cbdragstrip.my)
          cbdragstrip.nx = F_limit(math.floor(((cbdragstrip.x + dx)/gs)*gs) - surface_offset.x*lvar.zoom,0 - surface_offset.x,surface_size.w - surface_offset.x -lvar.stripctlbox.overstrip.w)
          cbdragstrip.ny = F_limit(math.floor(((cbdragstrip.y + dy)/gs)*gs) - surface_offset.y*lvar.zoom,0 - surface_offset.y,surface_size.h - surface_offset.y -lvar.stripctlbox.overstrip.h)

          if cbdragstrip.nx ~= cbdragstrip.ox or cbdragstrip.ny ~= cbdragstrip.oy then
            local nx = F_limit(math.floor(((cbdragstrip.x + dx/lvar.zoom)/gs)*gs) - surface_offset.x,0 - surface_offset.x,surface_size.w - surface_offset.x -lvar.stripctlbox.overstrip.w)
            local ny = F_limit(math.floor(((cbdragstrip.y + dy/lvar.zoom)/gs)*gs) - surface_offset.y,0 - surface_offset.y,surface_size.h - surface_offset.y -lvar.stripctlbox.overstrip.h)
            cbdragstrip.nx2 = nx
            cbdragstrip.ny2 = ny
            cbdragstrip.dx = nx +surface_offset.x - cbdragstrip.x
            cbdragstrip.dy = ny +surface_offset.y - cbdragstrip.y

            lupd.update_surface = true

            cbdragstrip.ox = cbdragstrip.nx
            cbdragstrip.oy = cbdragstrip.ny
          end
        else
        
        end]]

      elseif mouse.context == contexts.sk2_dragassign then
        if mouse.my ~= lvar.omy or mouse.mx ~= lvar.omx then
          
          
          lupd.update_surface = true
          lvar.omx = mouse.mx
          lvar.omy = mouse.my
        end
      elseif mouse.context == contexts.scrollmatrix then
      
        if mouse.mx ~= omx or mouse.my ~= omy or matrixoff.timer < reaper.time_precise() then
          if matrixoff.timer < reaper.time_precise() then
            if matrixoff.x ~= 0 or matrixoff.y ~= 0 then
              matrixoff.update = true
              pinmatrix_scrollpos.x = pinmatrix_scrollpos.x + matrixoff.x
              if settings_lockpinmatrix == false then
                pinmatrix_scrollpos.y = pinmatrix_scrollpos.y + matrixoff.y
              end
              matrixoff.x = 0
              matrixoff.y = 0
              matrixoff.dx = mouse.mx
              matrixoff.dy = mouse.my

              lupd.update_surface = true
            end
            matrixoff.timer = reaper.time_precise() + 0.2
          else
            matrixoff.update = false
            matrixoff.x = (mouse.mx - matrixoff.dx)
            if settings_lockpinmatrix == false then
              matrixoff.y = (mouse.my - matrixoff.dy)
            end
            lupd.update_surface = true
            omx, omy = mouse.mx, mouse.my
          end
        end
      end
    --end

    else --mouse.context == nil

      if lvar.mixvol_drag then
        if lvar.mixvol_drag.snd then
          reaper.Undo_BeginBlock2(0)
          reaper.Undo_EndBlock2(0, "Track send change",-1)
        end
        lvar.mixvol_drag = nil

      elseif lvar.trmix_snddrag then

        if lvar.trmix_snddrag.target then

          local srctrn = lvar.dynamicmode_trn
          local dsttrn = lvar.dm_trackbtns[lvar.dm_tbidx][lvar.trmix_snddrag.target].trn
          if srctrn and dsttrn then
            if lvar.trmix_sndpnl_show == 2 then
              srctrn, dsttrn = dsttrn, srctrn
            end
            local str = GetTrack(srctrn)
            local dtr = GetTrack(dsttrn)

            reaper.CreateTrackSend(str, dtr)

          end

        end

        lvar.trmix_snddrag = nil

      elseif lvar.mmov_drag then
        lvar.mmov_drag = nil
        GUI_DrawCtlBitmap_Mix()

      elseif lvar.infoclick then

        local i = lvar.infoclick.src

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local ctl = ctls[i]
        if ctl then
          local c, stripidx, stripid = GetControlAtXY(strip, page, lvar.omx--[[mouse.mx]], lvar.omy--[[mouse.my]])
          if c == i then
            if tonumber(ctl.param) == 2 then
              if not mouse.shift and not mouse.ctrl then
                local fxnum = tonumber(ctl.param_info.paramidx) + (lvar.slotoffset[ctl.tracknum or tracks[track_select].tracknum] or 0)
                if fxnum then
                  local trn = ctl.tracknum or tracks[track_select].tracknum
                  local track = GetTrack(trn)
                  local fxcnt = reaper.TrackFX_GetCount(track)
                  if fxnum < fxcnt then
                    if lvar.infoclick.active == false then

                      --close all fxchain windows
                      if ctl.infoctl and ctl.infoctl.closefx then
                        reaper.Main_OnCommand(reaper.NamedCommandLookup('_S&M_WNCLS4'), -1)
                        if reaper.TrackFX_GetOpen(track, fxnum) then
                          ctl.val = 1
                        else
                          ctl.val = 0
                        end
                      end

                      local centre
                      if ctl.val ~= 0 then
                        reaper.TrackFX_Show(track, fxnum, 0)
                        if not reaper.TrackFX_GetOpen(track, fxnum) then
                          --reopen
                          if ctl.infoctl and ctl.infoctl.closefx then
                            reaper.Main_OnCommand(reaper.NamedCommandLookup('_S&M_WNCLS3'),1)
                          end

                          reaper.TrackFX_Show(track, fxnum, 3)
                          centre = true
                        else
                          --close
                          reaper.TrackFX_Show(track, fxnum, 2)
                        end
                      else

                        --centre fx window ####
                        if ctl.infoctl and ctl.infoctl.closefx then
                          reaper.Main_OnCommand(reaper.NamedCommandLookup('_S&M_WNCLS3'),1)
                        end

                        reaper.TrackFX_Show(track, fxnum, 3)
                        centre = true
                      end

                      if centre then
                        if ctl.infoctl and ctl.infoctl.positionfx and reaper.JS_Window_Find then

                          local ret, fxname = reaper.TrackFX_GetFXName(track, fxnum, '')
                          local trname = reaper.GetTrackState(track)

                          local ttrn = reaper.GetMediaTrackInfo_Value(track, 'IP_TRACKNUMBER')
                          local tmpname
                          if ttrn == -1 then
                            tmpname = fxname..' - Master Track'
                          else
                            tmpname = fxname..' - Track '..string.format('%i',ttrn)
                            if trname ~= '' then
                              tmpname = tmpname .. ' "'..trname..'"'
                            end
                          end

                          local fd = reaper.GetMediaTrackInfo_Value(track, 'I_FOLDERDEPTH')
                          if fd == 1 then
                            tmpname = tmpname .. ' (folder)'
                          end
                          local bp = reaper.GetMediaTrackInfo_Value(track, 'I_FXEN')
                          if bp == 0 then
                            tmpname = tmpname .. ' [BYPASSED]'
                          end

                          if fxcnt > 1 then
                            tmpname = tmpname .. ' [' .. string.format('%i',fxnum+1) .. '/' .. string.format('%i',fxcnt) .. ']'
                          end

                          local hwnd = reaper.JS_Window_Find(tmpname,false)
                          if hwnd then
                            local ret, w, h = reaper.JS_Window_GetClientSize(hwnd)
                            if ret then
                              local x = lvar.fxpos.l + math.floor((lvar.fxpos.w/2)-(w/2))
                              local y = lvar.fxpos.t + math.floor((lvar.fxpos.h/2)-(h/2))
                              reaper.JS_Window_Move(hwnd,x,y) --may need to adjust for macos
                            end
                          end
                        end
                      end

                    end
                  else
                    --set track
                    local tr = reaper.GetSelectedTrack2(0,0,true)
                    reaper.SetOnlyTrackSelected(track)
                    reaper.Main_OnCommand(40914,0)
                    reaper.Main_OnCommand(40271,0)
                    if tr then
                      reaper.SetOnlyTrackSelected(tr)
                    end
                  end
                end
              elseif mouse.shift then
                local fxnum = tonumber(ctl.param_info.paramidx) + (lvar.slotoffset[ctl.tracknum or tracks[track_select].tracknum] or 0)
                if fxnum then
                  ToggleFXBypass2(ctl.tracknum or tracks[track_select].tracknum, fxnum)
                  --SetCtlDirty(i)
                end
              end
            end

          else
            local tctl = ctls[c]
            if tctl then
              local toffs = lvar.slotoffset[ctl.tracknum or tracks[track_select].tracknum] or 0
              local soffs = lvar.infoclick.soffs

              local ttrn = tctl.tracknum or tracks[track_select].tracknum
              local strn = ctl.tracknum or tracks[track_select].tracknum
              if tctl.ctlcat == ctlcats.infoctl and tctl.param == 2 and ttrn == strn then
                local sfxnum = ctl.param_info.paramidx + soffs
                local tfxnum = tctl.param_info.paramidx + toffs
                local tr = GetTrack(strn)
                if tr then
                  local fxcnt = reaper.TrackFX_GetCount(tr)
                  if sfxnum < fxcnt and tfxnum < fxcnt then
                    MoveFXChunkX(sfxnum+1,tfxnum+1,strn)
                  end
                end
              end
            end
          end
        end
        lvar.infoclick = nil
        lupd.update_surface = true

      elseif holdbtn ~= nil and not lvar.dm_editmode_data then
        local strip = tracks[track_select].strip
        if tracks[track_select] and strips[strip] and strips[strip][page].controls[holdbtn] then
          local ctl = strips[strip][page].controls[holdbtn]
          ctl.oval = ctl.val
          ctl.val = 0
          ctl.dirty = true
          SetCtlDirty(holdbtn)

          if ctl.ctltype == 7 or
             ctl.ctltype == 8 then
            A_SetParam(strip, page, holdbtn, ctl)
          end
        end
        holdbtn = nil
        lupd.update_ctls = true

      elseif macctlactive then

        local strip = tracks[track_select].strip
        local mac = strips[strip][page].controls[macctlactive].macroctl
        strips[strip][page].controls[macctlactive].diff = nil
        if mac then
          for m = 1, #mac do
            --strips[strip][page].controls[mac[m].ctl].mval = nil
          end
        end
        macctlactive = nil

      elseif lvar.magnetic_active then

        local i = lvar.magnetic_active
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[i]
        ctl.oval = ctl.val
        ctl.val = ctl.defval
        A_SetParam(strip,page,i,ctl)
        SetCtlDirty(i)
        lupd.update_ctls = true
        lvar.magnetic_active = nil

      elseif lvar.dragswitcher then

        switchers[lvar.dragswitcher.selected].dragging = nil

        local strip = tracks[track_select].strip
        if lvar.showpop == true and not lvar.popout_autoarrange and strips[strip][page].popidx and strips[strip][page].popidx[lvar.dragswitcher.selected] then

          --reorder
          PopOut_ToTop(lvar.dragswitcher.selected)
          --GUI_DrawCtlBitmap_Mix()
        else
          if not mouse.ctrl then
            if lvar.dragswitcher.showpop then
              ShowPop(lvar.dragswitcher.showpop)
            end
            if lvar.dragswitcher.target then
              local src_extid = switchers[lvar.dragswitcher.selected].extendid
              local oldpos = switchers[lvar.dragswitcher.selected].extendpos
              local newpos = switchers[lvar.dragswitcher.target].extendpos
              Switchers_Ext_MovePos(src_extid, oldpos, newpos, lvar.dragswitcher.before, true)

            end
          else
            --pop out
            local x = mouse.mx-lvar.dragswitcher.offx - obj.sections[10].x
            local y = mouse.my-lvar.dragswitcher.offy - obj.sections[10].y

            PopOut(lvar.dragswitcher.selected,x,y)
          end
        end

        oswid = nil
        lvar.dragswitcher = nil
        lupd.update_surface = true

      elseif lvar.switchdrag then

        if lvar.switchdrag.targetc then
          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls

          local srcctl = ctls[lvar.switchdrag.c]
          local dstctl = ctls[lvar.switchdrag.targetc]
          if srcctl and dstctl then
            local dst_extid = switchers[dstctl.switcherid].extendid
            local src_extid = switchers[srcctl.switcherid].extendid
            if src_extid == dst_extid then
              local oldpos = switchers[srcctl.switcherid].extendpos
              local newpos = switchers[dstctl.switcherid].extendpos

              local before
              if mouse.my + surface_offset.y - obj.sections[10].y < dstctl.y + math.floor(dstctl.ctl_info.cellh/2) then
                before = true
              end
              Switchers_Ext_MovePos(src_extid, oldpos, newpos, before, true)
            end
          end
        end
        lvar.switchdrag = nil
        lupd.update_surface = true

      elseif matrixoff then
        matrixoff = nil
        lupd.update_surface = true
      
      elseif lvar.mdrag then
        lvar.mdrag = nil
        lupd.update_trbtns = true
        --lupd.update_surface = true
      end

    end

    --SIDEBAR
    local sbfullscreen = (show_stripbrowser and lvar.stripbrowser.fullscreen)

    if not sbfullscreen and not lvar.closesb then
      if mode0_submode == 0 then
        --DBG(tostring(lvar.show_addstripdialog)..'  '..tostring(navigate))
        if MOUSE_click(obj.sections[500]) and (navigate or lvar.show_addstripdialog) then
        --DBG('A')
          if show_fsnapshots then
            show_fsnapshots = false
            lupd.update_surface = true
            RedrawGUIBitmap()
          end
  
          if mouse.my > obj.sections[500].y + obj.sections[500].h - tb_butt_h then
            if mouse.mx < obj.sections[500].w-41 then
              PopulateUsedTracksTable()
              hideunusedtracks = not hideunusedtracks
              lupd.update_sidebar = true
            else
              if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
                settings_followselectedtrack = not settings_followselectedtrack
                lupd.update_sidebar = true
              end
            end
          else
            local i = math.floor((mouse.my - obj.sections[500].y) / tb_butt_h)-1
            if i == -1 then
              if mouse.mx < obj.sections[500].w/2 then
                tlist_offset = tlist_offset - T_butt_cnt
                if tlist_offset < 0 then
                  tlist_offset = 0
                end
              else
                if tlist_offset + T_butt_cnt < #tracks then
                  tlist_offset = tlist_offset + T_butt_cnt
                end
              end
              lupd.update_gfx = true
  
            elseif (hideunusedtracks ~= true and tracks[i-1 + tlist_offset]) or (hideunusedtracks == true and tracksused_idx[i + tlist_offset]) then
              if lvar.show_addstripdialog == true then
                lvar.addstripdialog_tracknum = i-1 + tlist_offset
                local ofxdata = lvar.fxdata
                local fxdata = AddStripDialog_GetFxData()
                if #fxdata > 0 then
  
                  fxdata.dx = ofxdata.dx
                  fxdata.dy = ofxdata.dy
                  fxdata.insertstrip = ofxdata.insertstrip
                  fxdata.loadstrip = ofxdata.loadstrip
                  fxdata.mode = ofxdata.mode
  
                  AddStripDialog_UpdateSel(fxdata)
                  lvar.fxdata = fxdata
                  lvar.show_addstripdialog = true
                  RedrawGUIBitmap()
                  lupd.update_gfx = true
                  RedrawGUIBitmap()
                  
                end
              else
                if mouse.ctrl then
                  local tr
                  if hideunusedtracks == true then
                    tr = tracksused_idx[i + tlist_offset]
                  else
                    tr = i-1 + tlist_offset
                  end
                  if not lvar.multiselecttracks then
                    lvar.multiselecttracks = {}
                  end
                  lvar.multiselecttracks[tr] = 1-(lvar.multiselecttracks[tr] or 0)
                  lupd.update_sidebar = true
                else
                  lvar.multiselecttracks = {}
                  local tr
                  if hideunusedtracks == true then
                    tr = tracksused_idx[i + tlist_offset]
                  else
                    tr = i-1 + tlist_offset
                  end
  
                  local strip = tracks[tr].strip
                  local iw, ih = gfx.getimgdim(skin.stripctlbtnslock)
                  local scale = math.min(tb_butt_h/ih,1)
                  if lvar.livemode == 2 and ((strips[strip] and strips[strip][page].lmode) or lvar.dm_fixtrack == tr) 
                     and (strips[strip] and strips[strip][page].lmode == 2 or lvar.dm_fixtrack == tr)
                     and mouse.mx >= obj.sections[500].w - iw*scale - 10 then
                    --padlock
                    if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                      lvar.dm_trackslocked = not (lvar.dm_trackslocked or false)
                      lupd.update_sidebar = true
                    end
                  else
                    if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
                      if tr == LBX_GTRACK then
                        SetGlobalPage()
                      else
                        ChangeTrack2(tr)
                      end
                    elseif lvar.livemode == 2 then
                      local track = GetTrack(tr)
                      if track then
                        reaper.SetOnlyTrackSelected(track)
                        DM_AddStrips()
                      end
                    end
                  end
                  
                end
              end
            end
          end
        elseif MOUSE_click_RB(obj.sections[500]) then
          if mouse.my > obj.sections[500].y + obj.sections[500].h - tb_butt_h then
          else
            local i = math.floor((mouse.my - obj.sections[500].y) / tb_butt_h)-1
            if i > -1 then
              if (hideunusedtracks ~= true and tracks[i-1 + tlist_offset]) or (hideunusedtracks == true and tracksused_idx[i + tlist_offset]) then
                local tr
                if hideunusedtracks == true then
                  tr = tracksused_idx[i + tlist_offset]
                else
                  tr = i-1 + tlist_offset
                end
                if tr then
                  local lm_a, lm_lm, lm_mm, lm_dm = '', '', '', ''
                  local strip = tracks[tr].strip
                  if strip and strips[strip] then
                    if strips[strip][page].lmode then
                      if strips[strip][page].lmode == 0 then
                        lm_lm = '!'
                      elseif strips[strip][page].lmode == 1 then
                        lm_mm = '!'
                      elseif strips[strip][page].lmode == 2 then
                        lm_dm = '!'
                      end
                    end
                  else
                    --lm_a = '#'
                  end
  
                  local lmd = ''
                  if lvar.livemode == 2 then
                    lmd = '#'
                  end
                  local dmft = ''
                  local dmft2 = '#'
                  if lvar.dm_fixtrack then
                    dmft2 = ''
                  end
                  if lvar.dm_fixtrack == track_select then
                    dmft = '!'
                  end
                  local mstr = lmd..'Clear track strip data: '..tracks[tr].name..'|'..lmd..'Clear strips for ALL tracks||'..lmd..'Duplicate Track/Strip|'..lmd..'Duplicate Highlighted Tracks'..
                               '|'..lmd..'Duplicate Highlighted Tracks (Retain Links)||Save Set (Highlighted Tracks)||Load Set (Merge)'..
                               '||'..lm_a..lm_lm..'Set Track/Strip To Live Mode (Current Page)|'..lm_a..lm_mm..'Set Track/Strip To Mix Mode (Current Page)|'..
                               lm_a..lm_dm..'Set Track/Strip To Dynamic Mode (Current Page)|'..
                               lm_a..'Clear Track/Strip Mode Flag||'..dmft..'(Global) Set Track/Strip (Page 1) To Dynamic Mode|'..dmft2..'Disable Global DM Setting'
                  gfx.x = mouse.mx
                  gfx.y = mouse.my
                  local res = gfx.showmenu(mstr)
                  if res > 0 then
                    if res == 1 then
                      ClearTrackStrip(tr)
                    elseif res == 2 then
                      if tracks then
                        local ret = reaper.MB("Delete ALL strip data?\n\n(not recommended if you are using Dynamic mode in your project)",'Delete Strip Data',4)
                        if ret == 6 then
                          for i = -1, #tracks do
                            ClearTrackStrip(i, true)
                          end
                          switchers = {}
                          CleanData()
                        end
                      end
                    elseif res == 3 then
                      DuplicateStrip()
  
                    elseif res == 4 then
                      lvar.multiselecttracks[track_select] = 1
                      local trcnt = 0
                      for i = -1, reaper.CountTracks(0)-1 do
                        if lvar.multiselecttracks[i] then
                          trcnt = trcnt + 1
                        end
                      end
                      local fn='lbx_duplicatetracks_set'
                      SaveSet2(fn,lvar.multiselecttracks,trcnt,false)
                      local load_path=paths.sets_path
                      local ffn=load_path..fn..".stripset"
                      local ft, lt = LoadSet2(ffn,true)
  
                    elseif res == 5 then
                      lvar.multiselecttracks[track_select] = 1
                      local trcnt = 0
                      for i = -1, reaper.CountTracks(0)-1 do
                        if lvar.multiselecttracks[i] then
                          trcnt = trcnt + 1
                        end
                      end
                      local fn='lbx_duplicatetracks_set'
                      SaveSet2(fn,lvar.multiselecttracks,trcnt,false)
                      local load_path=paths.sets_path
                      local ffn=load_path..fn..".stripset"
                      local ft, lt = LoadSet2(ffn,true,true)
                      --DBG(ft..'  '..lt)
                      local trlst = {}
                      for a,b in pairs(lvar.multiselecttracks) do
                        trlst[#trlst+1] = a
                      end
                      table.sort(trlst)
  
                      for i = 1, #trlst do
                        local tr = GetTrack(trlst[i])
                        local scnt = reaper.GetTrackNumSends(tr, 0)
                        for s = 0, scnt-1 do
                          local dtr = reaper.BR_GetMediaTrackSendInfo_Track(tr, 0, s, 1)
                          if dtr then
                            local dtn = reaper.GetMediaTrackInfo_Value(dtr, 'IP_TRACKNUMBER')
                            if not lvar.multiselecttracks[dtn-1] then
                              --duplicate send to copied track
                              local ttr = GetTrack(ft + (i-1))
                              if ttr then
                                DupSend(tr, ttr, dtr, s)
                              end
                            end
                          end
                        end
                      end
  
                      for i = 1, #trlst do
                        local tr = GetTrack(trlst[i])
                        local scnt = reaper.GetTrackNumSends(tr, -1)
                        for s = 0, scnt-1 do
                          local dtr = reaper.BR_GetMediaTrackSendInfo_Track(tr, -1, s, 0)
                          if dtr then
                            local dtn = reaper.GetMediaTrackInfo_Value(dtr, 'IP_TRACKNUMBER')
                            if not lvar.multiselecttracks[dtn-1] then
                              --duplicate send to copied track
                              local ttr = GetTrack(ft + (i-1))
                              if ttr then
                                DupSend(tr, dtr, ttr, nil, s)
                              end
                            end
                          end
                        end
                      end
                      os.remove(ffn)
  
                    elseif res == 6 then
  
                      local retval, fileName = reaper.JS_Dialog_BrowseForSaveFile('Save Strip Set As...', paths.sets_path, '', "stripset files (.stripset)\0*.stripset\0\0")
                      if retval == 1 then
  
                        --[[local retval = 6
                        if reaper.file_exists(fileName) then
                          local str = 'The strip set file already exists:\n\n'..fileName..'\n\nOverwrite?'
                          retval = reaper.MB(str, 'Merge Strip Set', 4)
                        end
  
                        if retval == 6 then]]
                          local fn = string.match(fileName,'.+[\\/](.*)$')
                          fn = string.match(fn,'(.+)%.stripset$') or fn
  
                          if fn then
                            if not lvar.multiselecttracks then
                              lvar.multiselecttracks = {}
                            end
                            lvar.multiselecttracks[track_select] = 1
                            local trcnt = 0
                            for i = -1, reaper.CountTracks(0)-1 do
                              if lvar.multiselecttracks[i] then
                                trcnt = trcnt + 1
                              end
                            end
                            SaveSet2(fn,lvar.multiselecttracks,trcnt,true)
                          end
                        --end
                      end
                    elseif res == 7 then
                      loadset_fn = LoadSet(true)
                    elseif res == 8 then
                      --live mode
                      local strip = Strip_INIT(tr)
                      --local strip = tracks[tr].strip
                      if strip and strips[strip] then
                        strips[strip][page].lmode = 0
                        if tr == track_select then
                          --lvar.livemode = 0
                          SetLiveMode(0, track_select, page, surface_offset.mixx, surface_offset.mixy)
                          lupd.update_gfx = true
                        end
                      end
                    elseif res == 9 then
                      --mix mode
                      local strip = Strip_INIT(tr)
                      --local strip = tracks[tr].strip
                      if strip and strips[strip] then
                        strips[strip][page].lmode = 1
                        if tr == track_select then
                          SetLiveMode(1, track_select, page, surface_offset.mixx, surface_offset.mixy)
                          --lvar.livemode = 1
                          --GUI_DrawCtlBitmap_Mix()
                          --lupd.update_gfx = true
                        end
                      end
                    elseif res == 10 then
                      --dynamic mode
                      local strip = Strip_INIT(tr)
                      --local strip = tracks[tr].strip
                      if strip and strips[strip] then
                        strips[strip][page].lmode = 2
                        if tr == track_select then
                          SetLiveMode(2, track_select, page, surface_offset.mixx, surface_offset.mixy)
                          --lvar.livemode = 2
                          --SetSurfaceSize2(obj)
                          obj = PosTrBtns(obj)
  
                          DM_AddStrips()
                          DM_RefreshPage()
  
                          --GUI_DrawCtlBitmap_Mix()
                          --lupd.update_trbtns = true
                          lupd.update_gfx = true
                        end
                      end
                    elseif res == 11 then
                      local strip = tracks[tr].strip
                      if strip and strips[strip] then
                        strips[strip][page].lmode = nil
                        if tr == track_select then
                          SetLiveMode(lvar.glivemode, track_select, page, surface_offset.mixx, surface_offset.mixy)
                          --lvar.livemode = lvar.glivemode
                          --if lvar.livemode >= 1 then
                          --  GUI_DrawCtlBitmap_Mix()
                          --end
                          lupd.update_gfx = true
                        end
                      end
                    elseif res == 12 then
                      lvar.dm_fixtrack = track_select
                      SetPage(1)
                    elseif res == 13 then
                      lvar.dm_fixtrack = nil
                      SetPage(1)
                    end
                  end
                end
              end
            end
          end
        end
  
      elseif mode0_submode == 1 then
        if MOUSE_click(obj.sections[500]) then
          if show_fsnapshots then
            show_fsnapshots = false
            lupd.update_surface = true
            RedrawGUIBitmap()
          end
  
          local i = math.floor((mouse.my - obj.sections[500].y) / tb_butt_h)-1
          if i == -1 then
            --if settings_localfaders == true then
            StoreFaders()
            --end
            if lvar.livemode == 2 then
              settings_localfaders = true
            else
              settings_localfaders = not settings_localfaders
            end
            RecallFaders()
            lupd.update_sidebar = true
  
          elseif i == 0 then
            if LBX_CTL_TRACK_INF then
              if mouse.mx < obj.sections[500].w/2 then
                fdlist_offset = fdlist_offset - (FD_butt_cnt-3)
                if fdlist_offset < 0 then
                  fdlist_offset = 0
                end
              else
                if fdlist_offset + FD_butt_cnt < #faders-1 then
                  fdlist_offset = fdlist_offset + (FD_butt_cnt-3)
                end
              end
              lupd.update_sidebar = true
            end
  
          elseif faders[i + fdlist_offset] then
            if LBX_CTL_TRACK_INF then
              local fd = i + fdlist_offset
              fader_select = fd
              if show_striplayout == false then
                mouse.context = contexts.dragfader
                dragfader = {x = mouse.mx, y = mouse.my}
              end
              lupd.update_gfx = true
            end
          end
        elseif MOUSE_click_RB(obj.sections[500]) then
  
          if LBX_CTL_TRACK_INF then
  
            local i = math.floor((mouse.my - obj.sections[500].y) / tb_butt_h)-1
            if i > 0 and faders[i + fdlist_offset] and faders[i + fdlist_offset].targettype then
              local fd = i + fdlist_offset
              fader_select = fd
  
              lupd.update_sidebar = true
              lupd = GUI_draw(obj, gui)
              gfx.update()
  
              local mstr = 'Clear'
              gfx.x = mouse.mx
              gfx.y = mouse.my
              local ret = gfx.showmenu(mstr)
              if ret > 0 then
                if ret == 1 then
                  DeleteFader(i + fdlist_offset)
                  lupd.update_sidebar = true
                  lupd.update_gfx = true
                end
              end
            elseif i == -1 then
              local mstr = 'Clear All|Clear Parameter Faders'
              gfx.x = mouse.mx
              gfx.y = mouse.my
              local ret = gfx.showmenu(mstr)
              if ret > 0 then
                if ret == 1 then
                  for i = 1, #faders do
                    DeleteFader(i)
                  end
                  lupd.update_sidebar = true
                  lupd.update_gfx = true
                elseif ret == 2 then
                  for i = 1, #faders do
                    if faders[i].targettype == 4 then
                      DeleteFader(i)
                    end
                  end
                  lupd.update_sidebar = true
                  lupd.update_gfx = true
                end
              end
  
            end
  
          end
        end
  
      elseif mode0_submode == 2 then
  
        if MOUSE_click(obj.sections[500]) then
          if show_fsnapshots then
            show_fsnapshots = false
            lupd.update_surface = true
            RedrawGUIBitmap()
          end
  
          local i = math.floor((mouse.my - obj.sections[500].y) / tb_butt_h)-1
          if i == 0 then
            if mouse.mx < obj.sections[500].w/2 then
              mdlist_offset = mdlist_offset - (MD_butt_cnt-3)
              if mdlist_offset < 0 then
                mdlist_offset = 0
              end
            else
              if mdlist_offset + MD_butt_cnt < #modulators-1 then
                mdlist_offset = mdlist_offset + (MD_butt_cnt-3)
              end
            end
            lupd.update_sidebar = true
  
          elseif i == -1 then
  
            --show_lfoedit = not show_lfoedit
            if mouse.mx < obj.sections[500].w/2 then
              SetShowLFO(not show_lfoedit)
              lupd.update_gfx = true
            else
              show_modass = not show_modass
              if show_modass == true then
                lvar.modass = PopModAssObj()
                if lvar.modass then
                  lvar.modass.offset = 0
                end
              end
              lupd.update_gfx = true
              RedrawGUIBitmap()
            end
          elseif modulators[i + mdlist_offset] then
  
            if not mouse.ctrl then
              local md = i + mdlist_offset
              mod_select = md
              if show_striplayout == false and show_modass == false then
                mouse.context = contexts.dragmod
                dragmod = {x = mouse.mx, y = mouse.my}
              end
              lupd.update_gfx = true
            else
              local md = i + mdlist_offset
              mod_select = md
              lvar.modass = PopModAssObj()
              if lvar.modass then
                lvar.modass.offset = 0
              end
              show_modass = true
              lupd.update_gfx = true
              RedrawGUIBitmap()
            end
          end
  
        elseif MOUSE_click_RB(obj.sections[500]) then
  
          --show_lfoedit = not show_lfoedit
          if mouse.mx < obj.sections[500].w/2 then
            SetShowLFO(not show_lfoedit)
            lupd.update_gfx = true
          else
            show_modass = not show_modass
            if show_modass == true then
              lvar.modass = PopModAssObj()
              if lvar.modass then
                lvar.modass.offset = 0
              end
            end
            lupd.update_gfx = true
            RedrawGUIBitmap()
          end
  
        end
      end
    
    end
    
    if mouse.context then

      if mouse.context == contexts.scrollsamples then

        local my = mouse.my - (obj.sections[1300].y+obj.sections[1303].y)
        local rsdata
        if smshowfavs then
          rsdata = samplefavs
        else
          rsdata = strips[tracks[track_select].strip][page].controls[rs5k_select].rsdata
        end
        local oos = smlist_offset
        smlist_offset = F_limit(math.floor(scrollsamps.lo + ((my-scrollsamps.y)/obj.sections[1303].h) * #rsdata.samples),0,#rsdata.samples-SM_butt_cnt)
        if smlist_offset ~= oos then
          lupd.update_samplemanager = true
        end

      elseif mouse.context == contexts.scrollkeyb then

        local mx = mouse.mx - (obj.sections[1300].x+obj.sections[1304].x)
        local oos = lvar.kb.offset
        lvar.kb.offset = F_limit(scrollkeyb.lo - (mx-scrollkeyb.x),0,(lvar.kb.wkey_w*lvar.kb.wkeys)-obj.sections[1304].w)
        if lvar.kb.offset ~= oos then
          lupd.update_samplemanager = true
        end

      elseif mouse.context == contexts.scrollsswin then

        local my = mouse.my - (obj.sections[160].y+obj.sections[1016].y)
        local ss = scrollss.ss

        local oos = ssoffset
        ssoffset = F_limit(math.floor(scrollss.lo + ((my-scrollss.y)/obj.sections[1016].h) * #ss),0,#ss-SS_butt_cnt)
        if ssoffset ~= oos then
          lupd.update_snaps = true
        end

      elseif mouse.context == contexts.modwin_resize then

        modwinsz.w = math.min(math.max(modwinrsz.w + (mouse.mx - modwinrsz.mx)/pnl_scale,modwin.minw),lvar.maxdim)
        modwinsz.h = math.min(math.max(modwinrsz.h + (mouse.my - modwinrsz.my)/pnl_scale,modwin.minh),lvar.maxdim)
        --modwinsz.w = math.min(math.max(modwinrsz.w + (mouse.mx - modwinrsz.mx),modwin.minw),lvar.maxdim)
        --modwinsz.h = math.min(math.max(modwinrsz.h + (mouse.my - modwinrsz.my),modwin.minh),lvar.maxdim)
        if modwinsz.w ~= modwinsz.ow or modwinsz.h ~= modwinsz.oh then

          modwinsz.resize = true

          obj = GetObjects()
          lupd.update_lfoedit = true
          --lupd.update_surface = true
          RedrawGUIBitmap()
          
          modwinsz.ow = modwinsz.w
          modwinsz.oh = modwinsz.h
        end

      elseif mouse.context == contexts.modwin_resize2 then

        --modwinsz.w = math.max(modwinrsz.w + (mouse.mx - modwinrsz.mx),modwin.minw)
        local s = modwinrsz.h - (mouse.my - modwinrsz.my)
        if modwinsz.minimized == true then
          s = gfx1.main_h - mouse.my
        end
        if s > 50*pnl_scale or (modwinsz.minimized == true and s >= modwin.minh*pnl_scale) then
          s = modwinrsz.h - (mouse.my - modwinrsz.my)
          modwinsz.h = math.min(math.min(math.max(s,modwin.minh*pnl_scale),gfx1.main_h-obj.sections[10].y),lvar.maxdim)
          modwinsz.minimized = false
          --modwinsz.oh = modwinsz.h
        else
          modwinsz.h = gui.winsz.pnltit*pnl_scale
          modwinsz.minimized = true
        end
        if modwinsz.h ~= modwinsz.oh or modwinsz.minimized == true then
          modwinsz.resize = true
          obj = GetObjects()
          lupd.update_lfoedit = true
          lupd.update_surface = true
          lupd.update_samplemanager = true
          RedrawGUIBitmap()
          
          modwinsz.ow = modwinsz.w
          modwinsz.oh = modwinsz.h

          if show_striplayout == true then
            SetASLocs()
          end
        end

      elseif mouse.context == contexts.modwin_move then

        modwinsz.x = math.min(math.max(modwinmv.x + (mouse.mx - modwinmv.mx),0),obj.sections[10].x+obj.sections[10].w-10)
        modwinsz.y = math.min(math.max(modwinmv.y + (mouse.my - modwinmv.my),obj.sections[10].y),gfx1.main_h-(modwinsz.h or 300)*pnl_scale --[[obj.sections[10].y+obj.sections[10].h-10]])
        if modwinsz.x ~= modwinsz.ox or modwinsz.y ~= modwinsz.oy then
          --obj.sections[1100].x = modwinsz.x
          --obj.sections[1100].y = modwinsz.y
          obj = GetObjects()
          --lupd.update_lfoedit = true
          --lupd.update_surface = true
          RedrawGUIBitmap()
          
          modwinsz.ox = modwinsz.x
          modwinsz.oy = modwinsz.y
        end

      elseif mouse.context == contexts.modoffset_slider then

        local val = MOUSE_slider(modoffs, modoffs.yoff)
        if val ~= nil then
          local m = modulators[mod_select]

          if oms ~= mouse.shift then
            oms = mouse.shift
            modoffs.val = val
            modoffs.yoff = -(mouse.my - (modoffs.y+modoffs.h/2)) --modoffs.y+modoffs.h/2 - mouse.my
          else
            if mouse.shift then
              local mult = settings_defknobsens.fine
              val = modoffs.val + ((0.5-val)*2)*mult
            else
              local mult = settings_defknobsens.norm
              val = modoffs.val + (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            if val ~= octlval then
              m.offset = val
              octlval = val
              lupd.update_lfoedit = true
            end
          end
        end

      elseif mouse.context == contexts.modmin_slider then

        local val = MOUSE_slider(modoffs, modoffs.yoff)
        if val ~= nil then
          local m = modulators[mod_select]
          if oms ~= mouse.shift then
            oms = mouse.shift
            modoffs.val = val
            modoffs.yoff = -(mouse.my - (modoffs.y+modoffs.h/2))
          else
            if mouse.shift then
              local mult = settings_defknobsens.fine
              val = modoffs.val + ((0.5-val)*2)*mult
            else
              local mult = settings_defknobsens.norm
              val = modoffs.val + (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end

            if omc ~= mouse.ctrl then
              omc = mouse.ctrl
              modoffs.odiff = math.min(math.max(m.max-val,0),1)
            end

            if val ~= octlval --[[and val < m.max]] then
              m.min = math.min(val,m.max)
              if mouse.ctrl then
                m.max = math.min(m.min+modoffs.odiff,1)
              end
              octlval = val
              lupd.update_lfoedit = true
            end
          end
        end

      elseif mouse.context == contexts.modmax_slider then

        local val = MOUSE_slider(modoffs, modoffs.yoff)
        if val ~= nil then
          local m = modulators[mod_select]

          if oms ~= mouse.shift then
            oms = mouse.shift
            modoffs.val = val
            modoffs.yoff = -(mouse.my - (modoffs.y+modoffs.h/2))
          else
            if mouse.shift then
              local mult = settings_defknobsens.fine
              val = modoffs.val + ((0.5-val)*2)*mult
            else
              local mult = settings_defknobsens.norm
              val = modoffs.val + (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end

            if omc ~= mouse.ctrl then
              omc = mouse.ctrl
              modoffs.odiff = math.min(math.max(val-m.min,0),1)
            end

            if val ~= octlval then
              m.max = math.max(val,m.min)
              if mouse.ctrl then
                m.min = math.max(m.max-modoffs.odiff,0)
              end
              octlval = val
              lupd.update_lfoedit = true
            end
          end
        end

      elseif mouse.context == contexts.mod_nudge then
      
        local xoff = round((mouse.mx - lvar.modnudge.mx) / lvar.modnudge.barw, 0)
        local m = modulators[mod_select]
        if xoff ~= 0 then
          local d = {}
          for i = 1, m.steps do
          
            local ni = i + xoff
            if ni < 1 then 
              ni = m.steps + ni 
            elseif ni > m.steps then
              ni = ni - m.steps 
            end
            d[ni] = m.data[i]
          end

          m.data = d
          lupd.update_lfoedit = true
          lvar.modnudge.mx = lvar.modnudge.mx + xoff*lvar.modnudge.barw --mouse.mx 
        end
        
        --DBG(xoff)
      
      elseif mouse.context == contexts.mod_draw then

        local m = modulators[mod_select]
        xywh = {x = obj.sections[1100].x + obj.sections[1101].x, -- + moddraw.offs,
                y = obj.sections[1100].y + obj.sections[1101].y,
                w = math.floor(moddraw.barw * m.steps),
                h = obj.sections[1101].h}
        --if MOUSE_over(xywh) then
          local xbar = math.floor((mouse.mx-xywh.x)/moddraw.barw) + 1
          local yp
          if m.mode >= 2 then
            local maxx = takeswitch_max
            if m.mode == 3 then
              maxx = lvar.maxsamples
            end
            yp = (F_limit(1- ((mouse.my - xywh.y) / xywh.h),0,1) * (m.max-m.min))
            yp = math.floor(yp*maxx)/maxx
          else
            yp = F_limit(1- ((mouse.my - xywh.y) / xywh.h),0,1)
          end
          if mouse.shift then
            if not moddraw.yp then
              moddraw.yp = yp
            end
            yp = moddraw.yp
          end
          if mouse.ctrl then
            if moddraw.lastx then
              xbar = moddraw.lastx
            end
          end
          if xbar >= 1 and xbar <= m.steps then
            m.data[xbar] = yp
            if not modbaridx[xbar] then
              modbaridx[xbar] = true
              modbaredit[#modbaredit+1] = xbar
            end
          end
          if moddraw.lastx then
            local xd = xbar - moddraw.lastx
            if math.abs(xd) > 1 then
              local step = 1
              if xd < 0 then
                step = -1
              end
              local dy = (moddraw.lasty - yp) / -(xd)
              local min, max
              if yp > moddraw.lasty then
                min, max = moddraw.lasty, yp
              else
                min, max = yp, moddraw.lasty
              end
              for ii = step, xd-1, step do
                i = moddraw.lastx + ii
                if i >= 1 and i <= m.steps then
                  if mouse.shift then
                    m.data[i] = yp
                  else
                    m.data[i] = F_limit(moddraw.lasty + (ii * dy),min,max)
                  end
                  if not modbaridx[i] then
                    modbaridx[i] = true
                    modbaredit[#modbaredit+1] = i
                  end
                end
              end
            end
          end
          moddraw.lastx = xbar
          moddraw.lasty = yp
          lupd.update_lfoeditbar = true

          local txt = ''
          if m.mode == 2 then
            txt = 'TAKE '..math.floor(yp*takeswitch_max+1)
          elseif m.mode == 3 then
            --txt = 'SAMPLE '..math.floor(yp*(m.max*(lvar.maxsamples-1))+1)
            txt = 'SAMPLE '..math.floor(yp*(lvar.maxsamples-1))+1
          else
            txt = round(yp*(m.max*takeswitch_max),2)
          end
          local mx, my = gfx.mouse_x, gfx.mouse_y
          local dock_state, wx,wy,ww,wh = gfx.dock(-1,0,0,0,0)
          reaper.TrackCtl_SetToolTip(txt, wx+mx-15, wy+my-25, true)
        --end

      elseif mouse.context == contexts.movesnapwindow then

        obj.sections[160].x = F_limit(mouse.mx - movesnapwin.offx, obj.sections[10].x, gfx1.main_w-obj.sections[160].w)
        obj.sections[160].y = F_limit(mouse.my - movesnapwin.offy, obj.sections[10].y, gfx1.main_h-obj.sections[160].h)
        obj.sections[160].x = math.max(obj.sections[160].x,obj.sections[10].x)
        obj.sections[160].y = math.max(obj.sections[160].y,obj.sections[10].y)

        snapshot_win_pos = {x = obj.sections[160].x, y = obj.sections[160].y}
        lupd.update_msnaps = true
        --lupd.update_stripbrowser = true
        lupd.update_surface = true
        RedrawGUIBitmap()
        
      elseif mouse.context == contexts.addsnapctl then
        local iw, ih
        if dragparam then
          iw = dragparam.iw
          ih = dragparam.ih
        end
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'snapctl'}
        if mode == 0 and lvar.livemode >= 1 then
          dragparam.alpha = 0.2
          local strip = tracks[track_select].strip
          local _, stripidx, stripid = GetControlAtXY(strip, page, dragparam.x, dragparam.y)
          if stripidx and lvar.stripdim then
            local x, y = TranslateMixPos(dragparam.x, dragparam.y, nil, lvar.stripdim.swidx[stripid])
            local w, h
            if not ctl_files[knob_select].imageidx then
              w, h = iw or ksel_size.w*2, ih or ksel_size.h*2
            else
              w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
            end
            --local x, y = xx, yy--math.floor(xx-(w/2)), math.floor(yy-(h/2))
            stripid_add = stripid
            if lvar.stripdim.swidx[stripid] then
              parent_switcher = tonumber(Switcher_GetTopLevelSwitcher(lvar.stripdim.swidx[stripid]))
              swid_grpid = switchers[parent_switcher].current
              if x and y and stripid_add and parent_switcher and swid_grpid then
                if x >= lvar.stripdim.swdata[parent_switcher].l and x+w <= lvar.stripdim.swdata[parent_switcher].r and
                   y >= lvar.stripdim.swdata[parent_switcher].t+(lvar.stripdim.swdata[parent_switcher].sb-lvar.stripdim.swdata[parent_switcher].st)
                   and y+h <= lvar.stripdim.swdata[parent_switcher].b then
                  dragparam.alpha = 1
                end
              end
            end
          end
        end
        lupd.update_surface = true

      elseif mouse.context == contexts.addxyctl then
        local iw, ih
        if dragparam then
          iw = dragparam.iw
          ih = dragparam.ih
        end
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'xyctl'}
        if mode == 0 and lvar.livemode >= 1 then
          dragparam.alpha = 0.2
          local strip = tracks[track_select].strip
          local _, stripidx, stripid = GetControlAtXY(strip, page, dragparam.x, dragparam.y)
          if stripidx and lvar.stripdim then
            local x, y = TranslateMixPos(dragparam.x, dragparam.y, nil, lvar.stripdim.swidx[stripid])
            local w, h
            if not ctl_files[knob_select].imageidx then
              w, h = iw or ksel_size.w*2, ih or ksel_size.h*2
            else
              w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
            end
            --local x, y = xx, yy--math.floor(xx-(w/2)), math.floor(yy-(h/2))
            stripid_add = stripid
            parent_switcher = tonumber(Switcher_GetTopLevelSwitcher(lvar.stripdim.swidx[stripid]))
            swid_grpid = switchers[parent_switcher].current
            if x and y and stripid_add and parent_switcher and swid_grpid then
              if x >= lvar.stripdim.swdata[parent_switcher].l and x+w <= lvar.stripdim.swdata[parent_switcher].r and
                 y >= lvar.stripdim.swdata[parent_switcher].t+(lvar.stripdim.swdata[parent_switcher].sb-lvar.stripdim.swdata[parent_switcher].st)
                 and y+h <= lvar.stripdim.swdata[parent_switcher].b then
                dragparam.alpha = 1
              end
            end
          end
        end
        lupd.update_surface = true

      elseif mouse.context == contexts.snapshot_rand then
        local iw, ih
        if dragparam then
          iw = dragparam.iw
          ih = dragparam.ih
        end
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'snaprand'}
        if mode == 0 and lvar.livemode >= 1 then
          dragparam.alpha = 0.2
          local strip = tracks[track_select].strip
          local _, stripidx, stripid = GetControlAtXY(strip, page, dragparam.x, dragparam.y)
          if stripidx and lvar.stripdim then
            local x, y = TranslateMixPos(dragparam.x, dragparam.y, nil, lvar.stripdim.swidx[stripid])
            local w, h
            if not ctl_files[knob_select].imageidx then
              w, h = iw or ksel_size.w*2, ih or ksel_size.h*2
            else
              w, h = gfx.getimgdim(ctl_files[knob_select].imageidx)
            end

            --local x, y = xx, yy--math.floor(xx-(w/2)), math.floor(yy-(h/2))
            stripid_add = stripid
            if lvar.stripdim.swidx[stripid] then
              parent_switcher = tonumber(Switcher_GetTopLevelSwitcher(lvar.stripdim.swidx[stripid]))
              swid_grpid = switchers[parent_switcher].current
              if x and y and stripid_add and parent_switcher and swid_grpid then
                if x >= lvar.stripdim.swdata[parent_switcher].l and x+w <= lvar.stripdim.swdata[parent_switcher].r and
                   y >= lvar.stripdim.swdata[parent_switcher].t+(lvar.stripdim.swdata[parent_switcher].sb-lvar.stripdim.swdata[parent_switcher].st)
                   and y+h <= lvar.stripdim.swdata[parent_switcher].b then
                  dragparam.alpha = 1
                end
              end
            end
          end
        end
        lupd.update_surface = true


      elseif mouse.context == contexts.dragfader then
        if mouse.mx ~= dragfader.x or mouse.my ~= dragfader.y then
          local c = GetControlAtXY(tracks[track_select].strip,page,mouse.mx,mouse.my)
          if c then
            local ctl = strips[tracks[track_select].strip][page].controls[c]
            if ctl and (ctl.ctlcat == ctlcats.fxparam or
                        ctl.ctlcat == ctlcats.trackparam or
                        ctl.ctlcat == ctlcats.tracksend or
                        ctl.ctlcat == ctlcats.macro or
                        ctl.ctlcat == ctlcats.snapshot or
                        ctl.ctlcat == ctlcats.switcher or
                        ctl.ctlcat == ctlcats.midictl or
                        ctl.ctlcat == ctlcats.threshold) then
              dragfader = {x = mouse.mx, y = mouse.my, ctl = c}
            else
              dragfader = {x = mouse.mx, y = mouse.my, ctl = -1}
            end
          else
            dragfader = {x = mouse.mx, y = mouse.my, ctl = nil}
          end
          lupd.update_surface = true
        end

      elseif mouse.context == contexts.dragmod then
        if mouse.mx ~= dragmod.x or mouse.my ~= dragmod.y then
          local c = GetControlAtXY(tracks[track_select].strip,page,mouse.mx,mouse.my)
          if c --[[and not MOUSE_over(obj.sections[1100]) and not MOUSE_over(obj.sections[160]) and not MOUSE_over(obj.sections[1120])]] then
            local ctl = strips[tracks[track_select].strip][page].controls[c]
            if ctl and (ctl.ctlcat == ctlcats.fxparam or
                        ctl.ctlcat == ctlcats.trackparam or
                        ctl.ctlcat == ctlcats.tracksend or
                        ctl.ctlcat == ctlcats.macro or
                        ctl.ctlcat == ctlcats.takeswitcher or
                        ctl.ctlcat == ctlcats.rs5k) then
              dragmod = {x = mouse.mx, y = mouse.my, ctl = c}
            else
              dragmod = {x = mouse.mx, y = mouse.my, ctl = -1}
            end
          else
            dragmod = {x = mouse.mx, y = mouse.my, ctl = nil}
          end
          lupd.update_surface = true
        end

      elseif mouse.context == contexts.resizesnapwindow then

        local ly = obj.sections[10].h - obj.sections[160].y + butt_h*pnl_scale
        obj.sections[160].h = F_limit(resizesnapwin.origh + (mouse.my - resizesnapwin.offy) - obj.sections[160].y, 252*pnl_scale, ly)
        obj.sections[163].h = obj.sections[160].h - 208*pnl_scale
        obj.sections[1016].h = obj.sections[163].h-2 - math.floor(butt_h*pnl_scale) - 2

        obj.sections[1010].y = obj.sections[163].y + obj.sections[163].h + 3*pnl_scale
        obj.sections[1011].y = obj.sections[1010].y
        obj.sections[1012].y = obj.sections[1010].y
        obj.sections[1013].y = obj.sections[1010].y+(butt_h+2)*pnl_scale
        obj.sections[1014].y = obj.sections[1013].y
        obj.sections[1015].y = obj.sections[1013].y

        obj.sections[165].y = obj.sections[160].h - obj.sections[165].h
        snaph = obj.sections[160].h
        lupd.update_msnaps = true
        resize_snaps = true

        lupd.update_surface = true
        --lupd.update_gfx = true
        RedrawGUIBitmap()
        
      elseif mouse.context == contexts.resizefsnapwindow then

        local ly = obj.sections[10].h - obj.sections[180].y + butt_h
        obj.sections[180].h = F_limit(resizesnapwin.origh + (mouse.my - resizesnapwin.offy) - obj.sections[180].y, 180, ly)
        obj.sections[181].h = obj.sections[180].h - 12
        obj.sections[182].y = obj.sections[180].h - 6
        fsnaph = obj.sections[180].h
        lupd.update_mfsnaps = true
        resize_fsnaps = true
        --lupd.update_gfx = true

      elseif mouse.context == contexts.snap_move then
        local my = mouse.my-obj.sections[160].y
        local i = math.floor((my-obj.sections[163].y)/(butt_h*pnl_scale))
        local snapcnt
        if sstype_select == 1 then
          snapcnt = #snapshots[tracks[track_select].strip][page][sstype_select]
        else
          snapcnt = #snapshots[tracks[track_select].strip][page][sstype_select].snapshot
        end
        if reaper.time_precise() > ssshiftto then
          if i<1 then
            ssoffset = math.max(ssoffset-1,0)
          elseif i>SS_butt_cnt then
            ssoffset = math.min(ssoffset+1,snapcnt-1)
          end
          ssshiftto = reaper.time_precise() + 0.15
        end
        snap_move.epos = F_limit(ssoffset+i,1,snapcnt+1)
        lupd.update_snaps = true

      elseif mouse.context == contexts.morph_time then
        local xywh = {x = obj.sections[1010].x,
                      y = obj.sections[160].y + obj.sections[1010].y,
                      w = obj.sections[1010].w,
                      h = obj.sections[1010].h}
        local val = MOUSE_slider(xywh,mouse.slideoff)
        if val ~= nil then
          if oms ~= mouse.shift then
            oms = mouse.shift
            dragmorphtime = snapshots[tracks[track_select].strip][page][sstype_select].morph_time
            mouse.slideoff = obj.sections[1010].y+obj.sections[1010].h/2 - (mouse.my-obj.sections[160].y)
          else
            if mouse.shift then
              val = dragmorphtime + ((0.5-val))*0.01
            else
              val = dragmorphtime + (0.5-val)*0.1
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            if val ~= octlval then
              snapshots[tracks[track_select].strip][page][sstype_select].morph_time = val
              octlval = val
              lupd.update_snaps = true
            end
          end
        end

      elseif mouse.context == contexts.lg_min then
        local val = MOUSE_slider(obj.sections[1134],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[randomopts_select.ctls[p].ctl]
          if draglg.shift ~= mouse.shift then
            draglg.shift = mouse.shift
            draglg.pos = randomopts_select.ctls[p].min
            draglg.yoff = mouse.my-(obj.sections[1134].y+obj.sections[1134].h/2)
          end
          local mult = 1
          if mouse.shift == true then
            mult = 0.02
          end
          local v = draglg.pos + (val-0.5)*mult
          if round(v,4) ~= round(randomopts_select.ctls[p].min,4) then
            if ctl and ctl.ctlcat == ctlcats.takeswitcher then
              local numtakes = ctl.iteminfo.numtakes
              randomopts_select.ctls[p].min = F_limit(v,0,(1/takeswitch_max)*(numtakes-1))
            else
              randomopts_select.ctls[p].min = F_limit(round(v,4),0,1)
            end
            lupd.update_randomopts = true
          end
        end

      elseif mouse.context == contexts.lg_max then
        local val = MOUSE_slider(obj.sections[1135],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[randomopts_select.ctls[p].ctl]
          if draglg.shift ~= mouse.shift then
            draglg.shift = mouse.shift
            draglg.pos = randomopts_select.ctls[p].max
            draglg.yoff = mouse.my-(obj.sections[1135].y+obj.sections[1135].h/2)
          end
          local mult = 1
          if mouse.shift == true then
            mult = 0.02
          end
          local v = draglg.pos + (val-0.5)*mult
          if round(v,4) ~= round(randomopts_select.ctls[p].max,4) then
            if ctl and ctl.ctlcat == ctlcats.takeswitcher then
              local numtakes = ctl.iteminfo.numtakes
              randomopts_select.ctls[p].max = F_limit(v,0,(1/takeswitch_max)*(numtakes-1))
            else
              randomopts_select.ctls[p].max = F_limit(round(v,4),0,1)
            end
            lupd.update_randomopts = true
          end
        end

      elseif mouse.context == contexts.lg_probability then
        local val = MOUSE_slider(obj.sections[1137],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          randomopts_select.ctls[p].rprob = F_limit(draglg.pos + (val-0.5),0,1)
          lupd.update_randomopts = true
        end

      elseif mouse.context == contexts.lg_bias then
        local val = MOUSE_slider(obj.sections[1138],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          randomopts_select.ctls[p].bias = F_limit(draglg.pos + (val-0.5),0,1)
          lupd.update_randomopts = true
        end

      elseif mouse.context == contexts.lg_range then
        local val = MOUSE_slider(obj.sections[1140],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          if draglg.shift ~= mouse.shift then
            draglg.shift = mouse.shift
            draglg.pos = randomopts_select.ctls[p].amount
            draglg.yoff = mouse.my-(obj.sections[1140].y+obj.sections[1140].h/2)
          end
          local mult = 1
          if mouse.shift == true then
            mult = 0.002
          end
          local v = (draglg.pos or 0) + (val-0.5)*mult
          if round(randomopts_select.ctls[p].amount,5) ~= round(v,5) then
            randomopts_select.ctls[p].amount = F_limit(round(v,5),0,1)
            if randomopts_select.ctls[p].amount == 0 then
              randomopts_select.ctls[p].amount = nil
            end
            lupd.update_randomopts = true
          end
        end

      elseif mouse.context == contexts.lg_wild then
        local val = MOUSE_slider(obj.sections[1146],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          randomopts_select.ctls[p].wild = F_limit((draglg.pos or 0) + (val-0.5),0,1) *0.1
          lupd.update_randomopts = true
        end

      elseif mouse.context == contexts.lg_X then
        local val = MOUSE_slider(obj.sections[1144],-draglg.yoff)
        if val ~= nil then
          val = 1-val
          local p = randomopts_select.param
          local lg = randomopts_select.ctls[p].linkgrp
          if draglg.shift ~= mouse.shift then
            draglg.shift = mouse.shift
            draglg.pos = randomopts_select.linkgrps[lg].X
            draglg.yoff = mouse.my-(obj.sections[1144].y+obj.sections[1144].h/2)
          end
          local mult = 1
          if mouse.shift == true then
            local type = randomopts_select.linkgrps[lg].type
            if type <= 3 then
              mult = 0.1
            else
              mult = 0.002
            end
          end
          if randomopts_select.linkgrps[lg] then
            if round(randomopts_select.linkgrps[lg].X,5) ~= round(draglg.pos + (val-0.5)*mult,5) then
              randomopts_select.linkgrps[lg].X = F_limit(round(draglg.pos + (val-0.5)*mult,5),0,1)
              lupd.update_randomopts = true
            end
          end
        end

      elseif mouse.context == contexts.move_mutatewin then

        obj.sections[1120].x = F_limit(mouse.mx - movemutatewin.dx,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-obj.sections[1120].w)
        obj.sections[1120].y = F_limit(mouse.my - movemutatewin.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[1120].h)
        --lupd.update_surface = true
        RedrawGUIBitmap()
        
      elseif mouse.context == contexts.mutate_amt then
        local val = MOUSE_slider(obj.sections[1121],-mutateamt.yoff)
        if val ~= nil then
          val = 1-val
          lvar.mutate_settings.mutate_max = F_limit(mutateamt.pos + math.floor((val-0.5)*100),1,100)
          lupd.update_mutate = true
        end

      elseif mouse.context == contexts.move_randomwin then

        obj.sections[1130].x = F_limit(mouse.mx - moverandomwin.dx,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-obj.sections[1130].w)
        obj.sections[1130].y = F_limit(mouse.my - moverandomwin.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[1130].h)
        obj.sections[1130].y = math.max(obj.sections[1130].y,obj.sections[10000].y)
        --lupd.update_surface = true
        RedrawGUIBitmap()
        
      elseif mouse.context == contexts.move_smwin then

        obj.sections[1300].x = F_limit(mouse.mx - movesmwin.dx,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-obj.sections[1300].w)
        obj.sections[1300].y = F_limit(mouse.my - movesmwin.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[1300].h)
        obj.sections[1300].y = math.max(obj.sections[1300].y,obj.sections[10000].y)
        --lupd.update_surface = true
        RedrawGUIBitmap()
        
      elseif mouse.context == contexts.resize_smwin then

        local dx = smwinrsz.x + smwinrsz.sc_w - smwinrsz.mx
        local dy = smwinrsz.y + smwinrsz.sc_h - smwinrsz.my

        local nw = mouse.mx - smwinrsz.x + dx
        smwin.w = nw/pnl_scale

        local nh = mouse.my - smwinrsz.y + dy
        smwin.h = nh/pnl_scale

        if smwin.w ~= smwin.ow or smwin.h ~= smwin.oh then
          local smw,smh = math.max(math.min(math.floor(smwin.w*pnl_scale),obj.sections[10000].w-20,lvar.kb.wkey_w*lvar.kb.wkeys+20),300*pnl_scale),
                          math.max(math.min(math.floor((smwin.h*pnl_scale)),obj.sections[10000].h),405*pnl_scale)

          obj.sections[1300] = {x = math.max(F_limit(obj.sections[1300].x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-smw),obj.sections[10000].x),
                                y = math.max(F_limit(obj.sections[1300].y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-smh),obj.sections[10000].y),
                                w = smw,
                                h = smh}

          obj = PosSampleManager(obj)
          --lupd.update_surface = true
          lupd.update_samplemanager = true

          smwin.ow = smwin.w
          smwin.oh = smwin.h
          RedrawGUIBitmap()
        end

      elseif mouse.context == contexts.resize_smwinv then

        local dy = smwinrsz.y + smwinrsz.sc_h - smwinrsz.my

        local nh = mouse.my - smwinrsz.y + dy
        smwin.h = nh/pnl_scale

        if smwin.h ~= smwin.oh then
          local smw,smh = math.max(math.min(math.floor(smwin.w*pnl_scale),obj.sections[10000].w-20,lvar.kb.wkey_w*lvar.kb.wkeys+20),300*pnl_scale),
                          math.max(math.min(math.floor((smwin.h*pnl_scale)),obj.sections[10000].h),405*pnl_scale)

          obj.sections[1300] = {x = math.max(F_limit(obj.sections[1300].x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-smw),obj.sections[10000].x),
                                y = math.max(F_limit(obj.sections[1300].y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-smh),obj.sections[10000].y),
                                w = smw,
                                h = smh}

          obj = PosSampleManager(obj)
          --lupd.update_surface = true
          lupd.update_samplemanager = true
          RedrawGUIBitmap()
          
          smwin.oh = smwin.h
        end

      elseif mouse.context == contexts.move_sbwin then

        --obj.sections[1350].x = F_limit(mouse.mx - movesbwin.dx,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-obj.sections[1350].w)
        --obj.sections[1350].y = F_limit(mouse.my - movesbwin.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[1350].h)
        if not lvar.stripbrowser.fullscreen then
          obj.sections[1350].x = F_limit(mouse.mx - movesbwin.dx,0,gfx1.main_w-obj.sections[1350].w)
          obj.sections[1350].y = F_limit(mouse.my - movesbwin.dy,0,gfx1.main_h-obj.sections[1350].h)
          obj.sections[1350].y = math.max(obj.sections[1350].y,obj.sections[10000].y)
          sbwin.x = obj.sections[1350].x
          sbwin.y = obj.sections[1350].y
          --lupd.update_surface = true
          RedrawGUIBitmap()
        end
        
      elseif mouse.context == contexts.resize_sbwin then

        if not lvar.stripbrowser.fullscreen then
        
          local dx = sbwinrsz.x + sbwinrsz.sc_w - sbwinrsz.mx
          local dy = sbwinrsz.y + sbwinrsz.sc_h - sbwinrsz.my
          local nw = mouse.mx - sbwinrsz.x + dx
          sbwin.w = math.max(nw/pnl_scale,160)
  
          local nh = mouse.my - sbwinrsz.y + dy
          sbwin.h = math.max(nh/pnl_scale,160)
  
          if sbwin.w ~= sbwin.ow or sbwin.h ~= sbwin.oh then
            sbwin.ow = sbwin.w
            sbwin.oh = sbwin.h
            local maxh = gfx1.main_h - obj.sections[1350].y
            local sbw,sbh = math.max(math.min(math.floor(sbwin.w*pnl_scale),obj.sections[10000].w),lvar.sbmin*pnl_scale),
                            math.max(math.min(math.floor((sbwin.h*pnl_scale)),maxh),lvar.sbmin*pnl_scale)
  
            --[[obj.sections[1350] = {x = math.max(F_limit(obj.sections[1350].x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-sbw),obj.sections[10000].x),
                                  y = math.max(F_limit(obj.sections[1350].y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-sbh),obj.sections[10000].y),
                                  w = sbw,
                                  h = sbh}]]
            obj.sections[1350] = {x = F_limit(obj.sections[1350].x,0,gfx1.main_w-obj.sections[1350].w),
                                  y = F_limit(obj.sections[1350].y,0,gfx1.main_h-obj.sections[1350].h),
                                  w = sbw,
                                  h = sbh}
            obj.sections[1350].y = math.max(obj.sections[1350].y,obj.sections[10000].y)
            --DBG(obj.sections[1350].w..'  '..obj.sections[1350].h)
            if settings_sbdock == true then
              SetSurfaceSize2(obj)
              obj.sections[1350].x = obj.sections[10000].x+obj.sections[10000].w
              obj.sections[1350].y = obj.sections[10000].y
              obj.sections[1350].h = obj.sections[10000].h
              lupd.update_surface = true
            end
            obj = PosStripBrowser(obj)
            lupd.update_stripbrowser = true
            RedrawGUIBitmap()
  
          end
        end
        
      elseif mouse.context == contexts.resize_sbwinh then

        if not lvar.stripbrowser.fullscreen then
        
          local dx = sbwinrsz.x + sbwinrsz.sc_w - sbwinrsz.mx + sbwinrsz.ddx
          local nw = sbwinrsz.x + dx - mouse.mx + sbwinrsz.ddx
  
          local maxw = obj.sections[10000].w + math.floor(sbwin.w*pnl_scale)
          local maxw2 = obj.sections[10000].w + sbwin.w
          if settings_sbdock == true then
            sbwin.w = math.floor(math.min(math.max(nw/pnl_scale,lvar.sbmin),maxw2))
          else
            sbwin.w = math.max(math.floor(nw/pnl_scale),lvar.sbmin)
          end
  
          if sbwin.w ~= sbwin.ow then
            sbwin.ow = sbwin.w
  
            local sbw,sbh
            if settings_sbdock == true then
              sbw,sbh = math.max(math.min(math.floor(sbwin.w*pnl_scale),maxw),lvar.sbmin*pnl_scale),
                        math.max(math.min(math.floor((sbwin.h*pnl_scale)),obj.sections[10000].h),lvar.sbmin*pnl_scale)
            else
              sbw,sbh = math.max(math.min(math.floor(sbwin.w*pnl_scale),obj.sections[10000].w),lvar.sbmin*pnl_scale),
                        math.max(math.min(math.floor((sbwin.h*pnl_scale)),obj.sections[10000].h),lvar.sbmin*pnl_scale)
            end
            --[[obj.sections[1350] = {x = math.max(F_limit(obj.sections[1350].x,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-sbw),obj.sections[10000].x),
                                  y = math.max(F_limit(obj.sections[1350].y,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-sbh),obj.sections[10000].y),
                                  w = sbw,
                                  h = sbh}]]
            obj.sections[1350] = {x = F_limit(obj.sections[1350].x,0,gfx1.main_w-obj.sections[1350].w),
                                  y = F_limit(obj.sections[1350].y,0,gfx1.main_h-obj.sections[1350].h),
                                  w = sbw,
                                  h = sbh}
            obj.sections[1350].y = math.max(obj.sections[1350].y,obj.sections[10000].y)                                
            if settings_sbdock == true then
              SetSurfaceSize2(obj)
              if settings_ssdock == true and show_snapshots == true then
                obj.sections[1350].x = obj.sections[160].x-obj.sections[1350].w
              else
                obj.sections[1350].x = obj.sections[10000].x+obj.sections[10000].w
              end
              obj.sections[1350].y = obj.sections[10000].y
              local hh = math.min(math.max((gfx1.main_h-obj.sections[10000].y),lvar.sbmin*pnl_scale),lvar.maxdim)
              obj.sections[1350].h = hh
            else
              obj.sections[1350].x = sbwinrsz.ep - math.floor(sbwin.w*pnl_scale) -- sbwinrsz.mmx
              sbwin.x = obj.sections[1350].x
            end
            --resize_display = true
            --obj = PosStripBrowser(obj)
            --obj = GetObjects()
            obj = PosStripBrowser(obj)
            if settings_sbdock == true then
              SetSurfaceSize2(obj)
              obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])
              obj = PosTrBtns(obj)
            end
            lupd.update_surface = true
            lupd.update_stripbrowser = true
            RedrawGUIBitmap()
          end
        end
        
      elseif mouse.context == contexts.resize_sbwinv then

        if not lvar.stripbrowser.fullscreen then
        
          local dy = sbwinrsz.y + sbwinrsz.sc_h - sbwinrsz.my
  
          local nh = mouse.my - sbwinrsz.y + dy
          sbwin.h = math.max(nh/pnl_scale,lvar.sbmin)
  
          if sbwin.h ~= sbwin.oh then
            sbwin.oh = sbwin.h
  
            local sbh
            if settings_sbdock == true then
              local add = 0
              if settings_moddock == true and show_lfoedit == true then
                add = add + obj.sections[1100].h
              end
              if lvar.livemode >= 1 and lvar.trbtns_show then
                add = add + obj.sections[4999].h
                if lvar.trmix_show then
                  add = add + lvar.trmix_h
                end
              end
  
              local maxh = gfx1.main_h - obj.sections[1350].y - add
              sbh = math.max(math.min(math.floor(sbwin.h*pnl_scale),maxh),lvar.sbmin*pnl_scale)
              sbwin.h = math.floor(sbh/pnl_scale)
              sbh = math.floor(sbwin.h*pnl_scale)
            else
              local add = 0
              local maxh = gfx1.main_h - obj.sections[1350].y - add
              sbh = math.max(math.min(math.floor(sbwin.h*pnl_scale),maxh),lvar.sbmin*pnl_scale)
              sbwin.h = math.floor(sbh/pnl_scale)
              sbh = math.floor(sbwin.h*pnl_scale)            
            end
            obj.sections[1350] = {x = obj.sections[1350].x,
                                  y = obj.sections[1350].y, --math.max(F_limit(obj.sections[1350].y,obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-sbh),obj.sections[10].y)
                                  w = obj.sections[1350].w,
                                  h = sbh}
            --resize_display = true
            --obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])
            obj = PosStripBrowser(obj)
            if settings_sbdock == true then
              SetSurfaceSize2(obj)
              obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])
              obj = Repos5001(obj)
            end
            --lvar.resize_stripbrowser = true
            --[[if not lvar.resize_stripbrowser_t or reaper.time_precise() > lvar.resize_stripbrowser_t then
              lvar.resize_stripbrowser_t = reaper.time_precise()+0.5
              lvar.resize_stripbrowser = nil
            end]]
  
            --obj = GetObjects()
  
            lupd.update_surface = true
            lupd.update_stripbrowser = true
            RedrawGUIBitmap()
            
            if show_striplayout == true and stripgallery_view == 0 then
              SetASLocs()
            end
          end
        end
        
      elseif mouse.context == contexts.sb_movefav then

        local mx = mouse.mx - obj.sections[1350].x
        local my = mouse.my - obj.sections[1350].y
        local x = math.floor((mx - obj.sections[1352].x)/(obj.sections[1352].w/lvar.stripbrowser.xnum))
        local y = math.floor((my - obj.sections[1352].y)/(obj.sections[1352].h/lvar.stripbrowser.ynum))
        local offset = (lvar.stripbrowser.ynum*lvar.stripbrowser.xnum) * lvar.stripbrowser.page

        local n = x + (y*lvar.stripbrowser.xnum) + offset
        if n ~= oldn then
          strip_favs = table.copy(movefav)
          strip_favs_n = table.copy(movefav_n)
          if strip_favs[n+1] then
            local element = strip_favs[lvar.stripbrowser.moveselect+1]
            local element_n = strip_favs_n[lvar.stripbrowser.moveselect+1]
            strip_favs = Table_RemoveEntry(strip_favs,#movefav,lvar.stripbrowser.moveselect+1)
            table.insert(strip_favs,n+1,element)
            strip_favs_n = Table_RemoveEntry(strip_favs_n,#movefav_n,lvar.stripbrowser.moveselect+1)
            table.insert(strip_favs_n,n+1,element_n)

            lvar.stripbrowser.select = n
            oldn = n
          else
            oldn = nil
            lvar.stripbrowser.select = lvar.stripbrowser.moveselect
          end
          --lvar.reloadsbimages = true --slow - probably a better way to do this somehow
          lupd.update_stripbrowser = true
          lupd.update_surface = true
        end

      elseif mouse.context == contexts.sb_dragstrip then
        if stripgallery_view == 0 then
          if CheckOver10() then

            local fn
            if lvar.stripbrowser.search == true then
              fn = strip_search[lvar.stripbrowser.select+1]
            elseif lvar.stripbrowser.favs == true then
              fn = strip_favs[lvar.stripbrowser.select+1]
            else
              fn = strip_folders[stripfol_select].fn..'/'..strip_files[lvar.stripbrowser.select].fn
            end
            if fn then
              InsStrip(fn, true)
            end
            mouse.context = contexts.sb_dragstrip2
            if insertstrip then
              insertstrip.alpha = 0
            end
            if lvar.livemode >= 1 and not lvar.popout_autoarrange then
              ShowPop(false, nil, true)
            end
            --sb_drag = nil
            lupd.update_surface = true
          end
          if sb_drag then
            sb_drag.alpha = math.min(sb_drag.alpha+0.15,0.8)
            if sb_drag.x ~= mouse.mx or sb_drag.y ~= mouse.my then
              sb_drag.x = mouse.mx
              sb_drag.y = mouse.my
              lupd.update_surface = true
            end
          end
        end

      end

    else

      if lvar.resize_stripbrowser then
        lvar.resize_stripbrowser = nil
        lupd.update_stripbrowser = true
      elseif moddraw ~= nil then
        moddraw = nil
        reaper.TrackCtl_SetToolTip('',0,0, true)

      elseif snap_move then

        if snap_move.epos ~= snap_move.spos and snap_move.epos ~= snap_move.spos+1 then
          --move ss
          Snapshot_Move(snap_move.spos, snap_move.epos)
        end

        snap_move = nil
        lupd.update_snaps = true

      elseif dragfader ~= nil then

        if dragfader.ctl and dragfader.ctl ~= -1 then

          DragFader_Assign(fader_select, dragfader.ctl)

        end

        dragfader = nil
        lupd.update_sidebar = true
        lupd.update_surface = true

      elseif dragmod ~= nil then

        if dragmod.ctl and dragmod.ctl ~= -1 then

          DragMod_Assign(mod_select, dragmod.ctl)

        end

        dragmod = nil
        lupd.update_lfoedit = true
        lupd.update_sidebar = true
        lupd.update_surface = true

      elseif dragparam ~= nil then

        if mouse.mx > obj.sections[10].x and not MOUSE_over(obj.sections[160]) then
          Strip_AddParam()
          g_savedirty = true
        end

        dragparam = nil
        lupd.update_gfx = true

      elseif sb_drag then
        sb_drag = nil
        lupd.update_surface = true

      end
    
    end

    return noscroll

  end

  function Surface_EdgeDrag()
    local zone = 25
    local max = 25
    --if not lvar.edgedrag_mult then
      lvar.edgedrag_mult = 1
    --end
    --lvar.edgedrag_mult = math.min(lvar.edgedrag_mult + 0.02, 2)
    if lvar.livemode == 0 then
      if mouse.mx < obj.sections[10].x+zone then
        local jump = math.min(10+math.floor(((obj.sections[10].x+zone)-mouse.mx)/4),max) * lvar.edgedrag_mult
        surface_offset.x = math.max(surface_offset.x-jump,0)
        lupd.update_surface = true
      elseif mouse.mx > obj.sections[10].x+obj.sections[10].w-zone then
        local jump = math.max(-10+math.floor(((obj.sections[10].x+obj.sections[10].w-zone)-mouse.mx)/4),-max) * lvar.edgedrag_mult
        surface_offset.x = math.min(surface_offset.x-jump,surface_size.w-obj.sections[10].w)
        lupd.update_surface = true
      end
      if mouse.my < obj.sections[10].y+zone then
        local jump = math.min(10+math.floor(((obj.sections[10].y+zone)-mouse.my)/4),max) * lvar.edgedrag_mult
        surface_offset.y = math.max(surface_offset.y-jump,0)
        lupd.update_surface = true
      elseif mouse.my > obj.sections[10].y+obj.sections[10].h-zone then
        local jump = math.max(-10+math.floor(((obj.sections[10].y+obj.sections[10].h-zone)-mouse.my)/4),-max) * lvar.edgedrag_mult
        surface_offset.y = math.min(surface_offset.y-jump,surface_size.h-obj.sections[10].h)
        lupd.update_surface = true
      else
        lvar.edgedrag_mult = 1
      end
    else
      if lvar.mixmodedir == 0 then
        if mouse.my < obj.sections[10].y+zone then
          local jump = math.min(10+math.floor(((obj.sections[10].y+zone)-mouse.my)/4),max) * lvar.edgedrag_mult
          surface_offset.mixy = math.max((surface_offset.mixy or 0)-jump,-math.floor(obj.sections[10].h/2))
          lupd.update_surface = true
          GUI_DrawCtlBitmap_Mix()
        elseif mouse.my > obj.sections[10].y+obj.sections[10].h-zone then
          local jump = math.max(-10+math.floor(((obj.sections[10].y+obj.sections[10].h-zone)-mouse.my)/4),-max) * lvar.edgedrag_mult
          surface_offset.mixy = (surface_offset.mixy or 0) -jump --math.min(surface_offset.mixy-jump,surface_size.h-obj.sections[10].h)
          lupd.update_surface = true
          GUI_DrawCtlBitmap_Mix()
        end
      else
        if mouse.mx < obj.sections[10].x+zone then
          local jump = math.min(10+math.floor(((obj.sections[10].x+zone)-mouse.mx)/4),max) * lvar.edgedrag_mult
          surface_offset.mixx = math.max((surface_offset.mixx or 0)-jump,0)
          lupd.update_surface = true
          GUI_DrawCtlBitmap_Mix()
        elseif mouse.mx > obj.sections[10].x+obj.sections[10].w-zone then
          local jump = math.max(-10+math.floor(((obj.sections[10].x+obj.sections[10].w-zone)-mouse.mx)/4),-max) * lvar.edgedrag_mult
          surface_offset.mixx = (surface_offset.mixx or 0) -jump --math.min(surface_offset.mixy-jump,surface_size.h-obj.sections[10].h)
          lupd.update_surface = true
          GUI_DrawCtlBitmap_Mix()
        end
      end
    end
  end

  function FSS_Click(i, ctlxywh, togfsnap)

    local ctls = strips[tracks[track_select].strip][page].controls

    local openfss

    fss_ctl = i
    local mmx = mouse.mx - ctlxywh.x
    local mmy = mouse.my - ctlxywh.y
    local ci
    local strip, switchid, swdata
    if lvar.livemode >= 1 then
      mmx, mmy = TranslateMixPos2(mouse.mx, mouse.my, i)
      mmx, mmy = mmx - ctlxywh.x, mmy - ctlxywh.y -- lvar.mmgap
    elseif stripgallery_view > 0 then
      mmx, mmy, ci = TranslateGalleryPos(mouse.mx, mouse.my, i)
      mmx, mmy = mmx - ctlxywh.x, mmy - ctlxywh.y
    end

    if ctls[i].param_info.paramnum == 1 then
      --BASIC SNAPSHOT CTL
      --open fss

      openfss = true

    elseif ctls[i].param_info.paramnum == 2 then
      --FIXED SNAPSHOT CTL

      FixedSS(i)

    else
      --ADVANCED SNAPSHOT CTL
      --local x,y = TranslateMixCtlPos(i, switchid)
      local cf = ctl_files[ctls[i].knob_select]
      local scale = ctls[i].scale
      local topsplit
      if cf.topsplit then
        topsplit = math.ceil(cf.topsplit*scale)*lvar.zoom
      end
      if mmy <= (topsplit or (ctlxywh.h)/2) then
        if mmx < ((cf.ltopsplit or 30)*scale)*lvar.zoom then
          sstype_select = ctls[i].param
          ss_select = snapshots[tracks[track_select].strip][page][sstype_select].selected
          if sstype_select and ss_select then
            OpenEB(11,'Please enter new snapshot name:')
          end
        elseif mmx > ctlxywh.w-((cf.rtopsplit or 30)*scale)*lvar.zoom then
          sstype_select = ctls[i].param
          ss_select = snapshots[tracks[track_select].strip][page][sstype_select].selected
          if sstype_select then
            local ssmatch
            if lvar.livemode == 2 and lvar.dm_checkdupsnaps then
              ssmatch = GetSnapshotMatch(sstype_select, tracks[track_select].strip, page) 
            end
            if not ssmatch then
            
              if lvar.livemode == 2 and lvar.dm_autonamesnaps and not mouse.shift then
                local def
                if sstype_select == 1 then
                  def = 'Snapshot '..string.format('%i',#snapshots[tracks[track_select].strip][page][sstype_select]+1)
                else
                  def = 'Snapshot '..string.format('%i',#snapshots[tracks[track_select].strip][page][sstype_select].snapshot+1)
                end
                OpenEB(111,'Please enter snapshot name:',def)
              else
                local ss_overwrite
                if mouse.shift then
                  ss_overwrite = ss_select
                end
                Snapshots_CREATE(tracks[track_select].strip, page, sstype_select, ss_overwrite)
                SetCtlDirty(i)
                local sctls = strips[tracks[track_select].strip][page].snapctls
                if sctls and #sctls > 0 then
                  for sn = 1, #sctls do
                    SetCtlDirty(sctls[sn])
                  end
                end
                lupd.update_snaps = true
                lupd.update_ctls = true
              end
              
            else
              local name = snapshots[tracks[track_select].strip][page][sstype_select].snapshot[ssmatch].name
              OpenMsgBox(1, 'Snapshot already exists: '..name, 1)
            end
          end
        else
          if (cf.topdialogactive or 1) == 1 then
            sstype_select = ctls[i].param
            if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select]
                                        and snapshots[tracks[track_select].strip][page][sstype_select].selected then
              ss_select = snapshots[tracks[track_select].strip][page][sstype_select].selected
  
              if settings_followsnapshot then
                local snaps = snapshots[tracks[track_select].strip][page][sstype_select]
                if ss_select < ssoffset+1 or ss_select > ssoffset+SS_butt_cnt then
                  if sstype_select == 1 then
                    ssoffset = math.max(math.min(ss_select-math.floor(SS_butt_cnt/2),#snaps-SS_butt_cnt),0)
                  else
                    ssoffset = math.max(math.min(ss_select-math.floor(SS_butt_cnt/2),#snaps.snapshot-SS_butt_cnt),0)
                  end
                  --lupd.update_snaps = true
                end
              end
  
              show_snapshots = true
              SetShowSS(show_snapshots)
              lupd.update_snaps = true
            end
          else
            openfss = true
          end
        end
      elseif mmx < (cf.lbotsplit or 20)*scale*lvar.zoom then
        local xsstype_select,xss_select
        xsstype_select = ctls[i].param
        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][xsstype_select]
                                    and snapshots[tracks[track_select].strip][page][xsstype_select].selected then
          if snapshots[tracks[track_select].strip][page][xsstype_select].selected then
            if xsstype_select == 1 then
              xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected-1
              if xss_select < 1 then
                xss_select = #snapshots[tracks[track_select].strip][page][xsstype_select]
              end
            else
              xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected-1
              if xss_select < 1 then
                xss_select = #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot
              end
            end
          else
            if xsstype_select == 1 then
              if #snapshots[tracks[track_select].strip][page][xsstype_select] > 0 then
                xss_select = 1
              end
            else
              if #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot > 0 then
                xss_select = 1
              end
            end
          end
          if xss_select then
            Snapshot_Set(tracks[track_select].strip, page, xsstype_select, xss_select)
            if xsstype_select == sstype_select then
              ss_select = xss_select
            end
            lupd.update_ctls = true
            lupd.update_snaps = true
            --lupd.update_fsnaps = true
          end
        end
      elseif mmx > ctlxywh.w-((cf.rbotsplit or 20)*scale)*lvar.zoom then
        local xsstype_select,xss_select
        xsstype_select = ctls[i].param
        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][xsstype_select]
                                    and snapshots[tracks[track_select].strip][page][xsstype_select].selected then
          if snapshots[tracks[track_select].strip][page][xsstype_select].selected then
            if xsstype_select == 1 then
              xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected+1
              if xss_select > #snapshots[tracks[track_select].strip][page][xsstype_select] then
                xss_select = 1
              end
            else
              xss_select = snapshots[tracks[track_select].strip][page][xsstype_select].selected+1
              if xss_select > #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot then
                xss_select = 1
              end
            end
          else
            if xsstype_select == 1 then
              if #snapshots[tracks[track_select].strip][page][xsstype_select] > 0 then
                xss_select = 1
              end
            else
              if #snapshots[tracks[track_select].strip][page][xsstype_select].snapshot > 0 then
                xss_select = 1
              end
            end
          end
          if xss_select then
            Snapshot_Set(tracks[track_select].strip, page, xsstype_select, xss_select)
            if xsstype_select == sstype_select then
              ss_select = xss_select
            end
            lupd.update_ctls = true
            lupd.update_snaps = true
            --lupd.update_fsnaps = true
          end
        end

      else
        --open fss
        openfss = true
        
        
      end
    end
    
    if openfss then
      togfsnap = true
      if fsstype_select == ctls[i].param then
        show_fsnapshots = not show_fsnapshots
        show_xysnapshots = false
        RedrawGUIBitmap()
      else
        show_fsnapshots = true
        show_xysnapshots = false
        RedrawGUIBitmap()
      end
      fsstype_select = ctls[i].param
      fsstype_color = ctls[i].textcolv
      if show_fsnapshots then
        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][fsstype_select]
          --[[and snapshots[tracks[track_select].strip][page][fsstype_select].selected]] then

          local w = ctls[i].wsc*lvar.zoom
          obj.sections[180].w = w--math.max(w - (170-138),138)
          obj.sections[181].w = obj.sections[180].w-6
          obj.sections[182].w = obj.sections[180].w

          fss_select = snapshots[tracks[track_select].strip][page][fsstype_select].selected or 0
          --set scroll pos
          if FSS_butt_cnt == 0 then
            FSS_butt_cnt = math.floor(obj.sections[181].h / butt_h) - 1
          end
          if fsstype_select == 1 then
            fssoffset = F_limit(fss_select-math.floor(FSS_butt_cnt/2),0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select]-FSS_butt_cnt))
          else
            fssoffset = F_limit(fss_select-math.floor(FSS_butt_cnt/2),0,math.max(0,#snapshots[tracks[track_select].strip][page][fsstype_select].snapshot-FSS_butt_cnt))
          end

          if lvar.livemode >= 1 then

            local x,y = TranslateMixCtlPos(i, switchid)
            obj.sections[180].x = F_limit(x, obj.sections[10].x,obj.sections[10].x+obj.sections[10].w-obj.sections[180].w)
            obj.sections[180].y = F_limit(y + ctls[i].hsc*lvar.zoom,obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-obj.sections[180].h)

          elseif stripgallery_view == 0 then

            obj.sections[180].x = F_limit(ctls[i].x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x +
                                          math.floor((ctls[i].w*lvar.zoom - obj.sections[180].w)/2),
                                          obj.sections[10].x,obj.sections[10].x+obj.sections[10].w-obj.sections[180].w)
            obj.sections[180].y = F_limit((ctls[i].ysc+ctls[i].hsc)*lvar.zoom
                                          - surface_offset.y*lvar.zoom  + obj.sections[10].y - 3,
                                          obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-obj.sections[180].h)
          else
            local x,y = TranslateGalleryCtlPos(i,ci)
            obj.sections[180].x = x + math.floor((ctls[i].wsc - obj.sections[180].w)/2)
            obj.sections[180].y = y + ctls[i].hsc
          end
        else
          if show_fsnapshots then
            RedrawGUIBitmap()              
          end
          show_fsnapshots = false
        end
      end
      lupd.update_fsnaps = true
      lupd.update_surface = true
    end
    
    return togfsnap
  end

  function FixedSS(i)

    local ctls = strips[tracks[track_select].strip][page].controls

    local xsstype_select = ctls[i].param
    local xss_select = tonumber(ctls[i].param_info.paramidx)
    if xss_select then
      if xsstype_select == 1 then
        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][xsstype_select]
           and snapshots[tracks[track_select].strip][page][xsstype_select][xss_select] then
          Snapshot_Set(tracks[track_select].strip, page, xsstype_select, xss_select)
          if xsstype_select == sstype_select then
            ss_select = xss_select
          end
          lupd.update_ctls = true
          lupd.update_snaps = true
        end
      else
        if snapshots and snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][xsstype_select]
           and snapshots[tracks[track_select].strip][page][xsstype_select].snapshot[xss_select] then
          Snapshot_Set(tracks[track_select].strip, page, xsstype_select, xss_select)
          if xsstype_select == sstype_select then
            ss_select = xss_select
          end
          lupd.update_ctls = true
          lupd.update_snaps = true
        end
      end
    end

  end

  function CreateStripCB(force)

    if strips and tracks[track_select] and strips[tracks[track_select].strip] then
      local strip = tracks[track_select].strip
      local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)
      if stripidx then
        local lvar = lvar
        if lvar.stripctlbox.idx ~= stripidx or force then
          lvar.stripctlbox = {idx = stripidx, id = stripid}
          local iw, ih = gfx.getimgdim(skin.stripctlbtnsX)
          lvar.stripctlboxX = {}
          if stripgallery_view == 0 then
            lvar.stripctlbox.x = lvar.stripdim.data[stripidx].l * lvar.zoom
            lvar.stripctlbox.y = lvar.stripdim.data[stripidx].t * lvar.zoom
            lvar.stripctlboxX.x = (lvar.stripdim.data[stripidx].r) * lvar.zoom - iw
            lvar.stripctlboxX.y = (lvar.stripdim.data[stripidx].t) * lvar.zoom

            if lvar.stripctlboxX.x < lvar.stripctlbox.x + iw then
              lvar.stripctlboxX.x = lvar.stripctlbox.x
              lvar.stripctlboxX.y = lvar.stripctlbox.y + ih
            end
          elseif stripgallery_view > 0 then

            local mmx, mmy, idx = TranslateGalleryPos2(0, 0, stripid)
            lvar.stripctlbox.x = math.floor(mmx)
            lvar.stripctlbox.y = math.floor(mmy)
            lvar.stripctlboxX.x = math.floor(mmx)+lvar.stripdim.data[stripidx].r-lvar.stripdim.data[stripidx].l - iw
            lvar.stripctlboxX.y = math.floor(mmy)

          end
          lvar.stripctlbox.w, lvar.stripctlbox.h = gfx.getimgdim(skin.stripctlbtns)
          lvar.stripctlboxX.w, lvar.stripctlboxX.h = iw, ih
          lvar.stripctlbox.overstrip = {x = lvar.stripdim.data[stripidx].l,
                                        y = lvar.stripdim.data[stripidx].t,
                                        w = lvar.stripdim.data[stripidx].r-lvar.stripdim.data[stripidx].l,
                                        h = lvar.stripdim.data[stripidx].b-lvar.stripdim.data[stripidx].t}
          lupd.update_surface = true
        end
        if c and lvar.stripctlbox.idx == stripidx and (lvar.stripctlbox.ctl == nil or c ~= lvar.stripctlbox.ctl.ctl) then
          lvar.stripctlbox.ctl = {ctl = c}
          if stripgallery_view == 0 then
            local ctl = strips[strip][page].controls[c]
            local iw, ih = gfx.getimgdim(skin.stripctlbtnslock)
            lvar.stripctlbox.ctl.x = math.floor(ctl.xsc*lvar.zoom) + math.floor((ctl.wsc/2)*lvar.zoom - iw/2)
            lvar.stripctlbox.ctl.y = math.floor(ctl.ysc*lvar.zoom + ctl.hsc*lvar.zoom) -2
            lvar.stripctlbox.ctl.w = iw
            lvar.stripctlbox.ctl.h = ih
            lupd.update_surface = true
          end
        end
      elseif lvar.stripctlbox.idx then
        lvar.stripctlbox = {}
        lupd.update_surface = true
      end
    end

  end

  function A_Run_CBox()

    local mx, my = mouse.mx, mouse.my
    mouse.mx = mx - obj.sections[3000].x
    mouse.my = my - obj.sections[3000].y

    if mouse.ctrl and MOUSE_click(obj.sections[3001]) then

      settings_gridsize = settings_gridsize +1
      ogrid = settings_gridsize
      lupd.update_gfx = true

    elseif mouse.alt and MOUSE_click(obj.sections[3001]) then

      if tonumber(settings_gridsize) ~= 1 then
        lvar.grid = false
        settings_gridsize = 1
      else
        lvar.grid = true
        settings_gridsize = ogrid
      end
      lupd.update_gfx = true

    elseif not mouse.ctrl and MOUSE_click(obj.sections[3001]) then

      settings_gridsize = math.min(settings_gridsize * 2,256)
      ogrid = settings_gridsize
      lupd.update_gfx = true

    elseif mouse.ctrl and MOUSE_click_RB(obj.sections[3001]) then

      settings_gridsize = settings_gridsize -1
      ogrid = settings_gridsize
      lupd.update_gfx = true

    elseif not mouse.ctrl and MOUSE_click_RB(obj.sections[3001]) then

      settings_gridsize = math.max(math.floor(settings_gridsize / 2),1)
      ogrid = settings_gridsize
      lupd.update_gfx = true

    elseif MOUSE_click(obj.sections[3007]) then

      if tonumber(settings_gridsize) ~= 1 then
        lvar.grid = false
        settings_gridsize = 1
      else
        lvar.grid = true
        settings_gridsize = ogrid
      end
      lupd.update_gfx = true

    elseif MOUSE_click(obj.sections[3003]) then

      if submode == 0 then
        if ctl_select then
          local c = lvar.ctlpreview_sel or ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          if ctl then
            OpenEB(3003,'Please enter X coordinate:',ctl.xsc)
          end
        end
      elseif submode == 1 then
        if gfx4_select then
          local c = gfx4_select[1]
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          if ctl then
            OpenEB(3003,'Please enter X coordinate:',ctl.x)
          end
        end
      end

    elseif MOUSE_click(obj.sections[3004]) then

      if submode == 0 then
        if ctl_select then
          local c = lvar.ctlpreview_sel or ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          if ctl then
            OpenEB(3004,'Please enter Y coordinate:',ctl.ysc)
          end
        end
      elseif submode == 1 then
        if gfx4_select then
          local c = gfx4_select[1]
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          if ctl then
            OpenEB(3004,'Please enter Y coordinate:',ctl.y)
          end
        end
      end

    elseif MOUSE_click(obj.sections[3005]) then

      if submode == 0 then
        if ctl_select then
          local c = lvar.ctlpreview_sel or ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          if ctl then
            OpenEB(3005,'Please enter W (pixels):',ctl.wsc)
          end
        end
      elseif submode == 1 then
        if gfx4_select then
          local c = gfx4_select[1]
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          if ctl then
            OpenEB(3005,'Please enter W (pixels):',ctl.stretchw)
          end
        end
      end

    elseif MOUSE_click(obj.sections[3006]) then

      if submode == 0 then
        if ctl_select then
          local c = lvar.ctlpreview_sel or ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          if ctl then
            OpenEB(3006,'Please enter H (pixels):',ctl.hsc)
          end
        end
      elseif submode == 1 then
        if gfx4_select then
          local c = gfx4_select[1]
          local ctl = strips[tracks[track_select].strip][page].graphics[c]
          if ctl then
            OpenEB(3006,'Please enter H (pixels):',ctl.stretchh)
          end
        end
      end

    elseif MOUSE_click(obj.sections[3002]) then

      if submode == 0 then
        if ctl_select then
          local c = lvar.ctlpreview_sel or ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[c]
          if ctl then
            OpenEB(3002,'Please enter scale:',ctl.scale)
          end
        end
      end

    elseif MOUSE_click(obj.sections[3100]) then

      CtlSelect_AlignTop()

    elseif MOUSE_click(obj.sections[3110]) then

      CtlSelect_AlignBottom()

    elseif MOUSE_click(obj.sections[3101]) then

      CtlSelect_AlignLeft()

    elseif MOUSE_click(obj.sections[3111]) then

      CtlSelect_AlignRight()

    elseif MOUSE_click(obj.sections[3112]) then

      CtlSelect_AlignCentreH()

    elseif MOUSE_click(obj.sections[3113]) then

      CtlSelect_AlignCentreV()

    elseif MOUSE_click(obj.sections[3102]) then

      Distribute_Vert()

    elseif MOUSE_click(obj.sections[3103]) then

      Distribute_Horiz()

    elseif MOUSE_click(obj.sections[3104]) then

      Copy_Selected()

    elseif MOUSE_click_RB(obj.sections[3105]) then
    
      PasteSpecial_Menu(mx, my)
    
    elseif MOUSE_click(obj.sections[3105]) then

      local keep_coords
      if mouse.shift then
        keep_coords = true
      end
      Paste_Selected(keep_coords)
      SetCtlBitmapRedraw()
      ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      lupd.update_gfx = true

    elseif MOUSE_click(obj.sections[3106]) then

      lvar.locky = false
      lvar.lockx = not (lvar.lockx or false)
      lupd.update_cbox = true

    elseif MOUSE_click(obj.sections[3107]) then

      lvar.lockx = false
      lvar.locky = not (lvar.locky or false)
      lupd.update_cbox = true

    elseif MOUSE_click(obj.sections[3108]) then

      if undo.max > 0 and undo_pos > 0 then
        undo_pos = Undo_Recall(undo_pos)
        lupd.update_cbox = true
      end

    elseif MOUSE_click(obj.sections[3109]) then
      if undo.max > 0 and undo[undo_pos+1] then
        undo_pos = Undo_Redo(undo_pos+1)
        lupd.update_cbox = true
      end

    end
    mouse.mx, mouse.my = mx, my

  end

  function InfoCtl_INIT(v)

    if v == 2 then
      return {closefx = false, positionfx = false}
    end

  end

  function CP4_InfoCtl()

    if mouse.context == nil then
      local mx, my = mouse.mx + obj.sections[45].x, mouse.my + obj.sections[45].y
      local strip = tracks[track_select].strip
      local cctl = strips[strip][page].controls[ctl_select[1].ctl]

      if MOUSE_click(obj.sections[8020]) then
        InfoCtlMenu(mx, my)
        lupd.update_ctlopts = true
      elseif cctl.param == 2 and MOUSE_click(obj.sections[8021]) then
        local ctls = strips[strip][page].controls
        for c = 1, #ctl_select do
          local ctl = ctls[ctl_select[c].ctl]
          if ctl and ctl.ctlcat == ctlcats.infoctl and ctl.param == 2 then
            if not ctl.infoctl or ctl.infoctl.closefx == nil then
              ctl.infoctl = InfoCtl_INIT(2)
            end
            ctl.infoctl.closefx = not ctl.infoctl.closefx
          end
        end
        lupd.update_ctlopts = true

      elseif cctl.param == 2 and MOUSE_click(obj.sections[8022]) then
        local ctls = strips[strip][page].controls
        for c = 1, #ctl_select do
          local ctl = ctls[ctl_select[c].ctl]
          if ctl and ctl.ctlcat == ctlcats.infoctl and ctl.param == 2 then
            if not ctl.infoctl or ctl.infoctl.positionfx == nil then
              ctl.infoctl = InfoCtl_INIT(2)
            end
            ctl.infoctl.positionfx = not ctl.infoctl.positionfx
          end
        end
        lupd.update_ctlopts = true

      elseif cctl.param == 2 and MOUSE_click(obj.sections[8023]) then
        SetFXPosBoundary()
      end
    end

  end

  function SetFXPosBoundary()

    local str = lvar.fxpos.l .. ',' .. lvar.fxpos.t .. ',' .. lvar.fxpos.w .. ',' .. lvar.fxpos.h
    local ret,retcsv = reaper.GetUserInputs('FX Position Boundary',4,'left,top,width,height',str)
    if ret then
      local vals = split2(retcsv,',')
      local l,t,w,h = vals[1],vals[2],vals[3],vals[4]
      if tonumber(l) and tonumber(t) and tonumber(w) and tonumber(h) then
        lvar.fxpos = {l = tonumber(l), t = tonumber(t), w = tonumber(w), h = tonumber(h)}

        SaveSettings()        
      end
      lupd.update_gfx = true
    end

  end

  function CP4_Action()

    if mouse.context == nil then
      local mx, my = mouse.mx + obj.sections[45].x, mouse.my + obj.sections[45].y

      if MOUSE_click(obj.sections[8004]) then

        AssActionFromList()

      elseif MOUSE_click(obj.sections[8006]) then

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        for c = 1, #ctl_select do
          local ctl = ctls[ctl_select[c].ctl]
          if ctl and ctl.ctlcat == ctlcats.action then
            if ctl.monext then
              ctl.monext = nil
            else
              ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
            end
          end
        end
        lupd.update_ctlopts = true

      elseif MOUSE_click(obj.sections[8007]) then

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local retval, csv = reaper.GetUserInputs('Action Trigger',1,'Enter ExtState Section:','')
          if retval then

            for c = 1, #ctl_select do
              local ctl = ctls[ctl_select[c].ctl]
              if ctl and ctl.ctlcat == ctlcats.action then
                if not ctl.monext then
                  ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
                end
                ctl.monext.section = csv
              end
            end
            lupd.update_ctlopts = true

          end
        end

      elseif MOUSE_click(obj.sections[8008]) then

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local retval, csv = reaper.GetUserInputs('Action Trigger',1,'Enter ExtState Key:','')
          if retval then

            for c = 1, #ctl_select do
              local ctl = ctls[ctl_select[c].ctl]
              if ctl and ctl.ctlcat == ctlcats.action then
                if not ctl.monext then
                  ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
                end
                ctl.monext.key = csv
              end
            end
            lupd.update_ctlopts = true

          end
        end

      elseif MOUSE_click(obj.sections[8009]) then
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local range_val
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            if ctl and ctl.ctlcat == ctlcats.action then
              if not ctl.monext then
                ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
              end
              if c == 1 then
                range_val = ctl.monext.range_start + 1
              end
              ctl.monext.range_start = range_val
              if ctl.monext.range_start >= ctl.monext.range_end then
                ctl.monext.range_end = ctl.monext.range_start+1
              end
            end
          end
          lupd.update_ctlopts = true
        end

      elseif MOUSE_click_RB(obj.sections[8009]) then
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local range_val
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            if ctl and ctl.ctlcat == ctlcats.action then
              if not ctl.monext then
                ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
              end
              if c == 1 then
                range_val = ctl.monext.range_start - 1
              end
              ctl.monext.range_start = range_val
              if ctl.monext.range_start >= ctl.monext.range_end then
                ctl.monext.range_end = ctl.monext.range_start+1
              end
            end
          end
          lupd.update_ctlopts = true
        end

      elseif MOUSE_click(obj.sections[8010]) then
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local range_val
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            if ctl and ctl.ctlcat == ctlcats.action then
              if not ctl.monext then
                ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
              end
              if c == 1 then
                range_val = ctl.monext.range_end + 1
              end
              ctl.monext.range_end = range_val
              if ctl.monext.range_end <= ctl.monext.range_start then
                ctl.monext.range_start = ctl.monext.range_end-1
              end
            end
          end
          lupd.update_ctlopts = true
        end

      elseif MOUSE_click_RB(obj.sections[8010]) then
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls

        if ctls[ctl_select[1].ctl].monext then
          local range_val
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            if ctl and ctl.ctlcat == ctlcats.action then
              if not ctl.monext then
                ctl.monext = {section = '', key = '', range_start = 0, range_end = 1}
              end
              if c == 1 then
                range_val = ctl.monext.range_end - 1
              end
              ctl.monext.range_end = range_val
              if ctl.monext.range_end <= ctl.monext.range_start then
                ctl.monext.range_start = ctl.monext.range_end-1
              end
            end
          end
          lupd.update_ctlopts = true
        end
      end

    end

  end

  function CP4_NaviCtl()

    if mouse.context == nil then
      local mx, my = mouse.mx + obj.sections[45].x, mouse.my + obj.sections[45].y

      if MOUSE_click(obj.sections[8001]) then

        local mstr = 'Strip/Page|Location||Edit Mode'
        gfx.x = mx
        gfx.y = my
        local res = gfx.showmenu(mstr)
        if res > 0 then
          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            if ctl and ctl.ctlcat == ctlcats.navictl then
              ctl.param = res
            end
          end
          lupd.update_ctlopts = true
        end

      elseif MOUSE_click(obj.sections[8002]) then

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local ctl1 = ctls[ctl_select[1].ctl]
        if ctl1.param ~= 3 then

          local mstr = 'No Change||Previous Strip|Next Strip||Specific Strip'
          gfx.x = mx
          gfx.y = my
          local res = gfx.showmenu(mstr)
          if res > 0 then
            local val,tguid
            if res == 1 then
              val = -4
            elseif res == 2 then
              val = -3
            elseif res == 3 then
              val = -2
            else
              local ctl = ctls[ctl_select[1].ctl]
              local retval, v = reaper.GetUserInputs('Navigate Control',1,'Please enter track number:','')
              if retval then
                val = tonumber(v)
              end
            end
            if val then
              --get track details
              if val > -2 then
                local tr = GetTrack(val)
                if tr then
                  tguid = GetTrackGUID(tr)
                end
              end
              for c = 1, #ctl_select do
                local ctl = ctls[ctl_select[c].ctl]
                if ctl and ctl.ctlcat == ctlcats.navictl then
                  ctl.param_info.paramnum = val
                  ctl.param_info.paramstr = tguid
                end
              end
              lupd.update_ctlopts = true
            end
          end
        end

      elseif MOUSE_click(obj.sections[8003]) then

        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        local ctl1 = ctls[ctl_select[1].ctl]
        if ctl1.param ~= 3 then

          local mstr = 'No Change||Previous Page|Next Page|Global Page||Page 1|Page 2|Page 3|Page 4'
          gfx.x = mx
          gfx.y = my
          local res = gfx.showmenu(mstr)
          if res > 0 then
            local val
            if res == 1 then
              val = -4
            elseif res == 2 then
              val = -3
            elseif res == 3 then
              val = -2
            elseif res == 4 then
              val = -1
            else
              local ctl = ctls[ctl_select[1].ctl]
              val = res-4
            end
            if val then
              --get track details
              for c = 1, #ctl_select do
                local ctl = ctls[ctl_select[c].ctl]
                if ctl and ctl.ctlcat == ctlcats.navictl then
                  ctl.param_info.paramidx = val
                end
              end
              lupd.update_ctlopts = true
            end
          end
        end
      end
    end

  end

  function Adjust_Disable(v)
  
    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    for c = 1, #ctl_select do
      local ctl = ctls[ctl_select[c].ctl]
      ctl.adjust_active = v or 0
      SetCtlDirty(ctl_select[c].ctl)
    end
    adjust_active_select = v or 0
    lupd.update_ctls = true
    lupd.update_ctlopts = true
  
  end

  function ARun_CtlPage4()
    if ctl_select == nil then return end

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    local ccat = ctls[ctl_select[1].ctl].ctlcat

    if mouse.context == nil then
      if MOUSE_click(obj.sections[8050]) then

        if mouse.ctrl then
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            ctl.adjust.bright = 255
            SetCtlDirty(ctl_select[c].ctl)
          end
          adjust_bright_select = 255
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        else
          if ctls[ctl_select[1].ctl].adjust_active ~= 1 then
            Adjust_Disable(1)
          else
            Undo_Set({'adjust'})
            mouse.context = contexts.adjust_bright
          end
        end
        
      elseif MOUSE_click(obj.sections[8051]) then

        if mouse.ctrl then
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            ctl.adjust.contrast = 255
            SetCtlDirty(ctl_select[c].ctl)
          end
          adjust_contrast_select = 255
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        else
          if ctls[ctl_select[1].ctl].adjust_active ~= 1 then
            Undo_Set({'adjust','adjust_active'})
            Adjust_Disable(1)
          else
            Undo_Set({'adjust'})
            mouse.context = contexts.adjust_contrast
          end
        end

      elseif MOUSE_click(obj.sections[8052]) then
      
        if mouse.ctrl then
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            ctl.adjust.r = 255
            SetCtlDirty(ctl_select[c].ctl)
          end
          adjust_r_select = 255
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        else
          if ctls[ctl_select[1].ctl].adjust_active ~= 1 then
            Undo_Set({'adjust','adjust_active'})
            Adjust_Disable(1)
          else
            Undo_Set({'adjust'})
            mouse.context = contexts.adjust_r
          end
        end

      elseif MOUSE_click(obj.sections[8053]) then
      
        if mouse.ctrl then
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            ctl.adjust.g = 255
            SetCtlDirty(ctl_select[c].ctl)
          end
          adjust_g_select = 255
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        else
          if ctls[ctl_select[1].ctl].adjust_active ~= 1 then
            Undo_Set({'adjust','adjust_active'})
            Adjust_Disable(1)
          else
            Undo_Set({'adjust'})
            mouse.context = contexts.adjust_g
          end
        end
      
      elseif MOUSE_click(obj.sections[8054]) then
      
        if mouse.ctrl then
          for c = 1, #ctl_select do
            local ctl = ctls[ctl_select[c].ctl]
            ctl.adjust.b = 255
            SetCtlDirty(ctl_select[c].ctl)
          end
          adjust_b_select = 255
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        else
          if ctls[ctl_select[1].ctl].adjust_active ~= 1 then
            Undo_Set({'adjust','adjust_active'})
            Adjust_Disable(1)
          else
            Undo_Set({'adjust'})
            mouse.context = contexts.adjust_b
          end
        end
        
      elseif MOUSE_click_RB(obj.sections[8050]) then
        Adjust_Disable()
        
      elseif MOUSE_click_RB(obj.sections[8051]) then
        Adjust_Disable()
        
      elseif MOUSE_click_RB(obj.sections[8052]) then
        Adjust_Disable()

      elseif MOUSE_click_RB(obj.sections[8053]) then
        Adjust_Disable()
      
      elseif MOUSE_click_RB(obj.sections[8054]) then
        Adjust_Disable()
      
      elseif lvar.CP4Funcs[ccat] then
        local CP4_func = lvar.CP4Funcs[ccat].click
        if CP4_func then CP4_func() end
      end
    end
  end

  function CPM_SwitchPageData(ctls)
  
    local mstr = 'Clear|'
    local data = {}
    
    local tsp = cycle_select[cycle_select.selected].tsp
    
    for c = 1, #ctls do
      if ctls[c].ctlcat == ctlcats.switcher then
        local swid = ctls[c].switcherid
        if swid and switchers[swid].switchmode ~= 1 then
          local sw_name
          local ctl = ctls[c]
          if (ctl.ctlname_override or '') ~= '' then
            sw_name = ctl.ctlname_override
          else
            sw_name = ctl.param_info.paramname
          end
          local pages = #switchers[swid].grpids
          if pages > 0 then
            for p = 1, pages do
              
              local sw_pname = switchers[swid].grpids[p].name
              local sw_pid = switchers[swid].grpids[p].id
              
              local t = ''
              if tsp then
                if tsp.swid == swid and tsp.grpid == sw_pid then
                  t = '!'
                end
              end
              
              mstr = mstr .. '|' ..t .. sw_name .. ' > ' .. sw_pname
              data[#data+1] = {ctl = ctl.id, c = c, swid = swid, grpid = sw_pid}
            
            end
          end
        end
      end
    end
    return mstr, data
  end

  function CyclePos_Menu()

    local strip = tracks[track_select].strip
    local ctls = strips[strip][page].controls
    
    local mstr2, data = CPM_SwitchPageData(ctls)
    local mstr
    if #data == 0 then
      mstr = 'Rename||Delete||Create Radio Button|Create All Radio Buttons||#>Trigger Switcher Page'
    else
      local tsp = ''
      if cycle_select[cycle_select.selected].tsp then
        tsp = '!'
      end
      mstr = 'Rename||Delete||Create Radio Button|Create All Radio Buttons||>'..tsp..'Trigger Switcher Page|'..mstr2
    end
    gfx.x, gfx.y = mouse.mx, mouse.my
    local res = OpenMenu(mstr)
    if res == 1 then
      --txt = EditValue(10)
      OpenEB(10,'Please enter value:')
    elseif res == 2 then
      cycle_select = Cycle_DeleteStep(cycle_select.selected)
      lupd.update_gfx = true
    elseif res == 3 then
    
      if cycle_select.statecnt > 0 then
        local c = ctl_select[1].ctl
        Cycle_CreateRadioButton(c)
        ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
      end
    
    elseif res == 4 then
    
      if cycle_select.statecnt > 0 then
        local c = ctl_select[1].ctl
        local ctl = ctls[c]
        if ctl then
          local ch = ctl.ctl_info.cellh
          local dx, dy = 0, ch
          for i = 1, cycle_select.statecnt do
            cycle_select.selected = i
    
            Cycle_CreateRadioButton(c,dx,dy)
            dy = dy + ch
          end
          ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
        end
      end
    elseif res > 4 and res <= 5+#data then
      
      local i = res - 5
      if i == 0 then
        cycle_select[cycle_select.selected].tsp = nil
      else
        cycle_select[cycle_select.selected].tsp = {swid = data[i].swid,
                                                   grpid = data[i].grpid}
      end
    end
  end
  
  function Gauge_EditLabel(txt)
  
    local gtab = gauge_select
    if gtab.vals and #gtab.vals > 0 and gauge_ticksel and gauge_ticksel <= #gtab.vals then
      gtab.vals[gauge_ticksel].dover = txt
      lupd.update_surface = true
    end
    
  end
  
  function ClearSelected(ctl_select, gfx_select, gfx4_select)
    UnhideCtls()
    ctl_select = nil
    gfx_select = nil
    gfx4_select = nil
  end
  
  function WheelContext()
  
    if gfx.mouse_wheel == 0 then
      lvar.wheelcnt = (lvar.wheelcnt or 0) + 1  
    else
      lvar.wheelcnt = 0
    end
    if lvar.wheelcnt > 12 then
      UnhideCtls()
      wheelcontext = nil
      dragctl = nil
      draggfx2 = nil
      lupd.update_gfx = true
      lvar.wheelcnt = 0
    end
  
  end
  
  function GetKnobSensMult(val)
    local res, val = reaper.GetUserInputs('Sensitivity Multiplier',1,'Multiplier:',tostring(val))
    if res and tonumber(val) then
      return F_limit(tonumber(val),0.01,10)
    end
  end
  
  function A_Run_Submode0(noscroll, rt, char)
  
    local contexts = contexts
    local mouse = mouse
    local lvar = lvar
    local lupd = lupd

    --[[if keycontext ~= nil and gfx_keydragtimer and gfx_keydragtimer < reaper.time_precise() then
      ArrowKey_Shift(0,ctl_select,gfx3_select)
      gfx_keydragtimer = nil
    elseif keycontext ~= nil and char == 0 and not gfx_keydragtimer then
      gfx_keydragtimer = reaper.time_precise() + 0.3
    elseif gfx_keydragtimer and char ~= 0 then
      gfx_keydragtimer = nil
    end]]

    --DBG(tostring(ctl_select)..'  '..tostring(lvar.ctlshidden))
    --[[if ctl_select == nil and lvar.ctlshidden then
      DBG('XXX')
      UnhideCtls()
      gfx.setimgdim(1022,-1,-1)
      dragctl = nil
      dragoff = nil
    end]]

    if knob_select ~= lvar.oks then
      lupd.update_sidebar = true
      lvar.oks = knob_select
    end

    if wheelcontext then
      WheelContext()
    end

    if stripswitch_droploc then

      noscroll = true
      navigate = false

      if mouse.context == nil then
        mouse.context = contexts.dummy
      end

      local xx = math.floor(((mouse.mx -obj.sections[10].x + surface_offset.x*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize
                      - surface_offset.x + obj.sections[10].x
      local yy = math.floor(((mouse.my -obj.sections[10].y + surface_offset.y*lvar.zoom)/lvar.zoom)/settings_gridsize)*settings_gridsize
                      - surface_offset.y + obj.sections[10].y
      stripswitch_droploc.x = xx
      stripswitch_droploc.y = yy
      lupd.update_surface = true

      if (stripswitch_droploc.drag == true and mouse.context ~= contexts.swdrop) or MOUSE_click(obj.sections[10]) then

        local x = math.floor((xx - obj.sections[10].x) + surface_offset.x)
        local y = math.floor((yy - obj.sections[10].y) + surface_offset.y)

        local ctl = strips[tracks[track_select].strip][page].controls[stripswitch_droploc.c]
        local switchid = ctl.switcherid
        if not switchers[switchid] then


        end

        local dx = x-ctl.xsc
        local dy = y-ctl.ysc

        switchers[switchid].dropx = dx
        switchers[switchid].dropy = dy

        navigate = true
        stripswitch_droploc = nil
        lupd.update_surface = true
      end

    elseif mouse.context == nil and MOUSE_over(obj.sections[520]) then
      lvar.ctlpreview_img = nil
      lvar.ctlpreview_sel = nil
      lupd.update_surface = true

    elseif mouse.context == nil and MOUSE_over(obj.sections[522]) then
      local i = math.floor((mouse.my - obj.sections[522].y) / tb_butt_h)-1
      if fxmode == 0 then
        if lvar.ctlpreview_i ~= plist_offset + i then
          lvar.ctlpreview_i = plist_offset + i
          lupd.update_surface = true
        end
      elseif fxmode == 1 then
        if lvar.ctlpreview_i ~= trctlslist_offset + i then
          lvar.ctlpreview_i = trctlslist_offset + i
          lupd.update_surface = true
        end
      end
      if knob_select ~= lvar.ctlpreview_img then
        lvar.ctlpreview_img = knob_select
        lupd.update_surface = true
      end
    elseif lvar.ctlpreview_img ~= nil then
      lvar.ctlpreview_img = nil
      lupd.update_surface = true
    end

    if show_actionchooser then

      if gfx.mouse_wheel ~= 0 then
        local v = (mousewheel_val())*3
        if MOUSE_over(obj.sections[171]) then
            al_offset = F_limit(al_offset - v, 0, #action_tblF-1)
            lupd.update_actcho = true
            gfx.mouse_wheel = 0
        end
      end

      if mouse.context == nil and MOUSE_click(obj.sections[171]) then
        local i = math.floor((mouse.my-obj.sections[171].y)/butt_h) +1
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
          --double-click
          if al_select and action_tblF[al_select] then
            strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramname = action_tblF[al_select].command_desc
            strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramidx = action_tblF[al_select].command_id
            strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramnum = action_tblF[al_select].dcommand_id

            CloseActChooser()
            lupd.update_gfx = true
          end

        elseif action_tblF[i + al_offset] then
          al_select = i + al_offset
        end
        lupd.update_actcho = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[172]) then

        OpenEB(14,'Please enter action command filter:')

      elseif mouse.context == nil and MOUSE_click(obj.sections[173]) then

        action_tblF = table.copy(action_tbl)
        al_offset = 0
        al_select = 0
        lupd.update_actcho = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[174]) then

        if al_select and action_tblF[al_select] then
          local cmdid = action_tblF[al_select].command_id
          local d, d2, d3 = AssAction_GetNameFromID2(cmdid)
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramname = d2 or action_tblF[al_select].command_desc
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramidx = action_tblF[al_select].command_id
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramnum = action_tblF[al_select].dcommand_id
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramstr = d3
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].param_info.paramstr2 = d2

          CloseActChooser()
          lupd.update_gfx = true

        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[175]) then

        CloseActChooser()

      end

    elseif show_gaugeedit then

      if gfx.mouse_wheel ~= 0 then
        local v = (mousewheel_val())
        if MOUSE_over(obj.sections[809]) then
            gauge_select.x_offs = F_limit(math.floor(gauge_select.x_offs+v),-30,30)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[810]) then
            gauge_select.y_offs = F_limit(math.floor(gauge_select.y_offs-v),-30,30)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[802]) then
            gauge_select.radius = F_limit(gauge_select.radius+v*0.5,10,150)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[803]) then
            gauge_select.arclen = F_limit(gauge_select.arclen+v*0.01,0,1)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[804]) then
            gauge_select.rotation = F_limit(gauge_select.rotation+v*0.01,0,1)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[805]) then
            --gauge_select.ticks = F_limit(gauge_select.ticks + v,0,50)
            --Gauge_CalcTickVals()
            --lupd.update_surface = true
            --gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[807]) then
            gauge_select.tick_size = F_limit(gauge_select.tick_size+v,2,12)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[808]) then
            gauge_select.tick_offs = F_limit(gauge_select.tick_offs+v,0,12)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[814]) then
            gauge_select.fontsz = F_limit(gauge_select.fontsz+v,-8,0)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[825]) then
            gauge_select.val_freq = F_limit(gauge_select.val_freq+v,1,24)
            lupd.update_surface = true
            gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[830]) then
          if gauge_select.vals and gauge_ticksel and gauge_select.vals[gauge_ticksel] then
            if gauge_select.vals[gauge_ticksel].nudge == nil then
              gauge_select.vals[gauge_ticksel].nudge = 0
            end
            gauge_select.vals[gauge_ticksel].nudge = F_limit(gauge_select.vals[gauge_ticksel].nudge+v,-10,10)
          end
          lupd.update_surface = true
          gfx.mouse_wheel = 0
        end
      end

      if mouse.context == nil and mouse.LB and mouse.mx >= obj.sections[800].x and mouse.mx <= obj.sections[800].x+obj.sections[800].w
         and mouse.my >= obj.sections[800].y and mouse.my <= obj.sections[800].y+butt_h then
        movegaugeed = {dx = mouse.mx - obj.sections[800].x, dy = mouse.my - obj.sections[800].y}
        mouse.context = contexts.move_gaugeed
      end

      if mouse.context == nil and MOUSE_click(obj.sections[802]) then mouse.context = contexts.gauge_arcrad
      elseif mouse.context == nil and MOUSE_click(obj.sections[820]) then
        local gtab = gauge_select
        local retval, c = reaper.GR_SelectColor(_,ConvertColorString(gtab.col_arc))
        if retval ~= 0 then
          if lvar.Mac_revcol then c = MacRevC(c) end
          gtab.col_arc = ConvertColor(c)
          lupd.update_surface = true
        end
      elseif mouse.context == nil and MOUSE_click(obj.sections[821]) then
        local gtab = gauge_select
        local retval, c = reaper.GR_SelectColor(_,ConvertColorString(gtab.col_tick))
        if retval ~= 0 then
          if lvar.Mac_revcol then c = MacRevC(c) end
          gtab.col_tick = ConvertColor(c)
          lupd.update_surface = true
        end
      elseif mouse.context == nil and MOUSE_click(obj.sections[822]) then
        local gtab = gauge_select
        local retval, c = reaper.GR_SelectColor(_,ConvertColorString(gtab.col_val))
        if retval ~= 0 then
          if lvar.Mac_revcol then c = MacRevC(c) end
          gtab.col_val = ConvertColor(c)
          lupd.update_surface = true
        end
      elseif mouse.context == nil and MOUSE_click(obj.sections[803]) then mouse.context = contexts.gauge_arclen
      elseif mouse.context == nil and MOUSE_click(obj.sections[804]) then mouse.context = contexts.gauge_arcrot
      elseif mouse.context == nil and MOUSE_click(obj.sections[806]) then mouse.context = contexts.gauge_val
        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[ctl_select[1].ctl]
        local gtab = gauge_select

        local ctly = obj.sections[806].y+obj.sections[806].h/2
        mouse.slideoff = ctly - mouse.my
        ctlpos = ctlScaleInv(nz(ctl.scalemode,8),
                                gtab.val)
        oms = mouse.shift
        gaugeglob = {ctly = ctly, sec = obj.sections[806], offset = mouse.slideoff}

      elseif mouse.context == nil and MOUSE_click(obj.sections[807]) then mouse.context = contexts.gauge_tksz
      elseif mouse.context == nil and MOUSE_click(obj.sections[808]) then mouse.context = contexts.gauge_tkoffs
      elseif mouse.context == nil and MOUSE_click(obj.sections[809]) then mouse.context = contexts.gauge_xoffs
      elseif mouse.context == nil and MOUSE_click(obj.sections[810]) then mouse.context = contexts.gauge_yoffs
      elseif mouse.context == nil and MOUSE_click(obj.sections[814]) then mouse.context = contexts.gauge_fs
      elseif mouse.context == nil and MOUSE_click(obj.sections[825]) then mouse.context = contexts.gauge_valfreq
      elseif mouse.context == nil and MOUSE_click(obj.sections[830]) then mouse.context = contexts.gauge_nudge
      elseif mouse.context == nil and MOUSE_click(obj.sections[816]) then mouse.context = contexts.auto_delayslider

      elseif mouse.context == nil and MOUSE_click(obj.sections[831]) then
        if fontlist then
          OpenFontList(mouse.mx, mouse.my, 10)
          --[[local fnt = ChooseFontMenu(mouse.mx,mouse.my)
          if fnt then
            local f = CheckFont(fnt)
            if f then
              gauge_select.font = f
            end
            lupd.update_gfx = true
          end]]
        else
          OpenEB(61,'Please enter font name:')
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[831]) then
        UpdateFontList(mouse.mx,mouse.my)
        
      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[830]) then
        if gauge_select.vals and gauge_ticksel and gauge_select.vals[gauge_ticksel] then
          gauge_select.vals[gauge_ticksel].nudge = 0
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[811]) then
        gauge_select.show_arc = not gauge_select.show_arc
        lupd.update_surface = true
      elseif mouse.context == nil and MOUSE_click(obj.sections[812]) then
        gauge_select.tick_shape = gauge_select.tick_shape + 1
        if gauge_select.tick_shape == 3 then
          gauge_select.tick_shape = 0
        end
        if gauge_select.tick_shape > 0 then
          gauge_select.show_tick = true
        else
          gauge_select.show_tick = false
        end
        lupd.update_surface = true
      elseif mouse.context == nil and MOUSE_click(obj.sections[813]) then
        gauge_select.show_val = not gauge_select.show_val
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[805]) then
        gauge_select.ticks = F_limit(gauge_select.ticks + 1,0,50)
        Gauge_CalcTickVals()
        lupd.update_surface = true
      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[805]) then
        if gauge_select.vals and #gauge_select.vals > 0 then
          gauge_select.vals[#gauge_select.vals] = nil
        end
        gauge_select.ticks = #gauge_select.vals --F_limit(gauge_select.ticks - 1,0,50)
        Gauge_CalcTickVals()
        lupd.update_surface = true
      elseif mouse.context == nil and MOUSE_click(obj.sections[817]) then

        gauge_select.val_dp = F_limit(gauge_select.val_dp + 1, -1, 3)
        Gauge_RecalcTickVals()
        for i = 1, #ctl_select do
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[817]) then

        gauge_select.val_dp = F_limit(gauge_select.val_dp - 1, -1, 3)
        Gauge_RecalcTickVals()
        for i = 1, #ctl_select do
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[827]) then

        gauge_select.numonly = not gauge_select.numonly
        Gauge_RecalcTickVals()
        for i = 1, #ctl_select do
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[832]) then

        gauge_select.abbrev = not gauge_select.abbrev
        Gauge_RecalcTickVals()
        for i = 1, #ctl_select do
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[806]) then

        local gtab = gauge_select
        local gcnt = #gtab.vals+1
        gtab.vals[gcnt] = {val = gtab.val, dval = gtab.dval, dover = nil}
        local nonly
        if gtab.numonly then
          nonly = ''
        end
        if gtab.val_dp > -1 then
          gtab.vals[gcnt].dover = roundX(gtab.dval, gtab.val_dp, nonly)
        end
        Gauge_SortVals()
        for i = 1, #gtab.vals do
          if gtab.vals[i].val == gtab.val then
            gauge_ticksel = i
          end
        end
        gauge_select.ticks = #gtab.vals
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[818]) then

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[ctl_select[1].ctl]
        if ctl.ctltype == 4 then

          Gauge_CopyCycleData()
          Gauge_SortVals()
          lupd.update_surface = true

        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[823]) then
        --REMOVE
        Undo_Set({'gauge'})

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[ctl_select[1].ctl]
        ctl.gauge = nil
        lupd.update_bg = true
        lupd.update_gfx = true
        lvar.delayfunction.closegaugeedit = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[824]) then
        --RESET
        Undo_Set({'gauge'})

        gauge_select = GaugeSelect_INIT()
        Gauge_CalcTickVals()
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[819]) then
        --SAVE
        Undo_Set({'gauge'})

        local strip = tracks[track_select].strip
        local ctl = strips[strip][page].controls[ctl_select[1].ctl]
        ctl.gauge = Gauge_CopySelect(gauge_select)
        lupd.update_bg = true
        lupd.update_gfx = true
        lvar.delayfunction.closegaugeedit = true
        --show_gaugeedit = false

      elseif mouse.context == nil and MOUSE_click(obj.sections[801]) then
        local gtab = gauge_select
        gtab.type = gtab.type+1
        if gtab.type > #lvar.gaugetype_table then
          gtab.type = 1
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[801]) then
        local gtab = gauge_select
        gtab.type = gtab.type-1
        if gtab.type < 1 then
          gtab.type = #lvar.gaugetype_table
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[815]) then

        OpenEB(60,'Enter numeric display value to add tick','')

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[815]) then

        OpenEB(130,'Add tick at current position with label:','')

      elseif mouse.context == nil and MOUSE_click(obj.sections[833]) then

        OpenEB(833,'Enter label:','')

      elseif mouse.context == nil and MOUSE_click(obj.sections[826]) then

        local gtab = gauge_select
        if gtab.vals and #gtab.vals > 0 and gauge_ticksel and gauge_ticksel <= #gtab.vals then
          local cnt = #gtab.vals
          gtab.vals[gauge_ticksel] = nil
          gtab.vals = Table_RemoveNils(gtab.vals, cnt)
          if gauge_ticksel > #gtab.vals then
            gauge_ticksel = #gtab.vals
          end
          --Gauge_SortVals()
          gtab.ticks = #gtab.vals
          lupd.update_surface = true
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[828]) then
        if gauge_select.vals and #gauge_select.vals > 0 then
          if gauge_ticksel == nil then
            gauge_ticksel = 1
          else
            gauge_ticksel = gauge_ticksel-1
            if gauge_ticksel < 1 then
              gauge_ticksel = #gauge_select.vals
            end
          end
        else
          gauge_ticksel = 1
        end
        lupd.update_surface = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[829]) then
        if gauge_select.vals and #gauge_select.vals > 0 then
          if gauge_ticksel == nil then
            gauge_ticksel = 1
          else
            gauge_ticksel = gauge_ticksel+1
            if gauge_ticksel > #gauge_select.vals then
              gauge_ticksel = 1
            end
          end
        else
          gauge_ticksel = 1
        end
        lupd.update_surface = true

      end

      if mouse.context and mouse.context == contexts.move_gaugeed then

        obj.sections[800].x = F_limit(mouse.mx - movegaugeed.dx,obj.sections[10000].x,gfx1.main_w-obj.sections[800].w)
        obj.sections[800].y = F_limit(mouse.my - movegaugeed.dy,obj.sections[10000].y,gfx1.main_h-obj.sections[800].h)

        obj = PosGaugeEdCtls(obj)
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_val then

        local val = MOUSE_slider(gaugeglob.sec,gaugeglob.offset)
        if val ~= nil then

          local strip = tracks[track_select].strip
          local ctl = strips[strip][page].controls[ctl_select[1].ctl]

          if oms ~= mouse.shift then
            oms = mouse.shift
            local gtab = gauge_select
            ctlpos = gtab.val
            mouse.slideoff = gaugeglob.ctly - mouse.my
          else
            if mouse.shift then
              local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
              if mult == 0 then mult = settings_defknobsens.fine end
              val = ctlpos + ((0.5-val)*2)*mult
            else
              local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
              if mult == 0 then mult = settings_defknobsens.norm end
              val = ctlpos + (0.5-val)*mult
            end
            if val < 0 then val = 0 end
            if val > 1 then val = 1 end
            val = ctlScale(ctl.scalemode, val)
            if val ~= octlval then
              gauge_select.val = F_limit(val,0,1)
              gauge_select.dval = nz(GetParamDisp_Val(ctl_select[1].ctl,gauge_select.val,true),'')
              octlval = val
              --lupd.update_ctls = true
              lupd.update_surface = true
            end
          end
        end

        --[[local val = F_limit(MOUSE_slider(obj.sections[806]),0,1)
        if val ~= nil then
          gauge_select.val = F_limit(1-val,0,1)
          gauge_select.dval = GetParamDisp_Val(ctl_select[1].ctl,gauge_select.val)
          for i = 1, #ctl_select do
          end
        end]]
      elseif mouse.context and mouse.context == contexts.auto_delayslider then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[816]),0,1)
        if val ~= nil then
          auto_delay = math.floor(val * 10)
          lupd.update_surface = true
        end

      elseif mouse.context and mouse.context == contexts.gauge_arcrad then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[802]),0,1)
        if val ~= nil then
          gauge_select.radius = math.floor(val*110) + 10
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_arclen then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[803]),0,1)
        if val ~= nil then
          gauge_select.arclen = val
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_arcrot then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[804]),0,1)
        if val ~= nil then
          gauge_select.rotation = val
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_tksz then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[807]),0,1)
        if val ~= nil then
          gauge_select.tick_size = math.floor(val*10)+2
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_tkoffs then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[808]),0,1)
        if val ~= nil then
          gauge_select.tick_offs = math.floor(val*12)
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_xoffs then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[809]),0,1)
        if val ~= nil then
          gauge_select.x_offs = math.floor(val*60) -30
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_yoffs then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[810]),0,1)
        if val ~= nil then
          gauge_select.y_offs = math.floor(val*60) -30
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_fs then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[814]),0,1)
        if val ~= nil then
          gauge_select.fontsz = math.floor(val*8) -8
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_valfreq then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[825]),0,1)
        if val ~= nil then
          gauge_select.val_freq = math.floor(val*23)+1
          for i = 1, #ctl_select do
          end
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.gauge_nudge then

        local val = F_limit(MOUSE_sliderHBar(obj.sections[830]),0,1)
        if val ~= nil and gauge_select.vals and gauge_ticksel and gauge_select.vals[gauge_ticksel] then
          gauge_select.vals[gauge_ticksel].nudge = math.floor(val*20)-10
        end
        lupd.update_surface = true
      end

    else
      if mouse.context == nil and fxmode == 1 and trctltype_select == 1 and rt > time_sendupdate then
        time_sendupdate = rt + 1
        PopulateTrackSendsInfo()
        lupd.update_gfx = true
      end

      if gfx.mouse_wheel ~= 0 then
        local v = mousewheel_val()
        if MOUSE_over(obj.sections[520]) then
          if fxmode == 0 then
            flist_offset = F_limit(flist_offset - v, 0, #trackfx)
            lupd.update_sidebar = true
            gfx.mouse_wheel = 0
          elseif fxmode == 1 then
            trctltypelist_offset = F_limit(trctltypelist_offset - v, 0, #lvar.trctltype_table-1)
            lupd.update_sidebar = true
            gfx.mouse_wheel = 0
          end
        end
        if MOUSE_over(obj.sections[521]) then
          trackedit_select = math.floor(trackedit_select - math.ceil(v))
          if trackedit_select > #tracks then
            trackedit_select = -1
          elseif trackedit_select < -1 then
            trackedit_select = #tracks
          end
          PopulateTrackFX()
          PopulateTrackSendsInfo()
          PopulateSpecial()
          trctlslist_offset = 0
          lupd.update_gfx = true
        end
        if MOUSE_over(obj.sections[522]) then
          if fxmode == 0 then
            plist_offset = F_limit(plist_offset - v, 0, #trackfxparams)
            lupd.update_sidebar = true
            gfx.mouse_wheel = 0
          elseif fxmode == 1 then
            if trctltype_select == 0 then
              trctlslist_offset = F_limit(trctlslist_offset - v, 0, #trctls_table-1)
              lupd.update_sidebar = true
              gfx.mouse_wheel = 0
            elseif trctltype_select == 1 then
              trctlslist_offset = F_limit(trctlslist_offset - v, 0, #trsends_table*3+2)
              lupd.update_sidebar = true
              gfx.mouse_wheel = 0
            elseif trctltype_select == 2 then
              trctlslist_offset = F_limit(trctlslist_offset - v, 0, #lvar.special_table-1)
              lupd.update_sidebar = true
              gfx.mouse_wheel = 0
            elseif trctltype_select == 3 then
              trctlslist_offset = F_limit(trctlslist_offset - v, 0, #lvar.otherctl_table-1)
              lupd.update_sidebar = true
              gfx.mouse_wheel = 0
            end
          end
        end

        if show_ctlbrowser and MOUSE_over(obj.sections[210]) then

          local v = mousewheel_val()
          if v > 0 then
            cbi_offset = cbi_offset - ctl_browser_size.slots_x*ctl_browser_size.slots_y
            if cbi_offset < 0 then cbi_offset = 0 end
            --PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)
            lupd.update_surface = true
            noscroll = true

          else
            if cbi_offset + ctl_browser_size.slots_x*ctl_browser_size.slots_y <
                  (math.floor(#cbi/(ctl_browser_size.slots_x*ctl_browser_size.slots_y))+1)*(ctl_browser_size.slots_x*ctl_browser_size.slots_y) then
              cbi_offset = cbi_offset + ctl_browser_size.slots_x*ctl_browser_size.slots_y
            end
            --PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)
            lupd.update_surface = true
            noscroll = true
          end
          gfx.mouse_wheel = 0

        elseif show_ctlbrowser and MOUSE_over(obj.sections[209]) then

          local slh = math.floor(lvar.ctlbrowser_btnh*pnl_scale)
          local buttslots = math.floor(obj.sections[209].h / slh)
          
          local v = (mousewheel_val())*buttslots
          
          lvar.ctlbrowser_offs = F_limit(lvar.ctlbrowser_offs-v,0,lvar.ctlbrowserfavs_max-2+#lvar.ctlbrowserbutt_table)
          lupd.update_surface = true
          noscroll = true
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[3000]) then

          local mx, my = mouse.mx, mouse.my
          mouse.mx = mouse.mx - obj.sections[3000].x
          mouse.my = mouse.my - obj.sections[3000].y

          local v = (mousewheel_val())

          if MOUSE_over(obj.sections[3001]) then
            if mouse.shift == false then
              settings_gridsize = settings_gridsize +v
            elseif v > 0 then
              settings_gridsize = ogrid * 2
            elseif v < 0 then
              settings_gridsize = math.floor(ogrid / 2)
            end
            ogrid = settings_gridsize
            lupd.update_gfx = true
          end
          noscroll = true
          gfx.mouse_wheel = 0

          mouse.mx = mx
          mouse.my = my

        elseif MOUSE_over(obj.sections[45]) then

          local mx, my = mouse.mx, mouse.my
          mouse.mx = mouse.mx - obj.sections[45].x
          mouse.my = mouse.my - obj.sections[45].y

          if ctl_page == 0 then

            local xywh = {x = 0, y = 0, w = obj.sections[45].w, h = 150}
            if MOUSE_over(xywh) then
              knob_select = (knob_select - v) % #ctl_files
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[50]) then
              
              if not wheelcontext then
                Undo_Set({'scale','xsc','ysc','wsc','hsc'})
  
                local mult = 1
                if mouse.shift then
                  mult = 0.2
                end
                scale_select = F_limit(scale_select + (v*0.05)*mult,0.5,10)
                for i = 1, #ctl_select do
                  if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctlcat ~= ctlcats.xy then
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scale = scale_select
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].xsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
                                                                                               + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w/2
                                                                                               - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select)/2)
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ysc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y
                                                                                               + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh/2
                                                                                               - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select)/2)
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select
                    --strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
                  end
                end
                
                wheelcontext = "scale"
                dragctl = "scale"
                dragoff = {alpha = 1}
                GenCtlDragPreview(gui)
                A_HideSelectedCtls(true, ctl_select)                
                --lupd.update_ctls = true
                --lupd.update_ctlopts = true
                --lupd.update_surface = true
                movefrom_sc = nil
                lupd.update_gfx = true
              else
                local mult = 1
                if mouse.shift then
                  mult = 0.2
                end
                scale_select = F_limit(scale_select + (v*0.05)*mult,0.5,10)
                for i = 1, #ctl_select do
                  if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctlcat ~= ctlcats.xy then
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scale = scale_select
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].xsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
                                                                                               + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w/2
                                                                                               - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select)/2)
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ysc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y
                                                                                               + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh/2
                                                                                               - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select)/2)
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select
                    --strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
                  end
                end
                GenCtlDragPreview(gui)
                lupd.update_surface = true
                lupd.update_ctlopts = true
                movefrom_sc = nil
                
              end
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[56]) then
              Undo_Set({'textoff','textoffx'})

              if not wheelcontext then
                if toffY then
                  textoff_select = textoff_select + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoff = textoff_select
                  end
                else
                  textoff_selectx = textoff_selectx + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffx = textoff_selectx
                  end
                end
                wheelcontext = "textoff"
                dragctl = "textoff"
                dragoff = {alpha = 1}
                GenCtlDragPreview(gui)
                A_HideSelectedCtls(true, ctl_select)                
                movefrom_sc = nil
                lupd.update_gfx = true
              else
                if toffY then
                  textoff_select = textoff_select + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoff = textoff_select
                  end
                else
                  textoff_selectx = textoff_selectx + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffx = textoff_selectx
                  end
                end
                GenCtlDragPreview(gui)
                lupd.update_surface = true
                lupd.update_ctlopts = true
                movefrom_sc = nil
              
              end
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[65]) then
              Undo_Set({'textoffval','textoffvalx'})

              if not wheelcontext then
                if toffY then
                  textoffval_select = textoffval_select + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffval = textoffval_select
                  end
                else
                  textoffval_selectx = textoffval_selectx + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffvalx = textoffval_selectx
                  end
                end
                wheelcontext = "textoffv"
                dragctl = "textoffv"
                dragoff = {alpha = 1}
                GenCtlDragPreview(gui)
                A_HideSelectedCtls(true, ctl_select)                
                movefrom_sc = nil
                lupd.update_gfx = true
              else
                if toffY then
                  textoffval_select = textoffval_select + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffval = textoffval_select
                  end
                else
                  textoffval_selectx = textoffval_selectx + v*2
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffvalx = textoffval_selectx
                  end
                end
                GenCtlDragPreview(gui)
                lupd.update_surface = true
                lupd.update_ctlopts = true
                movefrom_sc = nil

              end
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[58]) then
              Undo_Set({'textsize','textsizev'})

              textsize_select = F_limit(textsize_select + v,-2,35)
              if textoptlink_select == true then
                textsizev_select = textsize_select
              end
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsize = textsize_select
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
                if textoptlink_select == true then
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsizev = textsizev_select
                end
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              --lupd.update_gfx = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[851]) then
              Undo_Set({'textsize','textsizev'})

              textsizev_select = F_limit(textsizev_select + v,-2,35)
              if textoptlink_select == true then
                textsize_select = textsizev_select
              end
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsizev = textsizev_select
                if textoptlink_select == true then
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsize = textsizev_select
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
                end
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              --lupd.update_gfx = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[57]) then
              Undo_Set()

              defval_select = F_limit(defval_select + v/200,0,1)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].val = defval_select
                trackfxparam_select = ctl_select[i].ctl
                SetParam()
              end
              lupd.update_gfx = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[55]) then
              Undo_Set({'ctltype'})

              ctltype_select = F_limit(ctltype_select + v,1,#lvar.ctltype_table)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctltype = ctltype_select
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
              end
              show_cycleoptions = false
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0
            end

          elseif ctl_page == 1 then

            if MOUSE_over(obj.sections[128]) then
              Undo_Set({'minov'})

              val = minov_select + v*0.00125

              local p = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].param
              local min, max = GetParamMinMax_ctl(ctl_select[1].ctl, false) --trctls_table[p].min, trctls_table[p].max

              if val < min then val = min end
              if val > max then val = max end
              if val ~= octlval then
                val = math.min(val,nz(maxov_select-0.05,1))
                SetParam4(val)
                local dval = GetParamDisp_Ctl(ctl_select[1].ctl)
                minov_select = val
                ov_disp = dval
                SetParam()
                octlval = val
                lupd.update_ctls = true
              end

              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].minov = minov_select
              end
              lupd.update_gfx = true
              gfx.mouse_wheel = 0

            elseif MOUSE_over(obj.sections[129]) then
              Undo_Set({'maxov'})

              val = maxov_select + v*0.00125

              local p = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].param
              local min, max = GetParamMinMax_ctl(ctl_select[1].ctl, false) --trctls_table[p].min, trctls_table[p].max

              if val < min then val = min end
              if val > max then val = max end
              if val ~= octlval then
                val = math.max(val,nz(minov_select+0.05,0))
                SetParam4(val)
                local dval = GetParamDisp_Ctl(ctl_select[1].ctl)
                maxov_select = val
                ov_disp = dval
                SetParam()
                octlval = val
                lupd.update_ctls = true
              end

              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].maxov = maxov_select
              end
              lupd.update_gfx = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[135]) then
              Undo_Set({'knobsens'})

              knobsens_select.norm = F_limit(knobsens_select.norm+(v*0.5),0,10)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.norm = knobsens_select.norm
              end
              lupd.update_surface = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[136]) then
              Undo_Set({'knobsens'})

              knobsens_select.fine = F_limit(knobsens_select.fine+(v*0.01),0,0.2)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.fine = knobsens_select.fine
              end
              lupd.update_surface = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[137]) then
              Undo_Set({'knobsens'})

              knobsens_select.wheel = F_limit(knobsens_select.wheel+(v*0.01),0,0.2)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.wheel = knobsens_select.wheel
              end
              lupd.update_surface = true
              gfx.mouse_wheel = 0
            elseif MOUSE_over(obj.sections[138]) then
              Undo_Set({'knobsens'})

              knobsens_select.wheelfine = F_limit(knobsens_select.wheelfine+(v*0.001),0,0.02)
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.wheelfine = knobsens_select.wheelfine
              end
              lupd.update_surface = true
              gfx.mouse_wheel = 0
            end

          elseif ctl_page == 3 then

            if MOUSE_over(obj.sections[8050]) then
              Undo_Set({'adjust'})
    
              adjust_bright_select = F_limit(adjust_bright_select+(v*(0.02*512)),0,512)
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
                ctl.adjust.bright = adjust_bright_select
                ctl.adjust_active = 1
                ctl.dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0

            elseif MOUSE_over(obj.sections[8051]) then
              Undo_Set({'adjust'})
            
              adjust_contrast_select = F_limit(adjust_contrast_select+(v*(0.02*512)),0,512)
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
                ctl.adjust.contrast = adjust_contrast_select
                ctl.adjust_active = 1
                ctl.dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0

            elseif MOUSE_over(obj.sections[8052]) then
              Undo_Set({'adjust'})
            
              adjust_r_select = F_limit(adjust_r_select+(v*(0.02*512)),0,512)
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
                ctl.adjust.r = adjust_r_select
                ctl.adjust_active = 1
                ctl.dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0

            elseif MOUSE_over(obj.sections[8053]) then
              Undo_Set({'adjust'})
            
              adjust_g_select = F_limit(adjust_g_select+(v*(0.02*512)),0,512)
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
                ctl.adjust.g = adjust_g_select
                ctl.adjust_active = 1
                ctl.dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0

            elseif MOUSE_over(obj.sections[8054]) then
              Undo_Set({'adjust'})
            
              adjust_b_select = F_limit(adjust_b_select+(v*(0.02*512)),0,512)
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
                ctl.adjust.b = adjust_b_select
                ctl.adjust_active = 1
                ctl.dirty = true
                SetCtlDirty(ctl_select[i].ctl)
              end
              lupd.update_ctls = true
              lupd.update_ctlopts = true
              gfx.mouse_wheel = 0
            end
          end

          mouse.mx, mouse.my = mx, my
        end
      end

      if show_paramlearn then
        last_touch_fx = GetLastTouchedFX(last_touch_fx)
      end

      if show_paramlearn and (MOUSE_click(obj.sections[115]) or MOUSE_click_RB(obj.sections[115])) then

        --LEARN
        local xywh = {x = obj.sections[115].x,
                      y = obj.sections[115].y+25,
                      w = obj.sections[115].w,
                      h = obj.sections[115].h-25}
        local xywh2 = {x = obj.sections[115].x,
                        y = obj.sections[115].y,
                        w = obj.sections[115].w,
                        h = butt_h}

        if MOUSE_click(xywh2) then
          moveparamlrn = {dx = mouse.mx - obj.sections[115].x, dy = mouse.my - obj.sections[115].y}
          mouse.context = contexts.move_paramlrn

        elseif MOUSE_click(xywh) then
          ClearSelected(ctl_select)
          
          ctl_select = nil
          lupd.update_gfx = true

          if ctl_files[knob_select].imageidx ~= nil then
            local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
            local h = ctl_files[knob_select].cellh
            if w == 0 or h == 0 then
              ksel_size = {w = 50, h = 50}
            else
             ksel_size = {w = w/2, h = h/2}
           end
          else
            ksel_size = {w = 50, h = 50}
          end
          mouse.context = contexts.dragparamlrn
        elseif MOUSE_click_RB(obj.sections[115]) then
          show_paramlearn = false
          ctl_select = nil
          lupd.update_gfx = true
        end

        noscroll = true

      elseif (ctl_select ~= nil or gfx3_select ~= nil) and (char ~= 0 or keycontext) then

        ArrowKey_Shift(char,ctl_select,gfx3_select)

      elseif show_ctlbrowser and (MOUSE_click(obj.sections[200]) or MOUSE_click_RB(obj.sections[200])) then

        cb_clicked = true
        noscroll = true

        if mouse.context == nil and MOUSE_click(obj.sections[237]) then
          
          lvar.ctlbrowser_docked = not lvar.ctlbrowser_docked
          lvar.cbi_loaded = nil
          obj = GetObjects()
          SetSurfaceSize2(obj)
          lupd.update_gfx = true
        
        elseif mouse.context == nil and MOUSE_click(obj.sections[236]) then
          if lvar.ctlbrowser_docked then

            mouse.context = contexts.resize_ctlbrowser
            lvar.cbwinrsz = {mx = mouse.mx, x = obj.sections[200].x, w = obj.sections[200].w}
          end

        elseif mouse.context == nil and MOUSE_click(obj.sections[211]) then
          cbi_offset = cbi_offset - math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y,maximg_browse+1)
          if cbi_offset < 0 then cbi_offset = 0 end
          --PopulateCtlBrowser_Imgs()
          GUI_DrawCtlBrowserCtls(obj, gui)
          lupd.update_surface = true

        elseif mouse.context == nil and MOUSE_click(obj.sections[212]) then
          if cbi_offset + math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y,maximg_browse+1) <
                (math.floor(#cbi/(ctl_browser_size.slots_x*ctl_browser_size.slots_y))+1)*(ctl_browser_size.slots_x*ctl_browser_size.slots_y) then
            cbi_offset = cbi_offset + math.min(ctl_browser_size.slots_x*ctl_browser_size.slots_y,maximg_browse+1)
          end
          --PopulateCtlBrowser_Imgs()
          GUI_DrawCtlBrowserCtls(obj, gui)
          lupd.update_surface = true

        elseif mouse.context == nil and MOUSE_click(obj.sections[210]) then

          if not mouse.ctrl then
            if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
              local ix = math.floor((mouse.mx - obj.sections[210].x) / ctl_browser_size.slotsz)
              local iy = math.floor((mouse.my - obj.sections[210].y) / ctl_browser_size.slotsz)
              local i = ix + iy*ctl_browser_size.slots_x +cbi_offset

              if cbi[i] then
                knob_select = cbi[i].idx
                --DBG(ctltype_select..'  '..tostring(cbi[i].ctltype))
                if cbi[i].ctltype then
                  --{'Knob','Slider','Button','Meter','Misc','Slider2','Slider2H','Slider3'}
                  if cbi[i].ctltype == 0 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 1 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 2 then
                    ctltype_select = 2
                  elseif cbi[i].ctltype == 3 then
                    ctltype_select = 5
                  elseif cbi[i].ctltype == 4 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 6 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 7 then
                    ctltype_select = 1
                  end
                end
                --[[local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx or 1023)
                local h = ctl_files[knob_select].cellh
                ksel_size = {w = w/2, h = h/2}]]
                if not lvar.ctlbrowser_docked then
                  closectlbrowser = true
                  show_ctlbrowser = false
                end
                lupd.update_surface = true
                lupd.update_ctlopts = true
                lupd.update_sidebar = true
              end
            else
              local ix = math.floor((mouse.mx - obj.sections[210].x) / ctl_browser_size.slotsz)
              local iy = math.floor((mouse.my - obj.sections[210].y) / ctl_browser_size.slotsz)
              local i = ix + iy*ctl_browser_size.slots_x +cbi_offset

              if cbi[i] then
                cbi_select = cbi[i].idx
                SetCbiSelect()
                lupd.update_surface = true

                knob_select = cbi[i].idx
                if cbi[i].ctltype then
                  --{'Knob','Slider','Button','Meter','Misc','Slider2','Slider2H','Slider3'}
                  if cbi[i].ctltype == 0 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 1 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 2 then
                    ctltype_select = 2
                  elseif cbi[i].ctltype == 3 then
                    ctltype_select = 5
                  elseif cbi[i].ctltype == 4 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 6 then
                    ctltype_select = 1
                  elseif cbi[i].ctltype == 7 then
                    ctltype_select = 1
                  end
                end
                --[[local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx or 1023)
                local h = ctl_files[knob_select].cellh
                ksel_size = {w = w/2, h = h/2}]]
                --closectlbrowser = true
                --show_ctlbrowser = false
                lupd.update_surface = true
                lupd.update_ctlopts = true
                lupd.update_sidebar = true
              end
            end
          else
            local ix = math.floor((mouse.mx - obj.sections[210].x) / ctl_browser_size.slotsz)
            local iy = math.floor((mouse.my - obj.sections[210].y) / ctl_browser_size.slotsz)
            local i = ix + iy*ctl_browser_size.slots_x +cbi_offset

            if cbi[i] then
              cbi_select = cbi[i].idx
              SetCbiSelect()
              lupd.update_surface = true

              local favs = lvar.ctlbrowserfavs
              local sel = lvar.ctlbrowserfav_select
              if not favs[sel] then
                favs[sel] = {}
              end
              local fnd = false
              for ii = 1, #favs[sel] do
                if ctl_files[cbi_select].fn == favs[sel][ii].fn then
                  --already in favs
                  fnd = true
                  break
                end
              end

              if fnd == false then
                favs[sel][#favs[sel]+1] = {fn = ctl_files[cbi_select].fn}
                CB_SaveFavs()
              end
            end
          end

        elseif mouse.context == nil and MOUSE_click_RB(obj.sections[210]) then
          local ix = math.floor((mouse.mx - obj.sections[210].x) / ctl_browser_size.slotsz)
          local iy = math.floor((mouse.my - obj.sections[210].y) / ctl_browser_size.slotsz)
          local i = ix + iy*ctl_browser_size.slots_x +cbi_offset

          if cbi[i] then
            cbi_select = cbi[i].idx
            SetCbiSelect()
            if ctl_files[cbi_select] then
              lupd.update_surface = true
              GUI_draw(obj,gui)
              gfx.update()

              if cbi_filter == -2 then
                mstr = 'Knob|Slider|Button|Meter|Misc||Remove from this set'
              else
                local favs = lvar.ctlbrowserfavs
                local sel = lvar.ctlbrowserfav_select
                local txt = ''
                if favs[sel] and favs[sel].name then
                  txt = ': '..favs[sel].name
                end
                mstr = 'Knob|Slider|Button|Meter|Misc||Add to set '..string.format('%i',lvar.ctlbrowserfav_select)..txt
              end
              gfx.x, gfx.y = mouse.mx, mouse.my
              local res = OpenMenu(mstr)
              if res == 1 then
                ctl_files[cbi_select].ctltype = 0
              elseif res == 2 then
                ctl_files[cbi_select].ctltype = 1
              elseif res == 3 then
                ctl_files[cbi_select].ctltype = 2
              elseif res == 4 then
                ctl_files[cbi_select].ctltype = 3
              elseif res == 5 then
                ctl_files[cbi_select].ctltype = 4
              elseif res == 6 then

                local favs = lvar.ctlbrowserfavs
                local sel = lvar.ctlbrowserfav_select
                local saveflag = false

                if cbi_filter == -2 then
                  if favs[sel] then
                    local fnd = false
                    local cnt = #favs[sel]
                    for ii = 1, cnt do
                      if ctl_files[cbi_select].fn == favs[sel][ii].fn then
                        --in favs
                        fnd = true
                        favs[sel][ii] = nil
                        favs[sel] = Table_RemoveNils(favs[sel], cnt)
                        PopulateCtlBrowser_Cbi()
                        GUI_DrawCtlBrowserCtls(obj, gui)
                        lupd.update_surface = true
                        saveflag = true
                        break
                      end
                    end
                  end
                else
                  if not favs[sel] then
                    favs[sel] = {}
                  end
                  local fnd = false
                  for ii = 1, #favs[sel] do
                    if ctl_files[cbi_select].fn == favs[sel][ii].fn then
                      --already in favs
                      fnd = true
                      break
                    end
                  end

                  if fnd == false then
                    favs[sel][#favs[sel]+1] = {fn = ctl_files[cbi_select].fn}
                    saveflag = true
                  end
                end
                if saveflag then
                  CB_SaveFavs()
                end
              end
              if res > 0 and res ~= 6 then

                local save_path=paths.controls_path
                local knbfn = ctl_files[cbi_select].fn

                local fn=save_path..string.sub(knbfn,0,string.len(knbfn)-3).. 'knb'

                local knbdata = {fn = ctl_files[cbi_select].fn,
                                 frames = ctl_files[cbi_select].frames,
                                 cellh = ctl_files[cbi_select].cellh,
                                 ctltype = ctl_files[cbi_select].ctltype}

                local DELETE=true
                local file

                if reaper.file_exists(fn) then

                end

                if DELETE then
                  file=io.open(fn,"w")
                  local pickled_table=pickle(knbdata)
                  file:write(pickled_table)
                  file:close()

                end
                SetCbiSelect()
                lupd.update_surface = true

              end
            end
          end

        elseif MOUSE_click(obj.sections[209]) then

          local slh = math.floor(lvar.ctlbrowser_btnh*pnl_scale)
          local iy = math.floor((mouse.my - obj.sections[209].y) / slh)
          local idx = lvar.ctlbrowser_offs + iy
          if idx < #lvar.ctlbrowserbutt_table then
            cbi_offset = 0
            if idx == 0 then
              cbi_filter = -1
            elseif idx == 1 then
              cbi_filter = 0
            elseif idx == 2 then
              cbi_filter = 1
            elseif idx == 3 then
              cbi_filter = 5
            elseif idx == 4 then
              cbi_filter = 2
            elseif idx == 5 then
              cbi_filter = 3
            elseif idx == 6 then
              cbi_filter = 4
            end
            PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)
            lupd.update_surface = true
          else
            idx = idx - #lvar.ctlbrowserbutt_table + 1

            if idx <= lvar.ctlbrowserfavs_max then
              lvar.ctlbrowserfav_select = idx
              cbi_offset = 0
              cbi_filter = -2
              PopulateCtlBrowser_Cbi()
              GUI_DrawCtlBrowserCtls(obj, gui)
              lupd.update_surface = true
            end
          end

        elseif MOUSE_click_RB(obj.sections[209]) then

          local slh = math.floor(lvar.ctlbrowser_btnh*pnl_scale)
          local iy = math.floor((mouse.my - obj.sections[209].y) / slh)
          local idx = lvar.ctlbrowser_offs + iy
          if idx >= #lvar.ctlbrowserbutt_table then
            idx = idx - #lvar.ctlbrowserbutt_table + 1

            if idx <= lvar.ctlbrowserfavs_max then

              mstr = 'Rename Set'
              gfx.x = mouse.mx
              gfx.y = mouse.my
              local res = gfx.showmenu(mstr)
              if res > 0 then
                local favs = lvar.ctlbrowserfavs
                if res == 1 then

                  lvar.ctlbrowserfav_select = idx
                  local sel = idx
                  cbi_offset = 0
                  cbi_filter = -2
                  PopulateCtlBrowser_Cbi()
                  GUI_DrawCtlBrowserCtls(obj, gui)
                  local def
                  if favs[sel] then
                    def = favs[sel].name
                  end
                  OpenEB(300,'Please enter name for favourite set:',def or '')
                end
              end
            end
          end
        end

        noscroll = true

      elseif mouse.context == nil and (MOUSE_click(obj.sections[3000]) or MOUSE_click_RB(obj.sections[3000])) then

        A_Run_CBox()

      elseif ctl_select ~= nil and (MOUSE_click(obj.sections[45]) or MOUSE_click_RB(obj.sections[45])) then

        --CONTROL OPTIONS
        local mx, my = mouse.mx, mouse.my
        mouse.mx = mouse.mx - obj.sections[45].x
        mouse.my = mouse.my - obj.sections[45].y

        if MOUSE_click(obj.sections[853]) then

          local mx = mouse.mx - obj.sections[853].x
          local b = math.floor(mx / (obj.sections[853].w/4))
          ctl_page = F_limit(b,0,3)
          lupd.update_gfx = true

        --[[elseif mouse.LB and mouse.my > obj.sections[45].y and mouse.my < obj.sections[45].y+butt_h*pnl_scale and mouse.mx > obj.sections[45].x+obj.sections[45].w-40 then

          show_cycleoptions = false
          ctl_page = ctl_page + 1
          if ctl_page > 2 then
            ctl_page = 0
          end
          lupd.update_gfx = true

        elseif mouse.RB and mouse.my > obj.sections[45].y and mouse.my < obj.sections[45].y+butt_h*pnl_scale and mouse.mx > obj.sections[45].x+obj.sections[45].w-40 then

          show_cycleoptions = false
          ctl_page = ctl_page - 1
          if ctl_page < 0 then
            ctl_page = 2
          end
          lupd.update_gfx = true
        ]]
        elseif mouse.LB and my > obj.sections[45].y and my < obj.sections[45].y+butt_h*pnl_scale then

          movectlopts = {dx = mouse.mx,dy = mouse.my}
          mouse.context = contexts.move_ctlopts

        end

        if ctl_page == 0 then

          if mouse.context == nil and MOUSE_click(obj.sections[90]) then

            knob_select = knob_select - 1
            if knob_select < 0 then
              knob_select = #ctl_files
            end
            lupd.update_ctlopts = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[91]) then

            knob_select = knob_select + 1
            if knob_select > #ctl_files then
              knob_select = 0
            end
            lupd.update_ctlopts = true

          elseif mouse.LB and mouse.my > butt_h*pnl_scale and mouse.my < obj.sections[99].y-4 then

            --PopulateCtlBrowser_Imgs()
            PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)

            cbi_select = knob_select

            SetCbiSelect()

            show_ctlbrowser = true
            lupd.update_surface = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[66]) then
            Undo_Set({'maxdp'})

            maxdp_select = F_limit(maxdp_select + 1, -1, 3)
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].maxdp = maxdp_select
            end
            lupd.update_gfx = true

          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[66]) then
            Undo_Set({'maxdp'})

            maxdp_select = F_limit(maxdp_select - 1, -1, 3)
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].maxdp = maxdp_select
            end
            lupd.update_gfx = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[99]) then

            show_gaugeedit = true
            gauge_select.val = 0
            gauge_select.dval = nz(GetParamDisp_Val(ctl_select[1].ctl,gauge_select.val,true),'')
            local strip = tracks[track_select].strip
            if strips[strip][page].controls[ctl_select[1].ctl].gauge == nil then
              Gauge_CalcTickVals()
            end
            lupd.update_gfx = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[852]) then
            textoptlink_select = not textoptlink_select
            lupd.update_ctlopts = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[52]) then
            Undo_Set({'show_paramname'})
            show_paramname = not show_paramname
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].show_paramname = show_paramname
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[53]) then
            Undo_Set({'show_paramval'})
            show_paramval = not show_paramval
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].show_paramval = show_paramval
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[54]) then
            local retval, c = reaper.GR_SelectColor(_,ConvertColorString(textcol_select))
            if retval ~= 0 then
              if lvar.Mac_revcol then c = MacRevC(c) end
              Undo_Set({'textcol','textcolv'})
              textcol_select = ConvertColor(c)
              if textoptlink_select == true then
                textcolv_select = textcol_select
              end
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textcol = textcol_select
                if textoptlink_select == true then
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textcolv = textcol_select
                end
              end
              lupd.update_gfx = true
            end
          elseif mouse.context == nil and MOUSE_click(obj.sections[850]) then
            local retval, c = reaper.GR_SelectColor(_,ConvertColorString(textcolv_select))
            if retval ~= 0 then
              if lvar.Mac_revcol then c = MacRevC(c) end
              Undo_Set({'textcol','textcolv'})
              textcolv_select = ConvertColor(c)
              if textoptlink_select == true then
                textcol_select = textcolv_select
              end
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textcolv = textcolv_select
                if textoptlink_select == true then
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textcol = textcolv_select
                end
              end
              lupd.update_gfx = true
            end
          elseif mouse.context == nil and MOUSE_click(obj.sections[55]) then
            Undo_Set({'ctltype'})

            ctltype_select = ctltype_select + 1
            if ctltype_select > #lvar.ctltype_table then ctltype_select = 1 end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctltype = ctltype_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            end
            lupd.update_ctls = true
            lupd.update_ctlopts = true

          elseif MOUSE_click_RB(obj.sections[55]) then
            Undo_Set({'ctltype'})

            ctltype_select = ctltype_select - 1
            if ctltype_select < 1 then ctltype_select = #lvar.ctltype_table end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctltype = ctltype_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            end
            lupd.update_ctls = true
            lupd.update_ctlopts = true
          end

          if mouse.context == nil and ctltype_select == 4 and MOUSE_click(obj.sections[67]) then
            show_cycleoptions = not show_cycleoptions
            if show_cycleoptions then
              cycle_select.val = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].val
            end
            lupd.update_gfx = true
          else
            show_cycleoptions = false
          end

          if mouse.context == nil and MOUSE_click(obj.sections[59]) then
            if ctl_select and #ctl_select > 0 then
              --EditCtlName()
              if strips and strips[tracks[track_select].strip] then
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
                local cn
                if (ctl.ctlname_override or '') ~= '' then
                  cn = ctl.ctlname_override
                else
                  cn = ctl.param_info.paramname
                end
                OpenEB(2,'Please enter a name for the selected controls:',cn)
                --lupd.update_gfx = true
              end
            end
          elseif mouse.context == nil and MOUSE_click(obj.sections[960]) then
            if strips and strips[tracks[track_select].strip] then
              if ctl_select and #ctl_select > 0 and strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
                 and strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].ctlcat == ctlcats.midictl then
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]

                midioutedit_ctlselect = true
                midioutedit_select = ctl_select[1].ctl
                midiout_select = ctl.midiout
                if midiout_select == nil then
                  midiout_select = {output = nil,
                                    msgtype = 4,
                                    mchan = 1,
                                    msg3 = 1,
                                    msg4 = 0,
                                    osc = nil,
                                    vmin = 0,
                                    vmax = 127,
                                    focus = 1,
                                    focus_wintit = nil,
                                    focus_winexact = false,
                                    updategfx = false}
                end
                show_midiout = true
                lupd.update_gfx = true
                mouse.context = contexts.dummy

              end
            end

          elseif mouse.context == nil and MOUSE_click(obj.sections[68]) then
            toffY = not toffY
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[57]) then
            local dv = GetParamValue_Ctl(ctl_select[1].ctl)
            if dv then
              defval_select = dv
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval = GetParamValue_Ctl(ctl_select[i].ctl)
              end
              lupd.update_ctlopts = true
            end
          elseif mouse.context == nil and MOUSE_click(obj.sections[962]) then
            Undo_Set({'enabledefval'})

            enabledefval_select = not enabledefval_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].enabledefval = enabledefval_select
            end
            lupd.update_ctlopts = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[51]) then
            --apply

            Undo_Set({'knob_select','ctl_info','w','xsc','ysc','wsc','hsc'})

            if ctl_files[knob_select].imageidx == nil then
              image_count = F_limit(image_count + 1,0,image_max)
              gfx.loadimg(image_count, paths.controls_path..ctl_files[knob_select].fn)
              ctl_files[knob_select].imageidx = image_count
            end
            local w, _ = gfx.getimgdim(ctl_files[knob_select].imageidx)
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knob_select = knob_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.fn = ctl_files[knob_select].fn
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.imageidx = ctl_files[knob_select].imageidx
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.frames = ctl_files[knob_select].frames
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w = w
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh = ctl_files[knob_select].cellh

              local scale = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scale
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].xsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
                                                                                         + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w/2
                                                                                         - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale)/2)
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ysc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y
                                                                                         + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh/2
                                                                                         - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale)/2)
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wsc = w*scale
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hsc = ctl_files[knob_select].cellh*scale
            end
            SetCtlBitmapRedraw()
            movefrom_sc = nil
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[48]) then
            
            if fontlist then
              OpenFontList(mx,my,8)
          
              --[[local fnt = ChooseFontMenu(mx,my)
              if fnt then
                local f = CheckFont(fnt)
                if f then
                  Undo_Set({'font'})
                  ctlfont_select = f
                  for i = 1, #ctl_select do
                    strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].font = ctlfont_select
                  end
                end
                lupd.update_gfx = true
              end]]
            else
              OpenEB(62,'Please enter font name:')
            end

          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[48]) then
            UpdateFontList(mx,my)
          end

          if mouse.context == nil and MOUSE_click(obj.sections[50]) then
            Undo_Set({'scale','xsc','ysc','wsc','hsc'})
            if mouse.ctrl or (mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then

              scale_select = 1
              --ctlscaling = true
              lupd.update_ctlopts = true
              for i = 1, #ctl_select do
                if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctlcat ~= ctlcats.xy then
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scale = scale_select
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].xsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
                                                                                             + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w/2
                                                                                             - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select)/2)
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ysc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y
                                                                                             + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh/2
                                                                                             - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select)/2)
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select
                  strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select
                end
              end
              movefrom_sc = nil
              lupd.update_gfx = true

            else
              mouse.context = contexts.scaleslider
              dragctl = 'dragscale'
              dragoff = {x = 0, y = 0, alpha = 1}
              GenCtlDragPreview(gui)
              A_HideSelectedCtls(true, ctl_select)
              lupd.update_gfx = true
              
            end
          elseif mouse.context == nil and MOUSE_click(obj.sections[56]) then 
            Undo_Set({'textoff','textoffx'}) 
            mouse.context = contexts.offsetslider
            dragctl = 'dragtextoff'
            dragoff = {x = 0, y = 0, alpha = 1}
            GenCtlDragPreview(gui)
            A_HideSelectedCtls(true, ctl_select)
            lupd.update_gfx = true
            
          elseif mouse.context == nil and MOUSE_click(obj.sections[65]) then 
            Undo_Set({'textoffval','textoffvalx'}) 
            mouse.context = contexts.valoffsetslider
            dragctl = 'dragtextoffv'
            dragoff = {x = 0, y = 0, alpha = 1}
            GenCtlDragPreview(gui)
            A_HideSelectedCtls(true, ctl_select)
            lupd.update_gfx = true
            
          elseif mouse.context == nil and MOUSE_click(obj.sections[57]) then Undo_Set({'val','defval'}) omx = -1 ctlpos = defval_select mouse.context = contexts.defvalslider
          elseif mouse.context == nil and MOUSE_click(obj.sections[58]) then Undo_Set({'textsize','textsizev'}) mouse.context = contexts.textsizeslider
          elseif mouse.context == nil and MOUSE_click(obj.sections[851]) then Undo_Set({'textsize','textsizev'}) mouse.context = contexts.textsizevslider end

        elseif ctl_page == 1 then

          if MOUSE_click(obj.sections[126]) then
            OpenEB(4,'Please enter normalized min value:')

          elseif MOUSE_click(obj.sections[127]) then
            OpenEB(16,'Please enter normalized max value:')
          end

          if MOUSE_click(obj.sections[125]) then
            --EditDValOffset()
            OpenEB(3,'Please enter a display offset value:',strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].dvaloffset)
          end

          if MOUSE_click(obj.sections[134]) then
            Undo_Set({'horiz'})

            horiz_select = not horiz_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].horiz = horiz_select
            end
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[139]) then
            Undo_Set({'noss'})

            if noss_select then
              noss_select = nil
            else
              noss_select = true
            end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].noss = noss_select
            end
            lupd.update_gfx = true
          end

          if MOUSE_click(obj.sections[131]) then
            Undo_Set({'scalemode','framemode'})

            knob_scalemode_select = knob_scalemode_select + 1
            if knob_scalemode_select > #lvar.scalemode_preset_table then knob_scalemode_select = 2 end
            if knob_scalemode_select == 2 then
              scalemode_select = 8
              framemode_select = 1
            elseif knob_scalemode_select == 3 then
              scalemode_select = 12
              framemode_select = 2
            end

            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scalemode = scalemode_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].framemode = framemode_select
            end
            lupd.update_gfx = true
          end

          if MOUSE_click(obj.sections[132]) then
            Undo_Set({'scalemode'})

            scalemode_select = scalemode_select + 1
            if scalemode_select > #lvar.scalemode_table then scalemode_select = 1 end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scalemode = scalemode_select
            end
            SetKnobScaleMode()
            lupd.update_gfx = true
          elseif MOUSE_click_RB(obj.sections[132]) then
            Undo_Set({'scalemode'})

            scalemode_select = scalemode_select - 1
            if scalemode_select < 1 then scalemode_select = #lvar.scalemode_table end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scalemode = scalemode_select
            end
            SetKnobScaleMode()
            lupd.update_gfx = true
          end

          if MOUSE_click(obj.sections[133]) then
            Undo_Set({'framemode'})

            framemode_select = framemode_select + 1
            if framemode_select > #lvar.framemode_table then framemode_select = 1 end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].framemode = framemode_select
            end
            SetKnobScaleMode()
            lupd.update_gfx = true
          elseif MOUSE_click_RB(obj.sections[133]) then
            Undo_Set({'framemode'})

            framemode_select = framemode_select - 1
            if framemode_select < 1 then framemode_select = #lvar.framemode_table end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].framemode = framemode_select
            end
            SetKnobScaleMode()
            lupd.update_gfx = true
          end

          if mouse.context == nil and MOUSE_click(obj.sections[128]) then
            Undo_Set({'minov','defval'})

            mouse.context = contexts.minov
            trackfxparam_select = ctl_select[1].ctl
            ctlpos = minov_select
            mouse.slideoff = obj.sections[128].y+obj.sections[128].h/2 - mouse.my
            oms = mouse.shift
            for i = 1, #ctl_select do
              local min, max = GetParamMinMax_ctl(ctl_select[i].ctl)
              ctl_select[i].denorm_defval = DenormalizeValue(min,
                                                             max,
                                                             strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval)
            end
            minov_act = 'minov'

          elseif mouse.context == nil and MOUSE_click(obj.sections[129]) then
            Undo_Set({'maxov','defval'})

            mouse.context = contexts.maxov
            trackfxparam_select = ctl_select[1].ctl
            ctlpos = maxov_select
            mouse.slideoff = obj.sections[129].y+obj.sections[129].h/2 - mouse.my
            oms = mouse.shift
            for i = 1, #ctl_select do
              local min, max = GetParamMinMax_ctl(ctl_select[i].ctl)
              ctl_select[i].denorm_defval = DenormalizeValue(min,
                                                             max,
                                                             strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval)
            end
            maxov_act = 'maxov'

          elseif mouse.context == nil and MOUSE_click(obj.sections[135]) then
            Undo_Set({'knobsens'})
            mouse.context = contexts.knobsens_norm
          elseif mouse.context == nil and MOUSE_click(obj.sections[136]) then
            Undo_Set({'knobsens'})
            mouse.context = contexts.knobsens_fine
          elseif mouse.context == nil and MOUSE_click(obj.sections[137]) then
            Undo_Set({'knobsens'})
            mouse.context = contexts.knobsens_wheel
          elseif mouse.context == nil and MOUSE_click(obj.sections[138]) then
            Undo_Set({'knobsens'})
            mouse.context = contexts.knobsens_wheelfine
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[135]) then
            Undo_Set({'knobsens'})
            local val = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].knobsens.m_norm
            local mult = GetKnobSensMult(val)
            if mult then
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                if ctl then
                  ctl.knobsens.m_norm = mult
                end
              end
            end
            lupd.update_ctlopts = true
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[136]) then
            Undo_Set({'knobsens'})
            local val = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].knobsens.m_fine
            local mult = GetKnobSensMult(val)
            if mult then
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                if ctl then
                  ctl.knobsens.m_fine = mult
                end
              end
            end
            lupd.update_ctlopts = true
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[137]) then
            Undo_Set({'knobsens'})
            local val = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].knobsens.m_wheel
            local mult = GetKnobSensMult(val)
            if mult then
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                if ctl then
                  ctl.knobsens.m_wheel = mult
                end
              end
            end
            lupd.update_ctlopts = true
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[138]) then
            Undo_Set({'knobsens'})
            local val = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].knobsens.m_wheelfine
            local mult = GetKnobSensMult(val)
            if mult then
              for i = 1, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]
                if ctl then
                  ctl.knobsens.m_wheelfine = mult
                end
              end
            end
            lupd.update_ctlopts = true
          end

        elseif ctl_page == 2 then

          if mouse.context == nil and MOUSE_click(obj.sections[860]) then
            Undo_Set({'bypassbg_c'})
            bypass_bgdraw_c_select = not bypass_bgdraw_c_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].bypassbg_c = bypass_bgdraw_c_select
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[861]) then
            Undo_Set({'bypassbg_n'})
            bypass_bgdraw_n_select = not bypass_bgdraw_n_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].bypassbg_n = bypass_bgdraw_n_select
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[862]) then
            Undo_Set({'bypassbg_v'})
            bypass_bgdraw_v_select = not bypass_bgdraw_v_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].bypassbg_v = bypass_bgdraw_v_select
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[863]) then
            Undo_Set({'clickthrough'})
            clickthrough_select = not clickthrough_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].clickthrough = clickthrough_select
            end
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[864]) then
            Undo_Set({'dnu'})
            dnu_select = not dnu_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dnu = dnu_select
            end
            ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
            lupd.update_gfx = true
          elseif mouse.context == nil and MOUSE_click(obj.sections[869]) then
            Undo_Set({'orr'})
            orr_select = not orr_select
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].orr = orr_select
            end
            ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
            lupd.update_gfx = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[868]) then
            --OpenEB(252,'Enter width in pixels',wwtext_select or 0)
            Undo_Set({'wwtext'})
            mouse.context = contexts.wwdrag
            ctlpos = wwtext_select
            dragctl = "wwtext"
            dragoff = {x = 0, y = 0, alpha = 1}
            GenCtlDragPreview(gui)
            A_HideSelectedCtls(true, ctl_select)
            lupd.update_gfx = true

          elseif mouse.context == nil and MOUSE_click(obj.sections[866]) then
            OpenEB(250,'Enter width in pixels',limittext_select or 0)
          elseif mouse.context == nil and MOUSE_click(obj.sections[867]) then
            OpenEB(251,'Enter text flags (-1 = auto justify when limit text is set)',flags_select or '')
          elseif mouse.context == nil and MOUSE_click(obj.sections[870]) then
            OpenEB(253,'Enter animate time (ms)',animatetime_select or '')
          
          elseif mouse.context == nil and MOUSE_click(obj.sections[871]) then
          
            Undo_Set({'animateshape'})
            animateshape_select = (animateshape_select or 1) + 1
            if animateshape_select > #lvar.macroscale_sm_table then
              animateshape_select = 1
            end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].animateshape = animateshape_select
            end            
            lupd.update_ctlopts = true
          
          elseif mouse.context == nil and MOUSE_click_RB(obj.sections[871]) then

            Undo_Set({'animateshape'})
            animateshape_select = (animateshape_select or (#lvar.macroscale_sm_table+1)) - 1
            if animateshape_select < 1 then
              animateshape_select = #lvar.macroscale_sm_table
            end
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].animateshape = animateshape_select
            end            
            lupd.update_ctlopts = true            

          elseif mouse.context == nil and MOUSE_click(obj.sections[865]) then
            Undo_Set({'tracknum','otracknum'})
            targetseltrack_select = not targetseltrack_select
            if targetseltrack_select == true then
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].otracknum = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].tracknum
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].tracknum = -3
              end
            else
              for i = 1, #ctl_select do
                strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].tracknum = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].otracknum
              end
            end
            ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
            lupd.update_gfx = true
          end

        elseif ctl_page == 3 then

          ARun_CtlPage4()

        end

        mouse.mx, mouse.my = mx, my

      elseif ctl_select ~= nil and show_cycleoptions and gfx.mouse_wheel ~= 0 and MOUSE_over(obj.sections[103]) then

        local v = mousewheel_val()
        cyclist_offset = F_limit(cyclist_offset - v, 0, max_cycle-8)
        lupd.update_gfx = true
        gfx.mouse_wheel = 0

      elseif ctl_select ~= nil and show_cycleoptions and (MOUSE_click(obj.sections[100]) or MOUSE_click_RB(obj.sections[100])) then

        -- CYCLE OPTS

        if MOUSE_click(obj.sections[102]) and mouse.ctrl == false then
          cyclist_offset = 0
          cycle_select.statecnt = F_limit(cycle_select.statecnt+1,0,max_cycle)
          Cycle_InitData()
          lupd.update_gfx = true
        elseif MOUSE_click_RB(obj.sections[102]) then
          cyclist_offset = 0
          cycle_select.statecnt = F_limit(cycle_select.statecnt-1,0,max_cycle)
          Cycle_InitData()
          lupd.update_gfx = true
        elseif MOUSE_click(obj.sections[102]) and (mouse.ctrl == true or mouse.shift == true) then

          OpenEB(17,'Enter number of cycle states:')

        end

        if mouse.context == nil and MOUSE_click(obj.sections[101]) then
          mouse.context = contexts.cycleknob
          cycle_editmode = true
          trackfxparam_select = ctl_select[1].ctl
          ctlpos = cycle_select.val
          mouse.slideoff = obj.sections[101].y+obj.sections[101].h/2 - mouse.my
          oms = mouse.shift

        elseif mouse.context == nil and MOUSE_click_RB(obj.sections[101]) then

          trackfxparam_select = ctl_select[1].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
          cycle_select.val = ctl.val
          if cycle_select.selected then
            local v = GetParamValue(ctl.ctlcat, ctl.tracknum or tracks[track_select].tracknum, ctl.fxnum, ctl.param, trackfxparam_select)
            local dispval = GetParamDisp(ctl.ctlcat, ctl.tracknum or tracks[track_select].tracknum, ctl.fxnum, ctl.param, ctl.dvaloffset, trackfxparam_select)
            cycle_select[cycle_select.selected].val = ctl.val
            --DBG(ctl.val..'  '..cycle_select[cycle_select.selected].val..'  '..v)
            cycle_select[cycle_select.selected].dispval = dispval
            cycle_select[cycle_select.selected].dv = dispval
          end
          lupd.update_gfx = true

        end

        if MOUSE_click(obj.sections[103]) then
          local i = math.floor((mouse.my - obj.sections[103].y) / (butt_h*pnl_scale))+1
          cycle_select.selected = F_limit(i+cyclist_offset,1,cycle_select.statecnt)
          --strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].cycledata.pos = cycle_select.selected
          lupd.update_gfx = true
          if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime < 0.2) then
            OpenEB(10,'Please enter value:')
          end

        elseif MOUSE_click_RB(obj.sections[103]) then
          if cycle_select and cycle_select.selected then
            CyclePos_Menu()
          end
        end

        if MOUSE_click(obj.sections[104]) then
          Cycle_Auto()
          cyclist_offset = 0
          lupd.update_gfx = true
        
        elseif MOUSE_click_RB(obj.sections[104]) then
          Cycle_AutoMenu()
          
        end

        if MOUSE_click(obj.sections[110]) then
          mouse.context = contexts.auto_delayslider
        end

        if MOUSE_click(obj.sections[105]) then
          local i = math.floor((mouse.mx-obj.sections[105].x)/(obj.sections[105].w/2))
          if #cycle_select < 8 then
            cyclist_offset = 0
          else
            if i >= 1 then
              cyclist_offset = F_limit(cyclist_offset+1,0,math.max(#cycle_select-8,0))
            else
              cyclist_offset = F_limit(cyclist_offset-1,0,math.max(#cycle_select-8,0))
            end
          end
          lupd.update_gfx = true
        end

        if MOUSE_click(obj.sections[106]) then
          Undo_Set({'cycledata'})
          trackfxparam_select = ctl_select[1].ctl
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata = Cycle_CopySelectOut()
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].cycledata.pos = cycle_select.selected
          strips[tracks[track_select].strip][page].controls[trackfxparam_select].dirty = true
          show_cycleoptions = false
          cycle_editmode = false
          lupd.update_gfx = true
        end

        if MOUSE_click(obj.sections[107]) then
          cycle_select.mapptof = not cycle_select.mapptof
          mapptof_select = cycle_select.mapptof
          lupd.update_gfx = true
        elseif MOUSE_click(obj.sections[111]) then
          cycle_select.invert = not cycle_select.invert
          invert_select = cycle_select.invert
          lupd.update_gfx = true
        elseif MOUSE_click(obj.sections[108]) then
          cycle_select.draggable = not cycle_select.draggable
          draggable_select = cycle_select.draggable
          lupd.update_gfx = true
        elseif MOUSE_click(obj.sections[109]) then
          cycle_select.spread = not cycle_select.spread
          spread_select = cycle_select.spread
          lupd.update_gfx = true
        end

      elseif mouse.mx > obj.sections[10].x then

        --SURFACE

        if mouse.context == nil and MOUSE_click(obj.sections[10]) then
          UnhideCtls() 
          
          if strips and tracks[track_select] and strips[tracks[track_select].strip] then

            if lvar.selctl then
              if lvar.selctl.switchsel then
                local sw = switchers[lvar.selctl.switchsel]
                if sw and sw.switchmode == 1 then
                  local ctl = strips[tracks[track_select].strip][page].controls[lvar.selctl.ctl]
                  if ctl --[[and sw.dropx and sw.dropy]] then
                    local bs = lvar.swdropsz*lvar.zoom
                    local objswdrop = {x = ctl.xsc*lvar.zoom + (sw.dropx or 0)*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                                       y = ctl.ysc*lvar.zoom + (sw.dropy or ctl.hsc)*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                                       w = bs, h = bs}
                    if MOUSE_click(objswdrop) then
                      mouse.context = contexts.swdrop
                      stripswitch_droploc = {drag = true, c = lvar.selctl.ctl, swid = lvar.selctl.switchsel, x = sw.dropx or mouse.mx, y = sw.dropy or mouse.my}
                    end
                  end
                end
              end
            end
            if not stripswitch_droploc then
              local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
              if c then

                octlsel = table.copy(ctl_select)
                ogfxsel = table.copy(gfx3_select)

                local i = c
                local ctl = strips[tracks[track_select].strip][page].controls[i]
                if i ~= lvar.ctlpreview_sel then
                  lvar.ctlpreview_sel = i
                  lupd.update_surface = true
                end


                  if Switcher_CtlsHidden(ctl.switcher, ctl.grpid) == false then
                    show_cycleoptions = false

                    lupd.update_cbox = true

                    local found = false
                    local j, ctlsel
                    if ctl_select ~= nil then
                      for j = 1, #ctl_select do
                        if tonumber(ctl_select[j].ctl) == tonumber(i) then
                          found = true
                          ctlsel = j
                          break
                        end
                      end
                    end

                    if mouse.alt then
                      local stripid = strips[tracks[track_select].strip][page].controls[i].id
                      if stripid ~= nil then
                        --A_HideSelectedCtls(false, ctl_select, gfx3_select)
                        ctl_select = nil
                        gfx3_select = nil
                        SelectStripElements(stripid)
                      else
                        if ctl_select == nil then
                          ctl_select = {}
                          ctl_select[1] = {ctl = i}
                        else
                          local cs = #ctl_select+1
                          ctl_select[cs] = {}
                          ctl_select[cs].ctl = i
                          ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
                          ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
                        end
                      end

                    elseif settings_groupsel == true or (settings_groupsel == false and mouse.shift or (mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2)) then
                      local switcherid = strips[tracks[track_select].strip][page].controls[i].switcherid
                      if mouse.ctrl == true then
                        if ctl_select == nil then ctl_select = {} end
                        if found == false then
                          local cs = #ctl_select+1
                          ctl_select[cs] = {}
                          ctl_select[cs].ctl = i
                          ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
                          ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
                        else
                          local cnt = #ctl_select
                          ctl_select[ctlsel] = nil
                          ctl_select = Table_RemoveNils(ctl_select, cnt)
                          if #ctl_select == 0 then ctl_select = nil end
                        end
                        lupd.update_ctlopts = true

                      elseif switcherid then
                        SelectSwitchElements(switcherid,i)
                      else
                        if settings_groupsel == true and mouse.shift == true then
                          --A_HideSelectedCtls(false, ctl_select, gfx3_select)
                          local grpid = strips[tracks[track_select].strip][page].controls[i].grpid
                          if grpid ~= nil then
                            ctl_select = SelectGroupElements(grpid, ctl_select)
                          else
                            if found == false then
                              if ctl_select == nil then ctl_select = {} end
                              local cs = #ctl_select+1
                              ctl_select[cs] = {}
                              ctl_select[cs].ctl = i
                              if cs ~= 1 then
                                ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
                                ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
                              end
                            end
                          end
                        else
                          local grpid = strips[tracks[track_select].strip][page].controls[i].grpid
                          if grpid ~= nil then
                            --if not mouse.shift then
                              --A_HideSelectedCtls(false, ctl_select, gfx3_select)
                              ctl_select = nil
                              gfx3_select = nil
                            --end
                            ctl_select = SelectGroupElements(grpid)
                          else
                            --if ctl_select == nil then
                              --A_HideSelectedCtls(false, ctl_select, gfx3_select)
                              ctl_select = {}
                              ctl_select[1] = {ctl = i}
                            --end
                          end
                        end
                      end

                    elseif mouse.ctrl and ctl_select ~= nil and found == true then
                      if ctlsel then
                        local cnt = #ctl_select
                        ctl_select[ctlsel] = nil
                        ctl_select = Table_RemoveNils(ctl_select, cnt)
                        if #ctl_select == 0 then ctl_select = nil end
                        lupd.update_ctlopts = true
                      end

                    elseif mouse.ctrl and ctl_select ~= nil and found == false then
                      local cs = #ctl_select+1
                      ctl_select[cs] = {}
                      ctl_select[cs].ctl = i
                      ctl_select[cs].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[i].x
                      ctl_select[cs].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[i].y
                      lupd.update_ctlopts = true
                    elseif ctl_select == nil or found == false then
                      --A_HideSelectedCtls(false, ctl_select, gfx3_select)
                      ctl_select = {}
                      gfx3_select = nil
                      ctl_select[1] = {ctl = i}
                      lupd.update_ctlopts = true
                    end

                    SetCtlSelectVals()
                    SetPosLockCtl()

                    if ctl_select then
                      if c then
                        for cc = 1, #ctl_select do
                          if ctl_select[cc].ctl == c then
                            local tmpc = ctl_select[1].ctl
                            ctl_select[1].ctl = c
                            ctl_select[cc].ctl = tmpc
                            ReselectSelection()
                            break
                          end
                        end
                      end
                      local cs = ctl_select[1].ctl
                      dragoff = {x = mouse.mx - strips[tracks[track_select].strip][page].controls[cs].x
                                     - 0.5*strips[tracks[track_select].strip][page].controls[cs].w - surface_offset.x,
                                 y = mouse.my - strips[tracks[track_select].strip][page].controls[cs].y
                                     - 0.5*strips[tracks[track_select].strip][page].controls[cs].ctl_info.cellh - surface_offset.y}
                      mouse.context = contexts.dummy
                      if --[[ctl_select ~= nil and]] not mouse.ctrl then --and not mouse.alt then
                        --dragctl = 'dragctl'
                        mouse.context = contexts.dragctl_timer
                        dragctl_timer = reaper.time_precise() + 0.2
                        --lvar.dc = {mx = mouse.mx, my = mouse.my}

                        if #ctl_select == 1 then
                          local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
                          if ctl then
                            if ctl.ctlcat == ctlcats.switcher then
                              lvar.selctl = {ctl = ctl_select[1].ctl,
                                             switchsel = ctl.switcherid}
                            else
                              if lvar.selctl then
                                lvar.selctl = nil
                                lupd.update_surface = true
                              end
                            end
                          else
                            if lvar.selctl then
                              lvar.selctl = nil
                              lupd.update_surface = true
                            end
                          end
                        else
                          if lvar.selctl then
                            lvar.selctl = nil
                            lupd.update_surface = true
                          end
                        end

                        --GenCtlDragPreview(gui)
                        --A_HideSelectedCtls(true, ctl_select, gfx3_select)
                        lupd.update_ctlopts = true
                      
                        --double click control
                        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                          local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
                          if ctl.ctlcat == ctlcats.macro then
                            setmode(1)
                            lvar.macro_returnedit = fxmode+2
                            macroedittype_select = 0
                            macro_edit_mode = true
                            macroedit_poffs = 0
                            trackfxparam_select = i
                            macroctl_select = trackfxparam_select
                            RedrawGUIBitmap()
                            --lupd.update_surface = true
                            lupd.update_gfx = true                          
                          end
                        end
                      else
                        if lvar.selctl then
                          lvar.selctl = nil
                          lupd.update_surface = true
                        end
                      end
                      if settings_dragmode == false then
                        lupd.update_bg = true
                      end
                    else
                      if lvar.selctl then
                        lvar.selctl = nil
                        lupd.update_surface = true
                      end
                    end

                    if settings_dragmode == false then
                      lupd.update_gfx = true
                    else
                      if octlsel then
                        for c = 1, #octlsel do
                          SetCtlDirty(octlsel[c].ctl)
                        end
                      end
                      if ctl_select then
                        for c = 1, #ctl_select do
                          SetCtlDirty(ctl_select[c].ctl)
                        end
                      end
                      lupd.update_ctls = true
                      movefrom_sc = nil
                    end
                    --break
                  end
                --end
              else
                lvar.selctl = nil
                lvar.ctlpreview_sel = nil
                lupd.update_cbox = true
                lupd.update_surface = true
              end
            end
          end
        elseif mouse.context == nil and MOUSE_click_RB(obj.sections[10]) then
          mouse.context = contexts.draglasso
          local cs, gs
          if mouse.ctrl then
            cs = table.copy(ctl_select)
            gs = table.copy(gfx3_select)
          end
          lasso = {l = mouse.mx, t = mouse.my, r = mouse.mx+5, b = mouse.my+5, ctl_select = cs, gfx3_select = gs}
        end
      end

      if mouse.context and mouse.context == contexts.auto_delayslider then
        local val = F_limit(MOUSE_sliderHBar(obj.sections[110]),0,1)
        if val ~= nil then
          auto_delay = math.floor(val * 10)
          lupd.update_gfx = true
        end
      elseif mouse.context == contexts.wwdrag then

        local objsec = obj.sections[868]

        local mx, my = mouse.mx, mouse.my
        mouse.mx = mx - obj.sections[45].x
        mouse.my = my - obj.sections[45].y
        local ctls = strips[tracks[track_select].strip][page].controls
        local ctl = ctls[ctl_select[1].ctl]

        local val = F_limit(MOUSE_slider(objsec),0,1)
        if val ~= nil then
          val = 1-val
          wwtext_select = F_limit(ctlpos + math.floor((val-0.5)*(ctl.wsc*2)),0,ctl.wsc*2)
          for c = 1, #ctl_select do
            ctls[ctl_select[c].ctl].wwtext = wwtext_select
            ctls[ctl_select[c].ctl].wwdata = nil
          end
          GenCtlDragPreview(gui)
          lupd.update_surface = true
          lupd.update_ctlopts = true
          --lupd.update_gfx = true
        end

        mouse.mx = mx
        mouse.my = my

      elseif mouse.context == contexts.gridslider then
        local mx, my = mouse.mx, mouse.my
        mouse.mx = mx - obj.sections[3000].x
        mouse.my = my - obj.sections[3000].y

        local val = F_limit(MOUSE_slider(obj.sections[3001]),0,1)
        if val ~= nil then
          val = 1-val
          settings_gridsize = F_limit(ctlpos + math.floor((val-0.5)*200),1,128)
          ogrid = settings_gridsize
          if settings_gridsize < 4 then
            settings_showgrid = false
          else
            settings_showgrid = nz(osg,true)
          end
          lupd.update_gfx = true
        end

        mouse.mx = mx
        mouse.my = my

      elseif mouse.context and mouse.context == contexts.knobsens_norm then
        local objsec = obj.sections[135]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 20)*0.5

          knobsens_select.norm = v
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.norm = v
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
        end
      elseif mouse.context and mouse.context == contexts.knobsens_fine then
        local objsec = obj.sections[136]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 20)*0.01
          knobsens_select.fine = v
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.fine = v
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
        end
      elseif mouse.context and mouse.context == contexts.knobsens_wheel then
        local objsec = obj.sections[137]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 20)*0.01
          knobsens_select.wheel = v
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.wheel = v
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
        end
      elseif mouse.context and mouse.context == contexts.knobsens_wheelfine then
        local objsec = obj.sections[138]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 20)*0.001
          knobsens_select.wheelfine = v
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].knobsens.wheelfine = v
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
        end

      elseif mouse.context and mouse.context == contexts.minov then
        local objsec = obj.sections[128]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = MOUSE_slider(xywh,mouse.slideoff)
        if val ~= nil then
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = minov_select
            mouse.slideoff = obj.sections[128].y+obj.sections[128].h/2 - (mouse.my-obj.sections[45].y)
          else
            if mouse.shift then
              val = ctlpos + ((0.5-val)*2)*0.0125
            else
              val = ctlpos + (0.5-val)*1
            end
            local p = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].param
            local min, max = GetParamMinMax_ctl(ctl_select[1].ctl, false) --trctls_table[p].min, trctls_table[p].max

            if val < min then val = min end
            if val > max then val = max end
            if val ~= octlval then
              val = math.min(val,nz(maxov_select-0.05,1))
              SetParam4(val)
              local dval = GetParamDisp_Ctl(ctl_select[1].ctl)
              minov_select = val
              ov_disp = dval
              SetParam()
              octlval = val
              lupd.update_ctls = true
              lupd.update_ctlopts = true
            end
          end
        elseif minov_act ~= nil then
          minov_act = nil

          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].minov = minov_select
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            trackfxparam_select = ctl_select[i].ctl

            local min, max = GetParamMinMax_ctl(ctl_select[i].ctl)
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval = normalize(min, max, ctl_select[i].denorm_defval)
            SetParam3(tracks[track_select].strip,page,ctl_select[i].ctl,strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl],
                      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval)
          end
        end

      elseif mouse.context and mouse.context == contexts.maxov then
        local objsec = obj.sections[129]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = MOUSE_slider(xywh,mouse.slideoff)
        if val ~= nil then
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = maxov_select
            mouse.slideoff = obj.sections[129].y+obj.sections[129].h/2 - (mouse.my-obj.sections[45].y)
          else
            if mouse.shift then
              val = ctlpos + ((0.5-val)*2)*0.1
            else
              val = ctlpos + (0.5-val)*2
            end
            local p = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].param
            local min, max = GetParamMinMax_ctl(ctl_select[1].ctl, false) --trctls_table[p].min, trctls_table[p].max

            if val < min then val = min end
            if val > max then val = max end
            if val ~= octlval then
              val = math.max(val,nz(minov_select+0.05,0))
              SetParam4(val)
              local dval = GetParamDisp_Ctl(ctl_select[1].ctl)
              maxov_select = val
              ov_disp = dval
              SetParam()
              octlval = val
              lupd.update_ctls = true
              lupd.update_ctlopts = true
            end
          end
        elseif maxov_act ~= nil then
          maxov_act = nil

          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].maxov = maxov_select
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            trackfxparam_select = ctl_select[i].ctl

            local min, max = GetParamMinMax_ctl(ctl_select[i].ctl)
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval = normalize(min, max, ctl_select[i].denorm_defval)
            SetParam3(tracks[track_select].strip,page,ctl_select[i].ctl,strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl],
                      strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval)
          end
        end

      elseif mouse.context and mouse.context == contexts.cycleknob then
        local val = MOUSE_slider(obj.sections[101],mouse.slideoff)
        if val ~= nil then
          if oms ~= mouse.shift then
            oms = mouse.shift
            ctlpos = cycle_select.val
            mouse.slideoff = obj.sections[101].y+obj.sections[101].h/2 - mouse.my
          else
            if mouse.shift then
              val = ctlpos + ((0.5-val)*2)*0.1
            else
              val = ctlpos + (0.5-val)*2
            end
            local min,max = 0,1
            local c = ctl_select[1].ctl
            local strip = tracks[track_select].strip
            local ctl = strips[strip][page].controls[c]
            if ctl.ctlcat == ctlcats.fxparam then
              min, max = GetParamMinMax_ctl(c)
            elseif ctl.ctlcat == ctlcats.statectl then
              local vv = ctl.stateinfo.min + round((val * (ctl.stateinfo.max-ctl.stateinfo.min))/ctl.stateinfo.step)*ctl.stateinfo.step
              val = (vv-ctl.stateinfo.min)/(ctl.stateinfo.max-ctl.stateinfo.min)
            end
            if val < tonumber(min) then val = tonumber(min) end
            if val > tonumber(max) then val = tonumber(max) end
            if val ~= octlval then
              SetParam3(strip,page,c,ctl,val)
              local t = strips[strip].track.tracknum
              if ctl.tracknum ~= nil then
                t = ctl.tracknum
              end
              local cc = ctl.ctlcat
              local f = ctl.fxnum
              local p = ctl.param
              local dvoff = ctl.dvaloffset
              local v2 = GetParamValue(cc,t,f,p,c)
              cycle_select.val = val

              if cycle_select.selected and cycle_select[cycle_select.selected] then
              --if cycle_select.selected then
                local dispval = GetParamDisp(cc, t, f, p, dvoff,c)
                cycle_select[cycle_select.selected].val = v2
                cycle_select[cycle_select.selected].dispval = dispval
                cycle_select[cycle_select.selected].dv = dispval
              end
              octlval = val
              --SetParam()
              ctl.dirty = true
              lupd.update_ctls = true
            end
          end
        end
 
      elseif mouse.context == contexts.adjust_bright then
        local objsec = obj.sections[8050]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 512)

          adjust_bright_select = v
          adjust_active_select = 1
          local ctls = strips[tracks[track_select].strip][page].controls
          for i = 1, #ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
            ctl.adjust.bright = v
            ctl.adjust_active = 1
            
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
          lupd.update_ctls = true
        end

      elseif mouse.context == contexts.adjust_contrast then
        local objsec = obj.sections[8050]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 512)

          adjust_contrast_select = v
          adjust_active_select = 1
          local ctls = strips[tracks[track_select].strip][page].controls
          for i = 1, #ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
            ctl.adjust.contrast = v
            ctl.adjust_active = 1
            
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
          lupd.update_ctls = true
        end

      elseif mouse.context == contexts.adjust_r then
        local objsec = obj.sections[8050]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 512)
      
          adjust_r_select = v
          adjust_active_select = 1
          local ctls = strips[tracks[track_select].strip][page].controls
          for i = 1, #ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
            ctl.adjust.r = v
            ctl.adjust_active = 1
            
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
          lupd.update_ctls = true
        end
      
      elseif mouse.context == contexts.adjust_g then
        local objsec = obj.sections[8050]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 512)
      
          adjust_g_select = v
          adjust_active_select = 1
          local ctls = strips[tracks[track_select].strip][page].controls
          for i = 1, #ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
            ctl.adjust.g = v
            ctl.adjust_active = 1
            
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
          lupd.update_ctls = true
        end
      
      elseif mouse.context == contexts.adjust_b then
        local objsec = obj.sections[8050]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          local v = math.floor(val * 512)
      
          adjust_b_select = v
          adjust_active_select = 1
          local ctls = strips[tracks[track_select].strip][page].controls
          for i = 1, #ctl_select do
            local ctl = ctls[ctl_select[i].ctl]
            ctl.adjust = ctl.adjust or {bright = 255, contrast = 255, r = 255, g = 255, b = 255}
            ctl.adjust.b = v
            ctl.adjust_active = 1
            
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_surface = true
          lupd.update_ctlopts = true
          lupd.update_ctls = true
        end
      end

      if mouse.context == contexts.resize_ctlbrowser then

        local dx = mouse.mx - lvar.cbwinrsz.mx
        obj.sections[200].x = lvar.cbwinrsz.x + dx
        obj.sections[200].w = math.max(lvar.cbwinrsz.w - dx,120)
        lvar.ctlbrowser_docked_w = obj.sections[200].w

        SetSurfaceSize2(obj)
        obj = GetObjects()
        lupd.update_surface = true

        if not lvar.resizetimer then
          lvar.slotsx = -1
          lvar.slotsy = -1
          if ctl_browser_size then
            lvar.slotsx = ctl_browser_size.slots_x
            lvar.slotsy = ctl_browser_size.slots_y
          end
        end
        lvar.resizetimer = rt+0.25

      elseif mouse.context and mouse.context == contexts.move_ctlopts then

        obj.sections[45].x = F_limit(mouse.mx-movectlopts.dx,obj.sections[10000].x,obj.sections[10000].x+obj.sections[10000].w-obj.sections[45].w)
        obj.sections[45].y = F_limit(mouse.my-movectlopts.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[45].h)

        local cw, ch = 160*pnl_scale, 380*pnl_scale
        obj.sections[100].x = obj.sections[45].x - cw - 10
        if obj.sections[100].x < obj.sections[10000].x then
          obj.sections[100].x = obj.sections[45].x + obj.sections[45].w + 10
        end
        obj.sections[100].y = obj.sections[45].y + obj.sections[45].h - ch
        obj = PosCycleCtls(obj)

        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.scaleslider then
        ctlscaling = true
        local objsec = obj.sections[50]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          scale_select = val*1 + 0.5
          for i = 1, #ctl_select do
            if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctlcat ~= ctlcats.xy then
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].scale = scale_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].xsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
                                                                                         + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w/2
                                                                                         - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select)/2)
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ysc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y
                                                                                         + math.floor(strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh/2
                                                                                         - (strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select)/2)
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].w*scale_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].hsc = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctl_info.cellh*scale_select
            end
          end
          --lupd.update_gfx = true
          GenCtlDragPreview(gui)
          lupd.update_surface = true
          lupd.update_ctlopts = true
        end

      elseif ctlscaling then
        ctlscaling = nil
        --if movefrom_sc ~= nil then
          if selrect_sc then
            movefrom_sc = table.copy(selrect_sc)
          else
            movefrom_sc = nil
          end
        --end
        lupd.update_gfx = true
      end

      if mouse.context and mouse.context == contexts.offsetslider then
        local objsec = obj.sections[56]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          if toffY then
            textoff_select = val*300 - 150
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoff = textoff_select
              --strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            end
          else
            textoff_selectx = val*300 - 150
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffx = textoff_selectx
              --strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            end
          end
          GenCtlDragPreview(gui)
          lupd.update_surface = true
          lupd.update_ctlopts = true
          --lupd.update_gfx = true
        end
      end

      if mouse.context and mouse.context == contexts.valoffsetslider then
        local objsec = obj.sections[65]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          if toffY then
            textoffval_select = val*300 - 150
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffval = textoffval_select
            end
          else
            textoffval_selectx = val*300 - 150
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textoffvalx = textoffval_selectx
            end
          end
          GenCtlDragPreview(gui)
          lupd.update_surface = true
          lupd.update_ctlopts = true
          --lupd.update_gfx = true
        end
      end

      if mouse.context and mouse.context == contexts.textsizeslider then
        textresize = true
        local objsec = obj.sections[58]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          textsize_select = (val*35)-2
          if textoptlink_select == true then
            textsizev_select = textsize_select
          end
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsize = textsize_select
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
            if textoptlink_select == true then
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsizev = textsize_select
            end
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_ctls = true
          lupd.update_ctlopts = true
          --lupd.update_bg = true
          --lupd.update_gfx = true
        end
      elseif mouse.context and mouse.context == contexts.textsizevslider then
        textresize = true
        local objsec = obj.sections[851]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        if val ~= nil then
          textsizev_select = (val*35)-2
          if textoptlink_select == true then
            textsize_select = textsizev_select
          end
          for i = 1, #ctl_select do
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsizev = textsizev_select
            if textoptlink_select == true then
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].textsize = textsizev_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].wwdata = nil
            end
            strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].dirty = true
            SetCtlDirty(ctl_select[i].ctl)
          end
          lupd.update_ctls = true
          lupd.update_ctlopts = true
          --lupd.update_gfx = true
        end
      elseif mouse.context == nil and textresize then
        textresize = nil
        lupd.update_gfx = true
      end

      if mouse.context and mouse.context == contexts.defvalslider then
        local objsec = obj.sections[57]
        local xywh = {x = obj.sections[45].x + objsec.x,
                      y = obj.sections[45].y + objsec.y,
                      w = objsec.w,
                      h = objsec.h}
        local val = F_limit(MOUSE_sliderHBar(xywh),0,1)
        local upd = false
        if mouse.ctrl then
          if mouse.mx ~= omx then
            if mouse.mx > omx then val = 0.002 else val = -0.002 end
            omx = mouse.mx
            val = F_limit(defval_select+val, 0, 1)
            upd = true
          end
        elseif val ~= nil then
          if mouse.shift then val = round(val*4,0)/4 end
          upd = true
          val = F_limit(val, 0, 1)
        end
        if val ~= octlval and upd then
          defval_select = val
          octlval = val
          for i = 1, #ctl_select do
            if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].ctltype == 4 then
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval = defval_select
            else
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].val = defval_select
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].defval = defval_select
            end
            trackfxparam_select = ctl_select[i].ctl
            SetParam_ToDef(trackfxparam_select)
          end
          lupd.update_ctls = true
          lupd.update_ctlopts = true
        end
      end

      if mouse.context and mouse.context == contexts.dragctl_timer then
        if reaper.time_precise() > dragctl_timer then

          Undo_Set({'x','xsc','y','ysc','grpid'})

          dragctl = 'dragctl'
          mouse.context = contexts.dragctl
          GenCtlDragPreview(gui)
          A_HideSelectedCtls(true, ctl_select, gfx3_select)
          lupd.update_surface = true
        end

      elseif mouse.context and mouse.context == contexts.dragctl then

        local ctls = strips[tracks[track_select].strip][page].controls
        newgrp = nil
        vert = true
        local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
        if c then
          local i = c
          local ctl = strips[tracks[track_select].strip][page].controls[i]
          if ctl.ctlcat == ctlcats.switcher and SwitcherInSelected(ctl.switcherid) == false then
            local swid = ctl.switcherid
            if swid and switchers[swid].switchmode ~= 1 then
              local x = mouse.mx -obj.sections[10].x+surface_offset.x*lvar.zoom
              local y = mouse.my -obj.sections[10].y+surface_offset.y*lvar.zoom

              if x > (ctl.x*lvar.zoom)+(ctl.w*lvar.zoom)/2 then
                vert = false
              end
              newgrp = {grpid = switchers[ctl.switcherid].current,
                        switchid = i,
                        vert = vert}
            end
          end
        end

        if newgrp then

          local rl, rt, rr, rb = GetLTRBControlInGrp(newgrp.grpid, newgrp.switchid)

          if math.floor(mouse.mx) ~= math.floor(mouse.last_x) or math.floor(mouse.my) ~= math.floor(mouse.last_y) then
            local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
            local scale = ctl.scale

            local zx, zy = rl, rb
            if newgrp.vert == false then
              zx, zy = rr, rt
            end

            local mrelx, mrely = 0,0
            if #ctl_select > 1 then
              for cs = 2, #ctl_select do
                mrelx = math.max(mrelx, ctl_select[cs].relx)
                mrely = math.max(mrely, ctl_select[cs].rely)
              end
              if gfx3_select then
                for cs = 1, #gfx3_select do
                  mrelx = math.max(mrelx, gfx3_select[cs].relx)
                  mrely = math.max(mrely, gfx3_select[cs].rely)
                end
              end
            end
            local zzx, zzy = zx, zy
            zx = zx + mrelx
            zy = zy + mrely

            local dx, dy
            if nz(ctl.poslock,false) == false then
              ctl.x = zx
              ctl.y = zy
              ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
              ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)

              if ctl.xsc < zzx then
                dx = math.max(dx or 0, zzx - ctl.xsc)
              end
              if ctl.ysc < zzy then
                dy = math.max(dy or 0, zzy - ctl.ysc)
              end
            end

            if #ctl_select > 1 then
              for i = 2, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

                if nz(ctl.poslock,false) == false then
                  scale = ctl.scale
                  ctl.x = zx - ctl_select[i].relx
                  ctl.y = zy - ctl_select[i].rely
                  ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
                  ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)

                  if ctl.xsc < zzx then
                    dx = math.max(dx or 0, zzx - ctl.xsc)
                  end
                  if ctl.ysc < zzy then
                    dy = math.max(dy or 0, zzy - ctl.ysc)
                  end
                end
              end
              if dx or dy then
                --DBG(zzy..' = '..(dy or 'nnil')..' dx '..zzx..' = '..(dx or 'nnil'))
                for i = 1, #ctl_select do
                  local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

                  if nz(ctl.poslock,false) == false then
                    scale = ctl.scale
                    ctl.x = ctl.x + (dx or 0)
                    ctl.y = ctl.y + (dy or 0)
                    ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
                    ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
                  end
                end
              end
            end

            if gfx3_select and #gfx3_select > 0 then
              for i = 1, #gfx3_select do
                local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]
                ctl.x = zx - gfx3_select[i].relx + (dx or 0)
                ctl.y = zy - gfx3_select[i].rely + (dy or 0)
              end
            end
            lupd.update_surface = true
          end

        else

          if math.floor(mouse.mx/settings_gridsize) ~= math.floor(mouse.last_x/settings_gridsize) or math.floor(mouse.my/settings_gridsize) ~= math.floor(mouse.last_y/settings_gridsize) then
            local i
            local cs = ctl_select[1].ctl
            local ctl = strips[tracks[track_select].strip][page].controls[cs]
            local scale = ctl.scale
            local zx, zy = 0.5*ctl.w, 0.5*ctl.ctl_info.cellh

            local mxx, myy = (mouse.mx - obj.sections[10].x + surface_offset.x*lvar.zoom)/lvar.zoom,
                             (mouse.my - obj.sections[10].y + surface_offset.y*lvar.zoom)/lvar.zoom
            if nz(ctl.poslock,false) == false then

              if (lvar.lockx or false) == false then
                ctl.x = math.floor((--[[mouse.mx]]mxx-zx --[[- surface_offset.x]])/settings_gridsize)*settings_gridsize
                                                                                 -- math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
                ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
              end
              if (lvar.locky or false) == false then
                ctl.y = math.floor((--[[mouse.my]]myy-zy --[[- surface_offset.y]])/settings_gridsize)*settings_gridsize
                                                                                   -- math.floor((dragoff.y)/settings_gridsize)*settings_gridsize
                ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              end
            end
            if #ctl_select > 1 then
              for i = 2, #ctl_select do
                local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

                if nz(ctl.poslock,false) == false then
                  scale = ctl.scale
                  if (lvar.lockx or false) == false then
                    ctl.x = math.floor((mxx-zx --[[- surface_offset.x]])/settings_gridsize)*settings_gridsize
                             -- math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
                             - ctl_select[i].relx
                    ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
                  end
                  if (lvar.locky or false) == false then
                    ctl.y = math.floor((myy-zy --[[- surface_offset.y]])/settings_gridsize)*settings_gridsize
                             -- math.floor((dragoff.y)/settings_gridsize)*settings_gridsize
                             - ctl_select[i].rely
                    ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
                  end
                end
              end
            end
            if gfx3_select and #gfx3_select > 0 then
              for i = 1, #gfx3_select do
                local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]
                if (lvar.lockx or false) == false then
                  ctl.x = math.floor((mxx-zx --[[- surface_offset.x]])/settings_gridsize)*settings_gridsize
                                 -- math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
                                 - gfx3_select[i].relx
                end
                if (lvar.locky or false) == false then
                  ctl.y = math.floor((myy-zy --[[- surface_offset.y]])/settings_gridsize)*settings_gridsize
                                 -- math.floor((dragoff.y)/settings_gridsize)*settings_gridsize
                                 - gfx3_select[i].rely
                end
              end
            end
            lupd.update_surface = true
            lupd.update_cbox = true
          end
        end

      elseif mouse.context == nil and dragctl ~= nil and keycontext == nil and wheelcontext == nil then
        dragctl = nil
        movefrom_sc = nil
        if MOUSE_over(obj.sections[60]) then
          --delete
          DeleteSelectedCtls()
          lupd.update_gfx = true
        else
          DropCtls()
        end
        if lvar.grid == nil or lvar.grid == true then
          lvar.grid = true
          settings_gridsize = ogrid
        end
        UnhideCtls()
        SetCtlBitmapRedraw()

      end

      if mouse.context and mouse.context == contexts.draglasso then
        if math.abs(lasso.l - mouse.mx) > 10 or math.abs(lasso.t - mouse.my) > 10 then
          lasso.r = mouse.mx
          lasso.b = mouse.my
          lasso.trig = true
          Lasso_Select(mouse.shift)
          if ctl_select ~= nil then
            SetCtlSelectVals()
          end
          SetPosLockCtl()
          movefrom_sc = nil
          lupd.update_ctls = true
          lupd.update_cbox = true
        end

      elseif lasso ~= nil then
        --Dropped

        if math.abs(lasso.l-lasso.r) < 10 and math.abs(lasso.t-lasso.b) < 10 then
        -- == mouse.mx and lasso.t == mouse.my then
          if lasso.trig ~= true and ctl_select then
            --[[if #ctl_select == 1 and strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].ctlcat == ctlcats.switcher then
              switcher_select = ctl_select[1].ctl
              SwitcherMenu_RB()
            else]]
              RBMenu_Edit()
            --end
          else
            local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
            if c then
              if strips[tracks[track_select].strip][page].controls[c].ctlcat == ctlcats.switcher then
                switcher_select = c
                SwitcherMenu_RB()
              elseif strips[tracks[track_select].strip][page].controls[c].ctlcat == ctlcats.rcm_switch then
                rcm_select = c
                RCMMenu_RB()
              end
            else

              local cp
              local cpp = ''
              if copy_ctls == nil then
                cpp = '#'
              end

              cp = cpp..'Paste||Check Control Assignments||Repatriate Lost Controls'
              local mstr = cp
              gfx.x, gfx.y = mouse.mx, mouse.my
              local res = OpenMenu(mstr)
              if res == 1 then
                local keep_coords
                if mouse.shift then
                  keep_coords = true
                end
                Paste_Selected(keep_coords)

                SetCtlBitmapRedraw()
                ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
                lupd.update_gfx = true

              elseif res == 2 then
              
                CheckControlAssignments()
              
              elseif res == 3 then
                RepatriateControls()
              end
            end
          end

        end

        lasso = nil
        lupd.update_ctls = true
        lupd.update_ctlopts = true
      end

      if MOUSE_click(obj.sections[521]) then
        if mouse.mx > obj.sections[521].w-40 then
          show_paramlearn = not show_paramlearn
          lupd.update_gfx = true
        else
          trackedit_select = trackedit_select + 1
          if trackedit_select > #tracks then
            trackedit_select = -1
          end
          PopulateTrackFX()
          PopulateTrackSendsInfo()
          PopulateSpecial()
          trctlslist_offset = 0
          lupd.update_gfx = true
        end
      elseif MOUSE_click_RB(obj.sections[521]) then
        trackedit_select = trackedit_select - 1
        if trackedit_select < -1 then
          trackedit_select = #tracks
        end
        PopulateTrackFX()
        PopulateTrackSendsInfo()
        PopulateSpecial()
        lupd.update_gfx = true

      elseif MOUSE_click(obj.sections[523]) then

        mouse.context = contexts.dragsep_fx
        dragsep_fx = {y = mouse.my, oh = fx_h}

      end

      if fxmode == 0 then
        if MOUSE_click(obj.sections[525]) then

          local msbh = obj.sections[525].h
          local p1 = 1 / (#trackfx+1)
          local sbh = math.ceil(F_limit(p1*(F_butt_cnt-1) * msbh,20,msbh))
          local p2 = p1*msbh
          local sby = math.floor(flist_offset * p2)

          sby = math.min(sby,msbh-sbh-1)

          if mouse.my >= obj.sections[525].y + sby and mouse.my <= obj.sections[525].y + sby+sbh then

            if F_butt_cnt-1 < #trackfx+1 then
              mouse.context = contexts.scrollfx
              scrollsidebar = {y = mouse.my-obj.sections[525].y, lo = flist_offset}
              lupd.update_sidebar = true
            else
              flist_offset = 0
            end

          elseif mouse.my < obj.sections[525].y + sby then

          elseif mouse.my > obj.sections[525].y + sby+sbh then

          end

        elseif MOUSE_click(obj.sections[520]) then
          local i = math.floor((mouse.my - obj.sections[520].y) / tb_butt_h)-1
          if i ~= -1 and mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
            if i == -1 then
            elseif i >= F_butt_cnt then
            elseif trackfx[i + flist_offset] then
              local track = GetTrack(tracks[trackedit_select].tracknum)
              if not reaper.TrackFX_GetOpen(track, i + flist_offset) then
                reaper.TrackFX_Show(track, i + flist_offset, 3)
              end
            else
              local otrack = reaper.GetSelectedTrack2(0,0,true)
              local track = GetTrack(tracks[trackedit_select].tracknum)
              reaper.SetOnlyTrackSelected(track)
              reaper.Main_OnCommand(40271,-1)
              reaper.SetOnlyTrackSelected(otrack)

            end

          else
            --local i = math.floor((mouse.my - obj.sections[520].y) / tb_butt_h)-1
            if i == -1 then
              if mouse.mx < obj.sections[520].w/4 then
                flist_offset = flist_offset - math.max(F_butt_cnt-2,1)
                if flist_offset < 0 then
                  flist_offset = 0
                end
              elseif mouse.mx < obj.sections[520].w/2 then
                if flist_offset + F_butt_cnt <= #trackfx+1 then
                  flist_offset = flist_offset + math.max(F_butt_cnt-2,1)
                end
              else
                lvar.tfx_type = lvar.trackfxtype_input - lvar.tfx_type
                PopulateTrackFX()
              end
              lupd.update_gfx = true
            elseif trackfx[i + flist_offset] then
              trackfx_select = i + flist_offset

              PopulateTrackFXParams()

              mouse.context = contexts.reassplugin
              reass_plugin = {fx = trackfx_select, time = rt}
              local w,h = gfx.getimgdim(998)
              if w == 0 or h == 0 then
                ksel_size = {w = 50*lvar.zoom, h = 50*lvar.zoom}
              else
                ksel_size = {w = (w*lvar.zoom/2), h = (h*lvar.zoom/2)}
              end
              lupd.update_gfx = true
            end
          end
        elseif MOUSE_click_RB(obj.sections[520]) then
          local i = math.floor((mouse.my - obj.sections[520].y) / tb_butt_h)-1
          if i > -1 and trackfx[i + flist_offset] then
            trackfx_select = i + flist_offset
            local track = GetTrack(tracks[trackedit_select].tracknum)
            --local chunk = GetTrackChunk(track, settings_usetrackchunkfix)
            --local fnd, fxc, s, e = GetFXChunkFromTrackChunk(chunk,i+1 + flist_offset)
            --local fxident = GetPlugIdentifierFromChunk(fxc)
            local _, fxident = reaper.BR_TrackFX_GetFXModuleName(track, trackfx[trackfx_select].fxnum, '', 64)
            fxident = string.lower(fxident)
            if plugdefstrips_idx then
              local idx = plugdefstrips_idx[fxident]
              if idx and plugdefstrips[idx] then
                --DBG(plugdefstrips[idx].stripfile)
                local sfol = plugdefstrips[idx].stripfol
                local sfil = plugdefstrips[idx].stripfile
                loadstrip = LoadStrip(nil, sfol, sfil)
                if loadstrip then

                  loadstrip.strip_w, loadstrip.strip_h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
                  loadstrip.plugpos = trackfx_select
                  loadstrip.plugtrack = trackedit_select
                  --if settings_stripautosnap == true then
                    stlay_data = AutoSnap_GetStripLocs(true)
                  --end
                  mouse.context = contexts.dragstrip
                end
                lupd.update_gfx = true
              end

              lupd.update_sidebar = true
            end
            --DBG(fxident)
          end


        end

        if MOUSE_click(obj.sections[524]) then

          local msbh = obj.sections[524].h
          local p1 = 1 / (#trackfxparams+1)
          local sbh = math.ceil(F_limit(p1*(P_butt_cnt-1) * msbh,20,msbh))
          local p2 = p1*msbh
          local sby = math.floor(plist_offset * p2)

          sby = math.min(sby,msbh-sbh-1)

          if mouse.my >= obj.sections[524].y + sby and mouse.my <= obj.sections[524].y + sby+sbh then

            if P_butt_cnt+1 < #trackfxparams+1 then
              mouse.context = contexts.scrollfxparams
              scrollsidebar = {y = mouse.my-obj.sections[524].y, lo = plist_offset, ss = ss}
              lupd.update_sidebar = true
            else
              plist_offset = 0
            end

          elseif mouse.my < obj.sections[524].y + sby then

          elseif mouse.my > obj.sections[524].y + sby+sbh then

          end

        elseif MOUSE_click(obj.sections[522]) then
          local i = math.floor((mouse.my - obj.sections[522].y) / tb_butt_h)-1
          --DBG(i.. '  '..tostring(trackfxparams[i + plist_offset])..'  '..i..'  '..plist_offset)

          local dp = true
          if i == -1 then
            if mouse.mx < obj.sections[522].w/2 then
              plist_offset = plist_offset - P_butt_cnt
              if plist_offset < 0 then
                plist_offset = 0
              end
            else
              if plist_offset + P_butt_cnt < #trackfxparams then
                plist_offset = plist_offset + P_butt_cnt
              end
            end
            lupd.update_gfx = true
          elseif trackfxparams[i + plist_offset] then
            trackfxparam_select = i + plist_offset
            if mouse.ctrl then
              if tfxp_sel == nil then
                tfxp_sel = {}
                tfxp_sel[i + plist_offset] = true
                tfxp_last = i + plist_offset
              elseif tfxp_sel[i + plist_offset] then
                --remove
                tfxp_sel[i + plist_offset] = nil
              else
                tfxp_sel[i + plist_offset] = true
                tfxp_last = i + plist_offset
              end
              dp = false
            elseif mouse.shift then
              if tfxp_sel == nil then
                tfxp_sel = {}
                tfxp_sel[i + plist_offset] = true
                tfxp_last = i + plist_offset
              else
                if tfxp_last == nil then

                else
                  local it = 1
                  if tfxp_last > i + plist_offset then
                    it = -1
                  end
                  tfxp_sel = {}
                  for p = tfxp_last, i + plist_offset, it do
                    tfxp_sel[p] = true
                  end
                  tfxp_last = i + plist_offset
                end
                dp = false
              end

            elseif tfxp_sel and tfxp_sel[i + plist_offset] then
              --do nothing but drag
              tfxp_last = i + plist_offset

            else
              tfxp_sel = {}
              tfxp_sel[i + plist_offset] = true
              tfxp_last = i + plist_offset
            end
            ctl_select = nil
            showctlbrowser(false)
            --[[if not lvar.ctlbrowser_docked then
              show_ctlbrowser = false
            end]]
            lupd.update_gfx = true

            if ctl_files[knob_select].imageidx ~= nil then
              local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
              local h = ctl_files[knob_select].cellh
              if w == 0 or h == 0 then
                ksel_size = {w = 50, h = 50}
              else
               ksel_size = {w = (w*lvar.zoom)/2, h = (h*lvar.zoom)/2}
             end
            else
              ksel_size = LoadTmpControl(knob_select)
            end
            if dp and trackfx[trackfx_select --[[+ flist_offset]]] then
              mouse.context = contexts.dragparam
            end
          end

        elseif MOUSE_click_RB(obj.sections[522]) then
          local i = math.floor((mouse.my - obj.sections[522].y) / tb_butt_h)-1
          if i == -1 then
            if mouse.mx < obj.sections[520].w/2 then
              plist_offset = 0
            else
              plist_offset = math.max(#trackfxparams - (P_butt_cnt)+2,0)
            end
            lupd.update_gfx = true
          else
            --PopulateCtlBrowser_Imgs()
            PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)

            cbi_select = knob_select

            SetCbiSelect()

            show_ctlbrowser = true
            lupd.update_surface = true
          end
        end

      elseif fxmode == 1 then

        if MOUSE_click(obj.sections[525]) then

          local msbh = obj.sections[525].h
          local p1 = 1 / (#lvar.trctltype_table)
          local sbh = math.ceil(F_limit(p1*(F_butt_cnt-1) * msbh,20,msbh))
          local p2 = p1*msbh
          local sby = math.floor(trctltypelist_offset * p2)

          sby = math.min(sby,msbh-sbh-1)

          if mouse.my >= obj.sections[525].y + sby and mouse.my <= obj.sections[525].y + sby+sbh then

            if F_butt_cnt-1 < #lvar.trctltype_table then
              mouse.context = contexts.scrollfx
              scrollsidebar = {y = mouse.my-obj.sections[525].y, lo = trctltypelist_offset}
              lupd.update_sidebar = true
            else
              trctltypelist_offset = 0
            end

          elseif mouse.my < obj.sections[525].y + sby then

          elseif mouse.my > obj.sections[525].y + sby+sbh then

          end

        elseif MOUSE_click(obj.sections[520]) then
          local i = math.floor((mouse.my - obj.sections[520].y) / tb_butt_h)-1
          if i == -1 then
            if mouse.mx < obj.sections[520].w/2 then
              trctltypelist_offset = trctltypelist_offset - math.max(F_butt_cnt-2,1)
              if trctltypelist_offset < 0 then
                trctltypelist_offset = 0
              end
            else
              if trctltypelist_offset + F_butt_cnt < #lvar.trctltype_table+1 then
                trctltypelist_offset = trctltypelist_offset + math.max(F_butt_cnt-2,1)
              end
            end
            lupd.update_gfx = true
          elseif lvar.trctltype_table[i + trctltypelist_offset+1] then
            trctltype_select = i + trctltypelist_offset
            trctlslist_offset = 0
            if i + trctltypelist_offset == 2 then
              PopulateSpecial()
            end
            lupd.update_gfx = true
          end
        end

        if MOUSE_click(obj.sections[524]) then

          local tblcnt = 0
          local tbloff = 1
          if trctltype_select == 0 then
            tblcnt = #trctls_table
          elseif trctltype_select == 1 then
            tblcnt = #trsends_table*3+2+1
          elseif trctltype_select == 2 then
            tblcnt = #lvar.special_table
            tbloff = 0
          elseif trctltype_select == 3 then
            tblcnt = #lvar.otherctl_table
            tbloff = 0
          end

          local msbh = obj.sections[524].h
          local p1 = 1 / tblcnt
          local sbh = math.ceil(F_limit(p1*(P_butt_cnt-1) * msbh,20,msbh))
          local p2 = p1*msbh
          local sby = math.floor(trctlslist_offset * p2)

          sby = math.min(sby,msbh-sbh-1)

          if mouse.my >= obj.sections[524].y + sby and mouse.my <= obj.sections[524].y + sby+sbh then
            if P_butt_cnt-1 < tblcnt+tbloff then
              mouse.context = contexts.scrollfxparams
              scrollsidebar = {y = mouse.my-obj.sections[524].y, lo = trctlslist_offset, tblcnt = tblcnt}
              lupd.update_sidebar = true
            else
              trctlslist_offset = 0
            end

          elseif mouse.my < obj.sections[524].y + sby then

          elseif mouse.my > obj.sections[524].y + sby+sbh then

          end

        elseif MOUSE_click(obj.sections[522]) then
          local pcnt = 0
          if trctltype_select == 0 then
            pcnt = #trctls_table
          elseif trctltype_select == 1 then
            pcnt = (#trsends_table+1)*3
          elseif trctltype_select == 2 then
            pcnt = #lvar.special_table
          elseif trctltype_select == 3 then
            pcnt = #lvar.otherctl_table
          end
          local i = math.floor((mouse.my - obj.sections[522].y) / tb_butt_h)-1
          if i == -1 then
            if mouse.mx < obj.sections[522].w/2 then
              trctlslist_offset = trctlslist_offset - P_butt_cnt
              if trctlslist_offset < 0 then
                trctlslist_offset = 0
              end
            else
              if trctlslist_offset + P_butt_cnt < pcnt-1 then
                trctlslist_offset = trctlslist_offset + P_butt_cnt-1
                if trctlslist_offset > pcnt-1 then
                  trctlslist_offset = pcnt-1
                end
              end
            end
            lupd.update_gfx = true
          elseif i >= 0 and i < pcnt then
            if trctltype_select == 0 then
              trctl_select = i + trctlslist_offset+1
              ctl_select = nil
              showctlbrowser(false)

              lupd.update_gfx = true
              if ctl_files[knob_select].imageidx ~= nil then
                local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
                local h = ctl_files[knob_select].cellh
                if w == 0 or h == 0 then
                  ksel_size = {w = 50, h = 50}
                else
                  ksel_size = {w = w/2, h = h/2}
                end
              else
                ksel_size = LoadTmpControl(knob_select)
              end
              mouse.context = contexts.dragparam_tr
            elseif trctltype_select == 1 then
              trctl_select = i + trctlslist_offset+1
              ctl_select = nil
              showctlbrowser(false)

              lupd.update_gfx = true

              if ctl_files[knob_select].imageidx ~= nil then
                local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
                local h = ctl_files[knob_select].cellh
                if w == 0 or h == 0 then
                  ksel_size = {w = 50, h = 50}
                else
                  ksel_size = {w = w/2, h = h/2}
                end
              else
                ksel_size = LoadTmpControl(knob_select)
              end
              mouse.context = contexts.dragparam_snd
            elseif trctltype_select == 2 then
              trctl_select = i + trctlslist_offset+1
              ctl_select = nil
              showctlbrowser(false)

              lupd.update_gfx = true

              if ctl_files[knob_select].imageidx ~= nil then
                local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
                local h = ctl_files[knob_select].cellh
                if w == 0 or h == 0 then
                  ksel_size = {w = 50, h = 50}
                else
                  ksel_size = {w = w/2, h = h/2}
                end
              else
                ksel_size = LoadTmpControl(knob_select)
              end
              mouse.context = contexts.dragparam_spec

            elseif trctltype_select == 3 then
              trctl_select = i + trctlslist_offset+1
              ctl_select = nil
              showctlbrowser(false)

              lupd.update_gfx = true

              if ctl_files[knob_select].imageidx ~= nil then
                local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
                local h = ctl_files[knob_select].cellh
                if w == 0 or h == 0 then
                  ksel_size = {w = 50, h = 50}
                else
                  ksel_size = {w = w/2, h = h/2}
                end
              else
                ksel_size = LoadTmpControl(knob_select)
              end
              mouse.context = contexts.dragparam_other
            end
          end

        elseif MOUSE_click_RB(obj.sections[522]) then
          local pcnt = 0
          if trctltype_select == 0 then
            pcnt = #trctls_table
          elseif trctltype_select == 1 then
            pcnt = (#trsends_table+1)*3
          elseif trctltype_select == 2 then
            pcnt = #lvar.special_table
          elseif trctltype_select == 3 then
            pcnt = #lvar.otherctl_table
          end
          local i = math.floor((mouse.my - obj.sections[522].y) / tb_butt_h)-1
          if i == -1 then
            if mouse.mx < obj.sections[520].w/2 then
              trctlslist_offset = 0
            else
              trctlslist_offset = math.max(pcnt - (P_butt_cnt),0)
            end
            lupd.update_gfx = true
          else
            --PopulateCtlBrowser_Imgs()
            PopulateCtlBrowser_Cbi()
            GUI_DrawCtlBrowserCtls(obj, gui)
            cbi_select = knob_select

            SetCbiSelect()

            show_ctlbrowser = true
            lupd.update_surface = true
          end
        end

      end

      if mouse.context == contexts.scrollfxparams then

        if fxmode == 0 then
          local my = mouse.my - (obj.sections[524].y)
          local lstcnt = #trackfxparams+1

          local oos = plist_offset
          plist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[524].h) * lstcnt),0,lstcnt-(P_butt_cnt-1))
          if plist_offset ~= oos then
            lupd.update_sidebar = true
          end
        else
          local my = mouse.my - (obj.sections[524].y)
          local lstcnt = scrollsidebar.tblcnt

          local oos = trctlslist_offset
          trctlslist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[524].h) * lstcnt),0,lstcnt-(P_butt_cnt-1))
          if trctlslist_offset ~= oos then
            lupd.update_sidebar = true
          end

        end

      elseif mouse.context == contexts.scrollfx then

        if fxmode == 0 then
          local my = mouse.my - (obj.sections[525].y)
          local lstcnt = #trackfx+1

          local oos = flist_offset
          flist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[525].h) * lstcnt),0,lstcnt-(F_butt_cnt-1))
          if flist_offset ~= oos then
            lupd.update_sidebar = true
          end
        else
          local my = mouse.my - (obj.sections[525].y)
          local lstcnt = #lvar.trctltype_table

          local oos = trctltypelist_offset
          trctltypelist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[525].h) * lstcnt),0,lstcnt-(F_butt_cnt-1))
          if trctltypelist_offset ~= oos then
            lupd.update_sidebar = true
          end

        end

      elseif mouse.context and mouse.context == contexts.reassplugin then
        if rt > reass_plugin.time + 0.75 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'reassplugin'}
          reass_param = nil
          if tracks[track_select] and tracks[track_select].strip ~= -1 then
            local i = GetReassCtl()
            if i and (strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxparam or
                      strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxoffline or
                      strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxgui or
                      strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.rcm_switch) then
              reass_param = i
              if trackfx[trackfx_select].name == strips[tracks[track_select].strip][page].controls[i].fxname then
                dragparam.bc = gui.color.green
              else
                dragparam.bc = '255 153 0'
              end
            end
          end
          lupd.update_surface = true
        end

      elseif mouse.context and mouse.context == contexts.dragparam then
        --[[local dp = nil
        if ksel_size.unload then
          ksel_size.w = 0
          ksel_size.h = 0
          dp = true
        end]]
--DBG('O')
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'track'}
        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.move_paramlrn then

        obj.sections[115].x = F_limit(mouse.mx - moveparamlrn.dx,obj.sections[10].x,gfx1.main_w - obj.sections[115].w)
        obj.sections[115].y = F_limit(mouse.my - moveparamlrn.dy,obj.sections[10].y,gfx1.main_h - obj.sections[115].h)
        obj = PosParamLrnCtls(obj)
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.dragparamlrn then
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'learn'}
        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.dragparam_tr then
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'trctl'}
        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.dragparam_snd then
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'trsnd'}
        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.dragparam_spec then
        dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'pkmeter'}

        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif mouse.context and mouse.context == contexts.dragparam_other then

        if trctl_select == 1 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'action'}
        elseif trctl_select == 2 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'macro'}
        elseif trctl_select == 3 then
          knob_select = def_boxctl
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'eqcontrol'}
        elseif trctl_select == 4 then
          knob_select = def_switchctl
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'switcher'}
        elseif trctl_select == 5 then
          --knob_select = def_boxctl
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'rcmswitch'}
        elseif trctl_select == 6 then
          --knob_select = def_boxctl
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'midimsgctl'}
        elseif trctl_select == 7 then
          --knob_select = def_boxctl
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'takeswitcher'}
        elseif trctl_select == 8 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'rs5k'}
        elseif trctl_select == 9 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'macro_updateparam'}
        elseif trctl_select == 10 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'paramvalue_glob'}
        elseif trctl_select == 11 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'infoctl'}
        elseif trctl_select == 12 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'statectl'}
        elseif trctl_select == 13 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'statectl_str'}
        elseif trctl_select == 14 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'navictl'}
        elseif trctl_select == 15 then
          dragparam = {x = mouse.mx-ksel_size.w, y = mouse.my-ksel_size.h, type = 'sk2ctl'}
        end

        reass_param = nil
        if tracks[track_select] and tracks[track_select].strip ~= -1 then
          reass_param = GetReassCtl()
        end
        lupd.update_surface = true

      elseif dragparam ~= nil then
        --Dropped
        if dragparam.type == 'reassplugin' then
          if reass_param ~= nil then
            local rctl = strips[tracks[track_select].strip][page].controls[reass_param]
            if rctl.ctlcat ~= ctlcats.rcm_switch then
              local guid = strips[tracks[track_select].strip][page].controls[reass_param].fxguid
              local nguid = trackfx[trackfx_select].guid
              local nfxnum = trackfx[trackfx_select].fxnum
              local nfxname = trackfx[trackfx_select].name
              for c = 1, #strips[tracks[track_select].strip][page].controls do
                local ctl = strips[tracks[track_select].strip][page].controls[c]
                if ctl.fxguid == guid then

                  ctl.fxnum = nfxnum
                  ctl.fxguid = nguid
                  ctl.fxname = nfxname
                  ctl.fxfound = true
                  if trackfxparams[ctl.param_info.paramnum] then
                    ctl.param_info.paramname = trackfxparams[ctl.param_info.paramnum].paramname
                  end
                  if tracks[trackedit_select].tracknum ~= tracks[track_select].tracknum then
                    ctl.tracknum=tracks[trackedit_select].tracknum
                    ctl.trackguid=tracks[trackedit_select].guid
                  else
                    ctl.tracknum=nil
                    ctl.trackguid=nil
                  end

                end
              end
            else
              --local guid = strips[tracks[track_select].strip][page].controls[reass_param].fxguid
              local nguid = trackfx[trackfx_select].guid
              local nfxnum = trackfx[trackfx_select].fxnum
              local nfxname = trackfx[trackfx_select].name
              --for c = 1, #strips[tracks[track_select].strip][page].controls do
                --local ctl = strips[tracks[track_select].strip][page].controls[c]
                --if rctl.fxguid == guid then

                  rctl.fxnum = nfxnum
                  rctl.fxguid = nguid
                  rctl.fxname = nfxname
                  rctl.fxfound = true
                  rctl.param_info.paramname = 'RCM' --trackfxparams[ctl.param_info.paramnum].paramname

                  if tracks[trackedit_select].tracknum ~= tracks[track_select].tracknum then
                    rctl.tracknum=tracks[trackedit_select].tracknum
                    rctl.trackguid=tracks[trackedit_select].guid
                  else
                    rctl.tracknum=nil
                    rctl.trackguid=nil
                  end

                --end
              --end

            end
          end
        elseif dragparam.type == 'track' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              local i
              local cnt = 0
              local dpx, dpy = dragparam.x, dragparam.y
              for i = 0, #trackfxparams do
                if tfxp_sel[i] then
                  trackfxparam_select = i
                  Strip_AddParam()
                  cnt = cnt + 1
                  dragparam.x = math.floor(dpx + ((ksel_size.w*2+settings_gridsize) * (cnt % 8)))
                  dragparam.y = math.floor(dpy + (ksel_size.h*2+(2*settings_gridsize)) * math.floor(cnt/8))
                end
              end
              tfxp_sel = nil

            end
          else
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w
               and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then

              local i
              local cnt = 0
              for i = 0, #trackfxparams do
                if tfxp_sel[i] then
                  cnt = cnt + 1
                end
              end
              if cnt <= 1 then
                ReassParam(tracks[track_select].strip, page, reass_param, trackedit_select, trackfx_select, trackfxparam_select)

              else
                OpenMsgBox(1, 'You cannot reassign multiple controls at once.', 1)
              end
              tfxp_sel = nil
            end
          end
        elseif dragparam.type == 'learn' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              if not MOUSE_over(obj.sections[115]) then
                Strip_AddParam()
              end
            end
          else
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              if not MOUSE_over(obj.sections[115]) then

                if last_touch_fx.tracknum ~= tracks[track_select].tracknum then
                  strips[tracks[track_select].strip][page].controls[reass_param].tracknum=last_touch_fx.tracknum
                  strips[tracks[track_select].strip][page].controls[reass_param].trackguid=last_touch_fx.trguid
                else
                  strips[tracks[track_select].strip][page].controls[reass_param].tracknum=nil
                  strips[tracks[track_select].strip][page].controls[reass_param].trackguid=nil
                end
                strips[tracks[track_select].strip][page].controls[reass_param].c_id = GenID()
                strips[tracks[track_select].strip][page].controls[reass_param].ctlcat = ctlcats.fxparam
                strips[tracks[track_select].strip][page].controls[reass_param].fxname=last_touch_fx.fxname
                strips[tracks[track_select].strip][page].controls[reass_param].fxguid=last_touch_fx.fxguid
                strips[tracks[track_select].strip][page].controls[reass_param].fxnum=last_touch_fx.fxnum
                strips[tracks[track_select].strip][page].controls[reass_param].fxfound = true
                strips[tracks[track_select].strip][page].controls[reass_param].param = last_touch_fx.paramnum
                strips[tracks[track_select].strip][page].controls[reass_param].param_info = {paramname = last_touch_fx.prname,
                                                                                             paramnum = last_touch_fx.paramnum}
                strips[tracks[track_select].strip][page].controls[reass_param].val = GetParamValue(ctlcats.fxparam,
                                                                                                   last_touch_fx.tracknum,
                                                                                                   last_touch_fx.fxnum,
                                                                                                   last_touch_fx.paramnum, reass_param)
                strips[tracks[track_select].strip][page].controls[reass_param].defval = GetParamValue(ctlcats.fxparam,
                                                                                                   last_touch_fx.tracknum,
                                                                                                   last_touch_fx.fxnum,
                                                                                                   last_touch_fx.paramnum, reass_param)

              end
            end
          end

        elseif dragparam.type == 'trctl' or dragparam.type == 'trsnd' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else
            local cnt = 1
            if cnt <= 1 then
              ctl_select = {}
              ctl_select[1] = {ctl = reass_param}
              gfx4_select = nil
              gfx3_select = nil
    
              strips[tracks[track_select].strip][page].controls[reass_param].c_id = GenID()
              Undo_Set() --must be performed after new cid is set so the replaced control can be determined correctly
              
              if tracks[trackedit_select].tracknum ~= tracks[track_select].tracknum then
                strips[tracks[track_select].strip][page].controls[reass_param].tracknum=tracks[trackedit_select].tracknum
                strips[tracks[track_select].strip][page].controls[reass_param].trackguid=tracks[trackedit_select].guid
              else
                strips[tracks[track_select].strip][page].controls[reass_param].tracknum=nil
                strips[tracks[track_select].strip][page].controls[reass_param].trackguid=nil
              end
              strips[tracks[track_select].strip][page].controls[reass_param].fxguid=nil
              strips[tracks[track_select].strip][page].controls[reass_param].fxnum=nil
              strips[tracks[track_select].strip][page].controls[reass_param].fxfound = true
              strips[tracks[track_select].strip][page].controls[reass_param].param = trctl_select

              if dragparam.type == 'trctl' then
                strips[tracks[track_select].strip][page].controls[reass_param].ctlcat = ctlcats.trackparam
                strips[tracks[track_select].strip][page].controls[reass_param].fxname='Track Parameter'
                strips[tracks[track_select].strip][page].controls[reass_param].param_info = {paramname = 'Track '..trctls_table[trctl_select].name,
                                                                                             paramnum = trctl_select}
                strips[tracks[track_select].strip][page].controls[reass_param].val = GetParamValue(ctlcats.trackparam,
                                                                                                    tracks[trackedit_select].tracknum,
                                                                                                    nil,
                                                                                                    trctl_select, nil)
                strips[tracks[track_select].strip][page].controls[reass_param].defval = strips[tracks[track_select].strip][page].controls[reass_param].val

              elseif dragparam.type == 'trsnd' then
                local sidx = math.floor((trctl_select-1) / 3)
                local pidx = (trctl_select-1) % 3 +1
                strips[tracks[track_select].strip][page].controls[reass_param].ctlcat = ctlcats.tracksend
                strips[tracks[track_select].strip][page].controls[reass_param].fxname='Track Send'
                strips[tracks[track_select].strip][page].controls[reass_param].param_info = {paramname = trsends_table[sidx][pidx].name,
                                                                                             paramnum = trctl_select,
                                                                                             paramidx = trsends_table[sidx].idx,
                                                                                             paramstr = trsends_table[sidx][pidx].parmname,
                                                                                             paramdesttrnum = trsends_table[sidx].desttracknum,
                                                                                             paramdestguid = trsends_table[sidx].desttrackguid,
                                                                                             paramdestchan = trsends_table[sidx].dstchan,
                                                                                             paramsrcchan = trsends_table[sidx].srcchan}
                strips[tracks[track_select].strip][page].controls[reass_param].val = GetParamValue(ctlcats.tracksend,
                                                                                                    tracks[trackedit_select].tracknum,
                                                                                                    nil,
                                                                                                    trctl_select, reass_param)
                strips[tracks[track_select].strip][page].controls[reass_param].defval = strips[tracks[track_select].strip][page].controls[reass_param].val
              end
            else
              OpenMsgBox(1, 'You cannot reassign multiple controls at once.', 1)
            end
          end
        elseif dragparam.type == 'action' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'navictl' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'sk2ctl' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else
        
          end
        elseif dragparam.type == 'pkmeter' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'macro' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'macro_updateparam' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'eqcontrol' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'rs5k' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              local c = Strip_AddParam()

              RS5k_INIT(c)
            end
          else

          end
        elseif dragparam.type == 'switcher' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'rcmswitch' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'midimsgctl' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'takeswitcher' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'paramvalue_glob' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'infoctl' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        elseif dragparam.type == 'statectl' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end

        elseif dragparam.type == 'statectl_str' then
          if reass_param == nil then
            if dragparam.x+ksel_size.w > obj.sections[10].x and dragparam.x+ksel_size.w < obj.sections[10].x+obj.sections[10].w and dragparam.y+ksel_size.h > obj.sections[10].y and dragparam.y+ksel_size.h < obj.sections[10].y+obj.sections[10].h then
              trackfxparam_select = i
              Strip_AddParam()
            end
          else

          end
        end

        --if mouse.mx > obj.sections[10].x then
          tfxp_sel = nil
          if tfxp_last then
            tfxp_sel = {}
            tfxp_sel[tfxp_last] = true
          end
        --end
        reass_param = nil
        dragparam = nil
        lupd.update_gfx = true

      elseif mouse.context and mouse.context == contexts.dragstrip then
        dragstripx = true --to force dropped action even if not
        if mouse.mx ~= mouse.last_x or mouse.my ~= mouse.last_y then

          if settings_stripautosnap == true or stripgallery_view == 1 then
            local x,y = AutoSnap_GetEndInsertPos(loadstrip.strip_w,loadstrip.strip_h)
            dragstrip = {x = x+obj.sections[10].x-surface_offset.x, y = y+obj.sections[10].y-surface_offset.y, xx = x, yy = y}
            lupd.update_surface = true
          else
            newgrp = nil
            local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
            if c then
              local i = c
              local ctl = strips[tracks[track_select].strip][page].controls[i]
              if ctl.ctlcat == ctlcats.switcher and show_striplayout == false then
                local x = mouse.mx -obj.sections[10].x +surface_offset.x
                local y = mouse.my -obj.sections[10].y +surface_offset.y
                vert = true
                if x > ctl.x+ctl.w/2 then
                  vert = false
                end
                newgrp = {grpid = switchers[ctl.switcherid].current,
                          switchid = i,
                          vert = vert}

                local rl, rt, rr, rb = GetLTRBControlInGrp(newgrp.grpid, newgrp.switchid)
                local zx, zy = rl, rb
                if newgrp.vert == false then
                  zx, zy = rr, rt
                end
                dragstrip = {x = zx+obj.sections[10].x-surface_offset.x, y = zy+obj.sections[10].y-surface_offset.y,xx = zx,yy = zy}
              else
                dragstrip = {x = mouse.mx, y = mouse.my, xx=mouse.mx,yy=mouse.my}
              end
            else
              dragstrip = {x = mouse.mx, y = mouse.my, xx=mouse.mx,yy=mouse.my}
            end
            lupd.update_surface = true

          end
        end

      elseif dragstripx ~= nil then
        --Dropped
        --image_count = image_count_add
        if dragstrip and newgrp == nil then
          local ignore = nil
          if settings_stripautosnap == true then
            ignore = true
          end
          if show_striplayout == true then
            if settings_stripautosnap == true or stripgallery_view == 1 then
              if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].h then
                Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y,ignore)
                SetASLocs()
              end
            else
              if mouse.mx >= obj.sections[10].x+striplayout_data.x and mouse.mx <= obj.sections[10].x+striplayout_data.x+striplayout_data.w and
                 mouse.my >= obj.sections[10].y+striplayout_data.y and mouse.my <= obj.sections[10].y+striplayout_data.y+striplayout_data.h then

                local x = mouse.mx- (obj.sections[10].x+striplayout_data.x)
                local y = mouse.my- (obj.sections[10].y+striplayout_data.y)
                x = (x/striplayout_data.w)*surface_size.w
                y = (y/striplayout_data.h)*surface_size.h
                Strip_AddStrip(loadstrip, x-surface_offset.x, y-surface_offset.y, false)
                SetASLocs()

              end
            end
          else
            if dragstrip.x >= obj.sections[10].x and dragstrip.x < obj.sections[10].w and dragstrip.y >= obj.sections[10].y and dragstrip.y < obj.sections[10].h then
              if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].h then
                Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y,ignore)
              end
            end
          end
        elseif dragstrip and newgrp then
          if dragstrip.x > obj.sections[10].x and dragstrip.x < obj.sections[10].w and dragstrip.y > obj.sections[10].y and dragstrip.y < obj.sections[10].h then
            local stripid, _, grpid = Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y, true)

            local ctls = strips[tracks[track_select].strip][page].controls
            local gfxx = strips[tracks[track_select].strip][page].graphics
            local switchid = ctls[newgrp.switchid].switcherid
            local ctl_sw = ctls[newgrp.switchid]

            local x,y = ctl_sw.x - surface_offset.x, ctl_sw.y - surface_offset.y
            y = y + ctl_sw.ctl_info.cellh

            local sw_cur = #switchers[switchid].grpids+1
            switchers[switchid].grpids[sw_cur] = {}
            switchers[switchid].grpids[sw_cur].id = grpid
            switchers[switchid].grpids[sw_cur].name = string.match(strip_files[strip_select].fn,'(.-).strip')

            if ctl_sw then
              ctl_sw.param_info.paramname = string.format('%i',sw_cur)..': '..switchers[switchid].grpids[sw_cur].name
            end
            switchers[switchid].current = grpid

            for c = 1, #ctls do
              if ctls[c].grpid == grpid then
                ctls[c].switcher = switchid

                if ctls[c].ctlcat == ctlcats.switcher then
                  --add parent info
                  local sid = ctls[c].switcherid
                  switchers[sid].parent = {switcherid = switchid,
                                           grpid = grpid}
                end
              end
            end
            for c = 1, #gfxx do
              if gfxx[c].grpid == grpid then
                gfxx[c].switcher = switchid
              end
            end

            lupd.update_bg = true
          end
        end
        loadstrip = nil
        dragstrip = nil
        dragstripx = nil
        ctl_select = nil
        lupd.update_gfx = true

        SetCtlBitmapRedraw()
        reaper.MarkProjectDirty(0)

      elseif mouse.context and mouse.context == contexts.dragsep_fx then

        local dy = mouse.my - dragsep_fx.y
        fx_h = math.min(math.max(dragsep_fx.oh + dy, tb_butt_h*2),gfx1.main_h-obj.sections[520].y-2-8)
        def_fx_h = fx_h
        obj = GetObjects()
        lupd.update_sidebar = true

      end

      if ctl_select ~= nil then
        show_ctloptions = true
      else
        show_ctloptions = false
        ctl_page = 0
      end

    end -- show_actionchooser

    return noscroll

  end

  function LoadTmpControl(knob_select)
    local iidx = ctl_files[knob_select].imageidx
    if iidx == nil and ksel_loaded == false then
      ksel_loaded = true
      gfx.loadimg(1023, paths.controls_path..ctl_files[knob_select].fn)
      iidx = 1023
    elseif iidx == nil then
      iidx = 1023
    end
    w, _ = gfx.getimgdim(iidx)
    h = ctl_files[knob_select].cellh
    return {w = (w*lvar.zoom)/2, h = (h*lvar.zoom)/2}
  end

  function RS5k_RescanFolder(strip, page, c, recurse, subfol)

    local ctl = strips[strip][page].controls[c]
    local fol
    if not subfol then
      fol = ctl.rsdata.samplefolder
      recurse = ctl.rsdata.recurse
    else
      fol = subfol
    end

    if fol then

      local add = 0
      local rem = 0

      local f = 0
      local sfn = reaper.EnumerateFiles(fol, f)
      while sfn do
        if not ctl.rsdata.samplesidx[fol..sfn] then
          local ext = string.match(sfn,'.+%.(.*)')
          if ext and RS5k_ValidSample(ext) then
            local sidx = #ctl.rsdata.samples + 1
            if sidx <= lvar.maxsamples then
              ctl.rsdata.samples[sidx] = {fol = fol,
                                          fn = sfn}
              ctl.rsdata.samplesidx[fol..sfn] = sidx
              ctl.rsdata.samples[sidx].flag = true
              add = add + 1
            end
          end
        else
          local sidx = ctl.rsdata.samplesidx[fol..sfn]
          ctl.rsdata.samples[sidx].flag = true
        end
        f=f+1
        sfn = reaper.EnumerateFiles(fol, f)
      end

      if recurse then
        local f = 0
        local sd = reaper.EnumerateSubdirectories(fol, f)
        while sd do

          RS5k_RescanFolder(strip, page, c, true, fol..sd..'/')
          f=f+1
          sd = reaper.EnumerateSubdirectories(fol, f)
        end
      end

      if not subfol then
        for i = 1, #ctl.rsdata.samples do
          if not ctl.rsdata.samples[i].flag then
            --remove
            if ctl.rsdata.samples[i].fn then
              ctl.rsdata.samplesidx[ctl.rsdata.samples[i].fol..ctl.rsdata.samples[i].fn] = nil
              ctl.rsdata.samples[i].fn = nil
              rem = rem + 1
            end
          end
          ctl.rsdata.samples[i].flag = nil
        end
        DBG('Added: '..add)
        DBG('Removed: '..rem)
      end
    end

  end

  function RS5k_LoadFolder(strip, page, c, recurse, subfol)

    local ctl, retval, fn
    ctl = strips[strip][page].controls[c]

    if not subfol then
      retval, fn = reaper.GetUserFileNameForRead('','Please locate any file in the folder you wish to import','')
    else
      retval = true
    end

    if retval == true then
      local fol
      if not subfol then
        fol = string.match(fn, '(.*[\\/])')
      else
        fol = subfol
      end
      if fol then
        if not subfol then
          ctl.rsdata = {}
          ctl.rsdata.samplefolder = fol
          ctl.rsdata.samples = {}
          ctl.rsdata.samplesidx = {}
          ctl.rsdata.recurse = recurse
        end

        local f = 0
        local sfn = reaper.EnumerateFiles(fol, f)
        while sfn do
          local ext = string.match(sfn,'.+%.(.*)')
          if ext and RS5k_ValidSample(ext) then
            local sidx = #ctl.rsdata.samples + 1
            if sidx <= lvar.maxsamples then
              ctl.rsdata.samples[sidx] = {fol = fol,
                                          fn = sfn}
              ctl.rsdata.samplesidx[fol..sfn] = sidx
            end
          end
          f=f+1
          sfn = reaper.EnumerateFiles(fol, f)
        end

        if recurse then
          local f = 0
          local sd = reaper.EnumerateSubdirectories(fol, f)
          while sd do

            RS5k_LoadFolder(strip, page, c, true, fol..sd..'/')
            f=f+1
            sd = reaper.EnumerateSubdirectories(fol, f)
          end
        end
      end
    end

    --ctl.maxov = (#ctl.rsdata.samples-1) / lvar.maxsamples
  end

  function RS5k_ValidSample(ext)

    if ext and (ext == 'wav' or
                ext == 'aiff' or
                ext == 'mp3' or
                ext == 'flac') then
      return true
    end

  end

  function RS5k_GetSample()

    local retval, fn = reaper.GetUserFileNameForRead('','Please locate sample','')
    if retval == true then
      local fol, fil = string.match(fn, '(.*[\\/])(.*)')

      if fol and fil then
        local ext = string.match(fil,'.+%.(.*)')
        if ext and RS5k_ValidSample(ext) then
          return fol, fil
        end
      end
    end

  end

  function RS5k_INIT(c)

    local track = GetTrack(track_select)
    local chunk = GetTrackChunk(track, true)

    local rs5kfx = {}
    local rs5kfxidx = {}

    for f = 1, reaper.TrackFX_GetCount(track) do
      local ret, fxc = GetFXChunkFromTrackChunk(chunk,f)
      if ret == true then
        local s, e = string.find(fxc,'reasamplomatic.dll')
        if s and e then
          rs5kfx[#rs5kfx+1] = {fxnum = f-1,
                               fxguid = reaper.TrackFX_GetFXGUID(track, f-1),
                              }
          rs5kfxidx[f-1] = #rs5kfx
        end

      end
    end

    local selfxnum = -1
    local selstrip = tracks[track_select].strip
    local selpage = page
    for f = 1, #rs5kfx do

      local ass = false
      for s = 1, #strips do
        if strips[s] then
          for p = 1, lvar.maxpage do
            for cc = 1, #strips[s][p].controls do
              local ctl = strips[s][p].controls[cc]
              if ctl.ctlcat == ctlcats.rs5k then
                if ctl.fxnum == rs5kfx[f].fxnum then
                  ass = true
                  break
                end
              end
            end
            if ass == true then break end
          end
          if ass == true then break end
        end
        if ass == true then break end
      end
      if ass == false then
        selfxnum = f
        break
      end
    end

    local ctl = strips[selstrip][selpage].controls[c]
    if ctl then
      if selfxnum == -1 then
        --Add RS5K control to track
        local cn = reaper.TrackFX_AddByName(track, 'ReaSamplOmatic5000', false, -1)
        ctl.fxnum = cn
        ctl.fxguid = reaper.TrackFX_GetFXGUID(track,cn)
      else
        --Assign selfxnum
        ctl.fxnum = rs5kfx[selfxnum].fxnum
        ctl.fxguid = rs5kfx[selfxnum].fxguid
      end

      --init control data
      ctl.rsdata = {samplefolder = nil,
                    samples = {}}

    end
  end

  function ReassParam(strip, page, reass_param, trackedit_select, trackfx_select, trackfxparam_select)

    ctl_select = {}
    ctl_select[1] = {ctl = reass_param}
    gfx4_select = nil
    gfx3_select = nil
    
    strips[strip][page].controls[reass_param].c_id = GenID()
    Undo_Set() --must be performed after new cid is set so the replaced control can be determined correctly
    
    if tracks[trackedit_select].tracknum ~= tracks[track_select].tracknum then
      strips[strip][page].controls[reass_param].tracknum=tracks[trackedit_select].tracknum
      strips[strip][page].controls[reass_param].trackguid=tracks[trackedit_select].guid
    else
      strips[strip][page].controls[reass_param].tracknum=nil
      strips[strip][page].controls[reass_param].trackguid=nil
    end
    local ccats = ctlcats.fxparam
    local param = trackfxparam_select
    if trackfxparam_select == #trackfxparams-5 then
      ccats = ctlcats.gr_meter
    
    elseif trackfxparam_select == #trackfxparams-4 then
      ccats = ctlcats.fxoffline
      --cts = 2
    elseif trackfxparam_select == #trackfxparams-3 then
      ccats = ctlcats.fxmulti
      --cts = 2
    elseif trackfxparam_select == #trackfxparams-2 then
      ccats = ctlcats.fxgui
      --cts = 2
    elseif trackfxparam_select == #trackfxparams-1 then
      --dummy param
      param = -1
    elseif trackfxparam_select == #trackfxparams then
      --fx name
      ccats = ctlcats.fxname
      param = -2
    end


    --[[if trackfxparam_select == #trackfxparams-2 then
      ccats = ctlcats.fxoffline
    elseif trackfxparam_select == #trackfxparams-1 then
      ccats = ctlcats.fxgui
    end]]
    strips[strip][page].controls[reass_param].ctlcat = ccats
    strips[strip][page].controls[reass_param].fxname=trackfx[trackfx_select].name
    strips[strip][page].controls[reass_param].fxguid=trackfx[trackfx_select].guid
    strips[strip][page].controls[reass_param].fxnum=trackfx[trackfx_select].fxnum
    strips[strip][page].controls[reass_param].fxfound = true
    strips[strip][page].controls[reass_param].param = param
    strips[strip][page].controls[reass_param].param_info = trackfxparams[trackfxparam_select]
    strips[strip][page].controls[reass_param].val = GetParamValue(ctlcats.fxparam,
                                                                   tracks[trackedit_select].tracknum,
                                                                   trackfx[trackfx_select].fxnum,
                                                                   param, reass_param) or 0
    --[[strips[strip][page].controls[reass_param].defval = GetParamValue(ctlcats.fxparam,
                                                                     tracks[trackedit_select].tracknum,
                                                                     trackfx[trackfx_select].fxnum,
                                                                     trackfxparam_select, reass_param)]]
  end

  function A_Run_Submode1(noscroll, rt, char)

    local contexts = contexts
    local mouse = mouse
    local lvar = lvar
    local lupd = lupd

    local grids = settings_gridsize
    if mouse.shift then
      grids = 1
    end

    if wheelcontext then
      WheelContext()
    end
    
    if gfx.mouse_wheel ~= 0 then
      local v = mousewheel_val()
      if MOUSE_over(obj.sections[531]) then
        gflist_offset = F_limit(gflist_offset - v, 0, #graphics_folders)
        lupd.update_sidebar = true
        gfx.mouse_wheel = 0
      elseif MOUSE_over(obj.sections[530]) then
        glist_offset = F_limit(glist_offset - v, 0, #graphics_folder_files)
        lupd.update_sidebar = true
        gfx.mouse_wheel = 0
      end

      if show_lbloptions and gfx4_select and MOUSE_over(obj.sections[49]) then
        if MOUSE_over(obj.sections[141]) then
          
          if not wheelcontext then
            Undo_Set({'font','x','y','stretchw','stretchh'})
            dragoff = {mx = 0, my = 0, x = {}, y = {}, w = {}, h = {}}
            lvar.dg2 = nil
            
            for g = 1, #gfx4_select do
              local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
              local flagb,flagi,flagu,flagv = 0,0,0,0
              if gfxx.gfxtype == lvar.gfxtype.txt then
                local flagb,flagi,flagu = 0,0,0
                if gfxx.font.bold then flagb = 98 end
                if gfxx.font.italics then flagi = 105 end
                if gfxx.font.underline then flagu = 117 end
                if gfxx.font.vertical then flagv = 122 end
                local flags = flagb + (flagi*256) + (flagu*(256^2)) --+ (flagv*(256^3))
                gfx.setfont(1,gfxx.font.name,
                              gfxx.font.size,flags)
                local w, h = gfx.measurestr(gfxx.text)
                if gfxx.font.vertical then
                  w, h = h, w
                  flags = flags + (flagv*(256^3))
                  gfx.setfont(1,gfxx.font.name,
                                gfxx.font.size,flags)
                end
                
                dragoff.x[g] = gfxx.x
                dragoff.y[g] = gfxx.y
                dragoff.w[g] = w
                dragoff.h[g] = h
              end
            end
            A_HideSelectedCtls(true, nil, nil, gfx4_select)
            wheelcontext = 'gfxtsize'
            draggfx2 = 'gfxFSize'
            GenGFX4DragPreview(gui)
            glob_gfxselrect = CalcGFX4SelRect()
            lupd.update_gfx = true
            
          end
          if wheelcontext then
          
            gfx_font_select.size = F_limit(gfx_font_select.size+v,8,250)
            if gfx_font_select.size ~= dragoff.ofs then
              dragoff.ofs = gfx_font_select.size
              for i = 1, #gfx4_select do
                local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]
                if gfxx.gfxtype == lvar.gfxtype.txt and dragoff then
                  gfxx.font.size = gfx_font_select.size
                  local flagb,flagi,flagu,flagv = 0,0,0,0
                  if gfxx.font.bold then flagb = 98 end
                  if gfxx.font.italics then flagi = 105 end
                  if gfxx.font.underline then flagu = 117 end
                  if gfxx.font.vertical then flagv = 122 end
                  local flags = flagb + (flagi*256) + (flagu*(256^2)) --+ (flagv*(256^3))
                  gfx.setfont(1,gfxx.font.name,
                                gfxx.font.size,flags)
                  local w, h = gfx.measurestr(gfxx.text)
                  if gfxx.font.vertical then
                    w, h = h, w
                    flags = flags + (flagv*(256^3))
                    gfx.setfont(1,gfxx.font.name,
                                  gfxx.font.size,flags)
                  end
                  
                  local cx = math.floor(dragoff.x[i] + dragoff.w[i]/2)
                  local cy = math.floor(dragoff.y[i] + dragoff.h[i]/2)
                  --DBG(gfx_font_select.size..' '..cx..' '..cy..' '..w..' '..h)
                  gfxx.x = cx - math.floor(w/2)
                  gfxx.y = cy - math.floor(h/2)
                  gfxx.stretchw = w
                  gfxx.stretchh = h
                end
              end
              GenGFX4DragPreview(gui)
              glob_gfxselrect = CalcGFX4SelRect()
              lupd.update_surface = true
            end
            
            gfx.mouse_wheel = 0
          end
          
        elseif MOUSE_over(obj.sections[148]) then
          Undo_Set({'font'})
          gfx_font_select.shadow_x = gfx_font_select.shadow_x+v
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_x = gfx_font_select.shadow_x
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[149]) then
          Undo_Set({'font'})
          gfx_font_select.shadow_y = gfx_font_select.shadow_y+v
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_y = gfx_font_select.shadow_y
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[150]) then
          Undo_Set({'font'})
          gfx_font_select.shadow_a = gfx_font_select.shadow_a+v*0.1
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_a = gfx_font_select.shadow_a
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        end
      elseif show_gfxoptions and gfx4_select and MOUSE_over(obj.sections[49]) then
        if MOUSE_over(obj.sections[910]) then
          Undo_Set({'bright'})

          gfxbright_select = F_limit(gfxbright_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bright = gfxbright_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[911]) then
          Undo_Set({'contr'})
          gfxcontr_select = F_limit(gfxcontr_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].contr = gfxcontr_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[913]) then
          Undo_Set({'rmult'})
          gfxr_select = F_limit(gfxr_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].rmult = gfxr_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[914]) then
          Undo_Set({'gmult'})
          gfxg_select = F_limit(gfxg_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].gmult = gfxg_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[915]) then
          Undo_Set({'bmult'})
          gfxb_select = F_limit(gfxb_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bmult = gfxb_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        elseif MOUSE_over(obj.sections[916]) then
          Undo_Set({'alpha'})
          gfxa_select = F_limit(gfxa_select+(v*0.02),0,1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].alpha = gfxa_select
          end
          lupd.update_gfx = true
          gfx.mouse_wheel = 0
        end
      end
    end

    if gfx4_select == nil or ((show_lbloptions or show_gfxoptions) and MC() and not MOUSE_click(obj.sections[49])) then
      clicklblopts = false
    end

    if mouse.context == nil and MOUSE_over(obj.sections[530]) then
      local i = math.floor((mouse.my - obj.sections[530].y) / tb_butt_h)-1
      if i >= 0 and graphics_folders[gfxfol_select] and graphics_folder_files[i+glist_offset] and graphics_files[graphics_folder_files[i+glist_offset]] then
        local gfxfn
        if graphics_folders[gfxfol_select] == 'GENERAL' then
          gfxfn = paths.graphics_path..graphics_files[graphics_folder_files[i+glist_offset]].fn
        else
          gfxfn = paths.graphics_path..graphics_folders[gfxfol_select]..'/'..graphics_files[graphics_folder_files[i+glist_offset]].fn
        end
        if gfxfn ~= lvar.gfxpreview_fn or lvar.gfxpreview_img ~= 984 then
          lvar.gfxpreview_img = 984
          local img = gfx.loadimg(lvar.gfxpreview_img,gfxfn)
          lvar.gfxpreview_fn = gfxfn
          lupd.update_surface = true
        end
      elseif lvar.gfxpreview_img ~= nil then
        lvar.gfxpreview_img = nil
        lupd.update_surface = true
      end
    elseif lvar.gfxpreview_img ~= nil then
      lvar.gfxpreview_img = nil
      lupd.update_surface = true
    end

    --[[if keycontext ~= nil and gfx_keydragtimer and gfx_keydragtimer < reaper.time_precise() then
      ArrowKey_Shift(0,nil,nil,gfx4_select)
      gfx_keydragtimer = nil
    elseif keycontext ~= nil and char == 0 and not gfx_keydragtimer then
      gfx_keydragtimer = reaper.time_precise() + 0.3
    elseif gfx_keydragtimer and char ~= 0 then
      gfx_keydragtimer = nil
    end]]

    if gfx4_select ~= nil and (char ~= 0 or keycontext) then

      if ArrowKey_Shift(char,nil,nil,gfx4_select) then
        glob_gfxselrect = CalcGFX4SelRect()
      end

    elseif mouse.context == nil and (MOUSE_click(obj.sections[3000]) or MOUSE_click_RB(obj.sections[3000])) then

      A_Run_CBox()

    elseif gfx4_select ~= nil and show_lbloptions and (MOUSE_click(obj.sections[49]) or MOUSE_click_RB(obj.sections[49])) then

      -- LBL OPTIONS
      clicklblopts = true

      local xywh = {x = obj.sections[49].x,
                    y = obj.sections[49].y,
                    w = obj.sections[49].w,
                    h = butt_h}
      if mouse.context == nil then

        if MOUSE_click(xywh) then
  
          movegfxopts = {dx = mouse.mx - obj.sections[49].x, dy = mouse.my - obj.sections[49].y}
          mouse.context = contexts.move_gfxopts
  
        elseif MOUSE_click(obj.sections[140]) then
          --EditLabel(7,gfx_text_select)
          if strips and strips[tracks[track_select].strip] then
            OpenEB(7,'Please enter text for label:',gfx_text_select)
          end
  
        elseif MOUSE_click(obj.sections[147]) then
          if fontlist then
            OpenFontList(mouse.mx,mouse.my,9)
            
            --[[local fnt = ChooseFontMenu(mouse.mx,mouse.my)
            if fnt then
              Undo_Set({'font'})
  
              EditFont2(fnt)
              lupd.update_gfx = true
            end]]
          else
            if strips and strips[tracks[track_select].strip] then
              OpenEB(8,'Please enter font name:')
            end
          end
        elseif MOUSE_click_RB(obj.sections[147]) then
  
          UpdateFontList(mouse.mx,mouse.my)
          
        elseif MOUSE_click(obj.sections[142]) then
          local retval, c = reaper.GR_SelectColor(_,ConvertColorString(gfx_textcol_select))
          if retval ~= 0 then
            if lvar.Mac_revcol then c = MacRevC(c) end
            Undo_Set({'text_col'})
            gfx_textcol_select = ConvertColor(c)
            for i = 1, #gfx4_select do
              strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].text_col = gfx_textcol_select
            end
            lupd.update_gfx = true
          end
  
        elseif MOUSE_click(obj.sections[143]) then
          Undo_Set({'font'})
          gfx_font_select.bold = not gfx_font_select.bold
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.bold = gfx_font_select.bold
          end
          lupd.update_gfx = true
  
        elseif MOUSE_click(obj.sections[144]) then
          Undo_Set({'font'})
          gfx_font_select.italics = not gfx_font_select.italics
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.italics = gfx_font_select.italics
          end
          lupd.update_gfx = true
  
        elseif MOUSE_click(obj.sections[145]) then
          Undo_Set({'font'})
          gfx_font_select.underline = not gfx_font_select.underline
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.underline = gfx_font_select.underline
          end
          lupd.update_gfx = true

        elseif MOUSE_click(obj.sections[151]) then
          Undo_Set({'font'})
          gfx_font_select.vertical = not gfx_font_select.vertical
          for i = 1, #gfx4_select do
            local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]
            gfxx.font.vertical = gfx_font_select.vertical
            gfxx.w, gfxx.h = gfxx.h, gfxx.w
            gfxx.stretchw, gfxx.stretchh = gfxx.stretchh, gfxx.stretchw
          end
          glob_gfxselrect = CalcGFX4SelRect()
          --lupd.update_bg = true
          lupd.update_gfx = true
          movefrom_sc = nil
  
        elseif MOUSE_click(obj.sections[146]) then
          Undo_Set({'font'})
          gfx_font_select.shadow = not gfx_font_select.shadow
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow = gfx_font_select.shadow
          end
          lupd.update_gfx = true
        
        elseif MOUSE_click(obj.sections[141]) then 
          Undo_Set({'font','x','y','stretchw','stretchh'}) 
          mouse.context = contexts.textsizeslider
          
          dragoff = {mx = 0, my = 0, x = {}, y = {}, w = {}, h = {}}
          lvar.dg2 = nil
    
          for g = 1, #gfx4_select do
            local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
            local flagb,flagi,flagu = 0,0,0
            if gfxx.gfxtype == lvar.gfxtype.txt then
              local flagb,flagi,flagu,flagv = 0,0,0,0
              if gfxx.font.bold then flagb = 98 end
              if gfxx.font.italics then flagi = 105 end
              if gfxx.font.underline then flagu = 117 end
              if gfxx.font.vertical then flagv = 122 end
              local flags = flagb + (flagi*256) + (flagu*(256^2)) --+ (flagv*(256^3))
              gfx.setfont(1,gfxx.font.name,
                            gfxx.font.size,flags)
              local w, h = gfx.measurestr(gfxx.text)
              if gfxx.font.vertical then
                w, h = h, w
                flags = flags + (flagv*(256^3))
                gfx.setfont(1,gfxx.font.name,
                              gfxx.font.size,flags)
              end
              
              dragoff.x[g] = gfxx.x
              dragoff.y[g] = gfxx.y
              dragoff.w[g] = w
              dragoff.h[g] = h
            end
          end
          A_HideSelectedCtls(true, nil, nil, gfx4_select)
          draggfx2 = 'gfxFSize'
          GenGFX4DragPreview(gui)
          glob_gfxselrect = CalcGFX4SelRect()
  
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]]
          --dragoff.mx = gfxx.x
          --dragoff.my = gfxx.y
          
          lupd.update_gfx = true
          
        elseif MOUSE_click(obj.sections[148]) then 
          Undo_Set({'font'}) 
          mouse.context = contexts.shadxslider
          dragoff = {mx = 0, my = 0}
          lvar.dg2 = nil
          A_HideSelectedCtls(true, nil, nil, gfx4_select)
          draggfx2 = 'gfxFShad'
          GenGFX4DragPreview(gui)
          lupd.update_gfx = true
          
        elseif MOUSE_click(obj.sections[149]) then 
          Undo_Set({'font'}) 
          mouse.context = contexts.shadyslider
          dragoff = {mx = 0, my = 0}
          lvar.dg2 = nil
          A_HideSelectedCtls(true, nil, nil, gfx4_select)
          draggfx2 = 'gfxFShad'
          GenGFX4DragPreview(gui)
          lupd.update_gfx = true
          
        elseif MOUSE_click(obj.sections[150]) then 
          Undo_Set({'font'}) 
          mouse.context = contexts.shadaslider
          dragoff = {mx = 0, my = 0}
          lvar.dg2 = nil
          A_HideSelectedCtls(true, nil, nil, gfx4_select)
          draggfx2 = 'gfxFShad'
          GenGFX4DragPreview(gui)
          lupd.update_gfx = true
        
        end
      end
      
    elseif gfx4_select ~= nil and show_gfxoptions and (MOUSE_click(obj.sections[49]) or MOUSE_click_RB(obj.sections[49])) then

      clicklblopts = true

      local xywh = {x = obj.sections[49].x,
                    y = obj.sections[49].y,
                    w = obj.sections[49].w,
                    h = butt_h}

      if mouse.context == nil then
        if MOUSE_click(xywh) then
  
          movegfxopts = {dx = mouse.mx - obj.sections[49].x, dy = mouse.my - obj.sections[49].y}
          mouse.context = contexts.move_gfxopts
  
        elseif MOUSE_click(obj.sections[912]) then
          Undo_Set({'bright','contr','rmult','gmult','bmult','amult'})
          gfxbright_select = 0.5
          gfxcontr_select = 0.5
          gfxr_select = 0.5
          gfxg_select = 0.5
          gfxb_select = 0.5
          gfxa_select = 1
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bright = gfxbright_select
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].contr = gfxcontr_select
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].rmult = gfxr_select
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].gmult = gfxg_select
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bmult = gfxb_select
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].amult = gfxa_select
          end
          lupd.update_gfx = true
  
        elseif MOUSE_click(obj.sections[917]) then
  
          Undo_Set({'stretchmode'})
  
          gfxstretchmode_select = math.max(((gfxstretchmode_select + 1) % (#lvar.gfxstretch_table+1)),1)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].stretchmode = gfxstretchmode_select
          end
          lupd.update_gfx = true
  
        end
  
        if MOUSE_click(obj.sections[910]) then Undo_Set({'bright'}) mouse.context = contexts.gfxopt_bright
        elseif MOUSE_click(obj.sections[911]) then Undo_Set({'contr'}) mouse.context = contexts.gfxopt_contr
        elseif MOUSE_click(obj.sections[913]) then Undo_Set({'rmult'}) mouse.context = contexts.gfxopt_r
        elseif MOUSE_click(obj.sections[914]) then Undo_Set({'gmult'}) mouse.context = contexts.gfxopt_g
        elseif MOUSE_click(obj.sections[915]) then Undo_Set({'bmult'}) mouse.context = contexts.gfxopt_b
        elseif MOUSE_click(obj.sections[916]) then Undo_Set({'alpha'}) mouse.context = contexts.gfxopt_a
        elseif MOUSE_click(obj.sections[918]) then
          Undo_Set({'edgesz'})
          mouse.context = contexts.gfxopt_edge
          gfxedgesz_select = F_limit(gfxedgesz_select + 1,0,127)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].edgesz = gfxedgesz_select
          end
  
          draggfxedge = {pos = gfxedgesz_select, yoff = mouse.my-obj.sections[918].y}
          lupd.update_bg = true
          lupd.update_gfx = true
        elseif MOUSE_click(obj.sections[919]) then
          gfx_shadow_select = not (gfx_shadow_select or false)
          for i = 1, #gfx4_select do
            strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].shadow = gfx_shadow_select
          end
          lupd.update_bg = true
          lupd.update_gfx = true
  
        end
      end
    end
    
    if mouse.context and mouse.context == contexts.move_gfxopts then

      obj.sections[49].x = F_limit(mouse.mx-movegfxopts.dx,obj.sections[10000].x,gfx1.main_w-obj.sections[49].w)
      obj.sections[49].y = F_limit(mouse.my-movegfxopts.dy,obj.sections[10000].y,obj.sections[10000].y+obj.sections[10000].h-obj.sections[49].h-1)
      obj = PosGfxOptCtls(obj)
      lupd.update_surface = true

    elseif mouse.context and mouse.context == contexts.textsizeslider then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[141]),0,1)
      if val ~= nil then
        gfx_font_select.size = F_limit(round(val*250),8,250)
        if gfx_font_select.size ~= dragoff.ofs then
          dragoff.ofs = gfx_font_select.size
          for i = 1, #gfx4_select do
            local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]
            if gfxx.gfxtype == lvar.gfxtype.txt and dragoff then
              gfxx.font.size = gfx_font_select.size
              local flagb,flagi,flagu = 0,0,0
              if gfxx.font.bold then flagb = 98 end
              if gfxx.font.italics then flagi = 105 end
              if gfxx.font.underline then flagu = 117 end
              if gfxx.font.vertical then flagv = 122 end
              local flags = flagb + (flagi*256) + (flagu*(256^2)) --+ (flagv*(256^3))
              gfx.setfont(1,gfxx.font.name,
                            gfxx.font.size,flags)
              local w, h = gfx.measurestr(gfxx.text)
              if gfxx.font.vertical then
                w, h = h, w
                flags = flags + (flagv*(256^3))
                gfx.setfont(1,gfxx.font.name,
                              gfxx.font.size,flags)
              end
              
              local cx = math.floor(dragoff.x[i] + dragoff.w[i]/2)
              local cy = math.floor(dragoff.y[i] + dragoff.h[i]/2)
              --DBG(gfx_font_select.size..' '..cx..' '..cy..' '..w..' '..h)
              gfxx.x = cx - math.floor(w/2)
              gfxx.y = cy - math.floor(h/2)
              gfxx.stretchw = w
              gfxx.stretchh = h
            end
          end
          GenGFX4DragPreview(gui)
          glob_gfxselrect = CalcGFX4SelRect()
          lupd.update_surface = true
        end
      end
      
    elseif mouse.context and mouse.context == contexts.shadxslider then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[148]),0,1)
      if val ~= nil then
        gfx_font_select.shadow_x = math.floor((val*30)-15)
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_x = gfx_font_select.shadow_x
        end
        lupd.update_surface = true
        GenGFX4DragPreview(gui)
        glob_gfxselrect = CalcGFX4SelRect()
      end
    elseif mouse.context and mouse.context == contexts.shadyslider then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[149]),0,1)
      if val ~= nil then
        gfx_font_select.shadow_y = math.floor((val*30)-15)
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_y = gfx_font_select.shadow_y
        end
        lupd.update_surface = true
        GenGFX4DragPreview(gui)
        glob_gfxselrect = CalcGFX4SelRect()
      end
    elseif mouse.context and mouse.context == contexts.shadaslider then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[150]),0,1)
      if val ~= nil then
        gfx_font_select.shadow_a = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].font.shadow_a = gfx_font_select.shadow_a
        end
        lupd.update_surface = true
        GenGFX4DragPreview(gui)
        glob_gfxselrect = CalcGFX4SelRect()
      end

    elseif mouse.context and mouse.context == contexts.gfxopt_bright then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[910]),0,1)
      if val ~= nil then
        gfxbright_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bright = gfxbright_select
        end
        lupd.update_gfx = true
      end
    elseif mouse.context and mouse.context == contexts.gfxopt_contr then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[911]),0,1)
      if val ~= nil then
        gfxcontr_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].contr = gfxcontr_select
        end
        lupd.update_gfx = true
      end

    elseif mouse.context and mouse.context == contexts.gfxopt_r then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[913]),0,1)
      if val ~= nil then
        gfxr_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].rmult = gfxr_select
        end
        lupd.update_gfx = true
      end
    elseif mouse.context and mouse.context == contexts.gfxopt_g then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[914]),0,1)
      if val ~= nil then
        gfxg_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].gmult = gfxg_select
        end
        lupd.update_gfx = true
      end
    elseif mouse.context and mouse.context == contexts.gfxopt_b then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[915]),0,1)
      if val ~= nil then
        gfxb_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].bmult = gfxb_select
        end
        lupd.update_gfx = true
      end
    elseif mouse.context and mouse.context == contexts.gfxopt_a then
      local val = F_limit(MOUSE_sliderHBar(obj.sections[916]),0,1)
      if val ~= nil then
        gfxa_select = val
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].alpha = gfxa_select
        end
        lupd.update_gfx = true
      end

    elseif mouse.context and mouse.context == contexts.gfxopt_edge then
      local v = MOUSE_sliderX(obj.sections[918], -draggfxedge.yoff)
      if v then
        v=v-0.5
        gfxedgesz_select = F_limit(math.floor(draggfxedge.pos - v*96),0,127)
        for i = 1, #gfx4_select do
          strips[tracks[track_select].strip][page].graphics[gfx4_select[i]].edgesz = gfxedgesz_select
        end
        lupd.update_bg = true
        lupd.update_gfx = true
      end
    end

    if MOUSE_click(obj.sections[535]) then

      local msbh = obj.sections[535].h
      local p1 = 1 / (#graphics_folders+1)
      local sbh = math.ceil(F_limit(p1*(GF_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(gflist_offset * p2)

      sby = math.min(sby,msbh-sbh-1)

      if mouse.my >= obj.sections[535].y + sby and mouse.my <= obj.sections[535].y + sby+sbh then

        if GF_butt_cnt-1 < #graphics_folders+1 then
          mouse.context = contexts.scrollgfxfols
          scrollsidebar = {y = mouse.my-obj.sections[535].y, lo = gflist_offset}
          lupd.update_sidebar = true
        else
          gflist_offset = 0
        end

      elseif mouse.my < obj.sections[535].y + sby then

      elseif mouse.my > obj.sections[535].y + sby+sbh then

      end

    elseif MOUSE_click(obj.sections[531]) then
      local i = math.floor((mouse.my - obj.sections[531].y) / tb_butt_h)-1
      if i == -1 then
        if mouse.mx < obj.sections[531].w/2 then
          gflist_offset = gflist_offset - GF_butt_cnt
          if gflist_offset < 0 then
            gflist_offset = 0
          end
        else
          if gflist_offset + GF_butt_cnt < #graphics_folders then
            gflist_offset = gflist_offset + GF_butt_cnt-1
          end
        end
        lupd.update_gfx = true

      elseif graphics_folders[i + gflist_offset] then
        gfxfol_select = i + gflist_offset
        --PopulateTrackFXParams()
        PopGfxFolder(gfxfol_select)
        lupd.update_gfx = true
      end

    elseif MOUSE_click_RB(obj.sections[531]) then

      local mstr = 'New folder'
      gfx.x = mouse.mx
      gfx.y = mouse.my
      local res = gfx.showmenu(mstr)
      if res > 0 then
        if res == 1 then
          OpenEB(122, 'Please enter folder name:')
        end
      end

    elseif MOUSE_click(obj.sections[534]) then

      local msbh = obj.sections[534].h
      local p1 = 1 / (#graphics_folder_files+1)
      local sbh = math.ceil(F_limit(p1*(G_butt_cnt+1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(glist_offset * p2)

      sby = math.min(sby,msbh-sbh-1)

      if mouse.my >= obj.sections[534].y + sby and mouse.my <= obj.sections[534].y + sby+sbh then

        if G_butt_cnt+1 < #graphics_folder_files+1 then
          mouse.context = contexts.scrollgfxfiles
          scrollsidebar = {y = mouse.my-obj.sections[534].y, lo = glist_offset}
          lupd.update_sidebar = true
        else
          glist_offset = 0
        end

      elseif mouse.my < obj.sections[534].y + sby then

      elseif mouse.my > obj.sections[534].y + sby+sbh then

      end

    elseif MOUSE_click(obj.sections[530]) then
      local i = math.floor((mouse.my - obj.sections[530].y) / tb_butt_h)-1

      if i == -1 then
        if mouse.mx < obj.sections[530].w/2 then
          glist_offset = glist_offset - math.max(G_butt_cnt-1,1)
          if glist_offset < 0 then
            glist_offset = 0
          end
        else
          if glist_offset + G_butt_cnt < #graphics_folder_files then
            glist_offset = glist_offset + math.max(G_butt_cnt-1,1)
          end
        end
        lupd.update_gfx = true
      elseif graphics_files[graphics_folder_files[i + glist_offset]] then
        gfx_select = i + glist_offset

        --load temp image
        local gfol = ''
        local fol = graphics_files[graphics_folder_files[gfx_select]].fol
        if fol and fol ~= 'GENERAL' then
          gfol = fol..'/'
        end
        gfx.loadimg(1023,paths.graphics_path..gfol..graphics_files[graphics_folder_files[gfx_select]].fn)
        draggfx_w, draggfx_h = gfx.getimgdim(1023)

        lupd.update_gfx = true
        mouse.context = contexts.draggfx
      end

    elseif MOUSE_click(obj.sections[533]) then

      mouse.context = contexts.dragsep_gfx
      dragsep_gfx = {y = mouse.my, oh = gx_h}

    elseif mouse.context == nil and (MOUSE_click_RB(obj.sections[10])) then

      mouse.context = contexts.draglasso
      local cs, gs
      
      if mouse.ctrl then
        gs = table.copy(gfx4_select)
      end
      lasso = {l = mouse.mx, t = mouse.my, r = mouse.mx+5, b = mouse.my+5, gfx4_select = gs}
    end

    if mouse.context == contexts.scrollgfxfiles then

      local my = mouse.my - (obj.sections[534].y)
      local lstcnt = #graphics_folder_files+1

      local oos = glist_offset
      glist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[534].h) * lstcnt),0,lstcnt-(G_butt_cnt+1))
      if glist_offset ~= oos then
        lupd.update_sidebar = true
      end

    elseif mouse.context == contexts.scrollgfxfols then

      local my = mouse.my - (obj.sections[535].y)
      local lstcnt = #graphics_folders+1

      local oos = gflist_offset
      gflist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[535].h) * lstcnt),0,lstcnt-(GF_butt_cnt-1))
      if gflist_offset ~= oos then
        lupd.update_sidebar = true
      end

    elseif mouse.context and mouse.context == contexts.draggfx then

      draggfx = {x = mouse.mx - draggfx_w/2, y = mouse.my - draggfx_h/2}
      if MOUSE_over(obj.sections[531]) then
        local i = math.floor((mouse.my - obj.sections[531].y) / tb_butt_h)-1
        ogdf = gfx_dropfolder
        if graphics_folders[i + gflist_offset] then
          local dropfolder = i + gflist_offset
          if dropfolder ~= gfx_dropfolder then
            gfx_dropfolder = dropfolder
          end
        else
          gfx_dropfolder = nil
        end
      else
        gfx_dropfolder = nil
      end
      if ogdf ~= gfx_dropfolder then
        lupd.update_sidebar = true
      end
      lupd.update_surface = true

    elseif draggfx ~= nil then
      --Dropped
      if mouse.mx > obj.sections[10].x and mouse.mx < obj.sections[10].x+obj.sections[10].w and mouse.my > obj.sections[10].y and mouse.my < obj.sections[10].y+obj.sections[10].h then
        Strip_AddGFX(lvar.gfxtype.img)
      elseif MOUSE_over(obj.sections[531]) then

        local i = math.floor((mouse.my - obj.sections[531].y) / tb_butt_h)-1
        if graphics_folders[i + gflist_offset] then
          local dropfolder = i + gflist_offset

          MoveGFXFileToFolder(gfx_select, dropfolder)
        end

      end

      gfx_dropfolder = nil
      draggfx = nil
      lupd.update_gfx = true
    end

    --DBG('b'..tostring(clicklblopts))
    if --[[mouse.mx > obj.sections[10].x]] MOUSE_over(obj.sections[10]) and clicklblopts ~= true then

      if strips and tracks[track_select] and strips[tracks[track_select].strip] then

        if gfx4_select ~= nil and show_lbloptions == false and show_gfxoptions == true then

          local clickrsz = false
          local selrect = table.copy(glob_gfxselrect) --CalcGFX4SelRect()
          local sx = (selrect.x*lvar.zoom - surface_offset.x*lvar.zoom) + obj.sections[10].x
          local sy = selrect.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y
          local sw = selrect.w*lvar.zoom
          local sh = selrect.h*lvar.zoom
          local xywh = {x = sx+sw-5,
                        y = sy+sh/2-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              Undo_Set({'stretchw'})
              mouse.context = contexts.stretch_x
              gfx2_stretch = {mx = mouse.mx, sw = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx-5,
                        y = sy+sh/2-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              Undo_Set({'x','stretchw'})
              mouse.context = contexts.stretch_x2
              gfx2_stretch = {mx = mouse.mx, sw = {}, r = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.r[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end
          
          local xywh = {x = sx+sw/2-5,
                        y = sy-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              Undo_Set({'y','stretchh'})
              mouse.context = contexts.stretch_y2
              gfx2_stretch = {my = mouse.my, sh = {}, b = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.b[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx+sw/2-5,
                        y = sy+sh-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              Undo_Set({'stretchh'})
              mouse.context = contexts.stretch_y
              gfx2_stretch = {my = mouse.my, sh = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx+sw-5,
                        y = sy+sh-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              mouse.context = contexts.stretch_xy
              Undo_Set({'stretchw','stretchh'})
              gfx2_stretch = {mx = mouse.mx, my = mouse.my, sw = {}, sh = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx-5,
                        y = sy-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              mouse.context = contexts.stretch_xy2
              Undo_Set({'x','y','stretchw','stretchh'})
              gfx2_stretch = {mx = mouse.mx, my = mouse.my, sw = {}, sh = {}, r = {}, b = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.r[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.b[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx+sw-5,
                        y = sy-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              mouse.context = contexts.stretch_xy3
              Undo_Set({'x','y','stretchw','stretchh'})
              gfx2_stretch = {mx = mouse.mx, my = mouse.my, sw = {}, sh = {}, r = {}, b = {}}
              
              for g = 1, #gfx4_select do
                --gfx2_stretch.r[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.b[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          local xywh = {x = sx-5,
                        y = sy+sh-5,
                        w = 10,
                        h = 10}
          if mouse.context == nil and MOUSE_click(xywh) then
            if poslock_select == false then
              mouse.context = contexts.stretch_xy4
              Undo_Set({'x','y','stretchw','stretchh'})
              gfx2_stretch = {mx = mouse.mx, my = mouse.my, sw = {}, sh = {}, r = {}, b = {}}
              
              for g = 1, #gfx4_select do
                gfx2_stretch.r[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                --gfx2_stretch.b[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y + strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
                gfx2_stretch.sw[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw
                gfx2_stretch.sh[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh
              end
              A_HideSelectedCtls(true, nil, nil, gfx4_select)
              draggfx2 = 'stretchgfx'
              GenGFX4DragPreview(gui)
              
              lupd.update_gfx = true
            end
          end

          if mouse.context then
            if mouse.context == contexts.stretch_x then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] + ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
  
            elseif mouse.context == contexts.stretch_x2 then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] - ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x = math.floor(gfx2_stretch.r[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
              
            elseif mouse.context == contexts.stretch_y then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] + ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
  
            elseif mouse.context == contexts.stretch_y2 then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] - ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y = math.floor(gfx2_stretch.b[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
  
            elseif mouse.context == contexts.stretch_xy then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] + ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] + ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
  
            elseif mouse.context == contexts.stretch_xy2 then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] - ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] - ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x = math.floor(gfx2_stretch.r[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y = math.floor(gfx2_stretch.b[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()
  
            elseif mouse.context == contexts.stretch_xy3 then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] + ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] - ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
                --strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x = math.floor(gfx2_stretch.r[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y = math.floor(gfx2_stretch.b[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()

            elseif mouse.context == contexts.stretch_xy4 then
  
              for g = 1, #gfx4_select do
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw = math.max(math.floor((gfx2_stretch.sw[g] - ((mouse.mx-gfx2_stretch.mx)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh = math.max(math.floor((gfx2_stretch.sh[g] + ((mouse.my-gfx2_stretch.my)/lvar.zoom))/grids)*grids,2)
                strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].x = math.floor(gfx2_stretch.r[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchw)
                --strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].y = math.floor(gfx2_stretch.b[g] - strips[tracks[track_select].strip][page].graphics[gfx4_select[g]].stretchh)
              end
              GenGFX4DragPreview(gui)
              lupd.update_surface = true
              --lupd.update_gfx = true
              glob_gfxselrect = CalcGFX4SelRect()

            end
          end
        end

        local clickxywh = false
        if mouse.context == nil then

          local dclick
          if MC() then --mouse.LB or mouse.RB --[[and clickedlblopts ~= true]] then
            local clickedon = false
            local loop = 1
            if settings_drawbglabelsontop then
              loop = 2
            end

            lupd.update_cbox = true

            gfx2_select = nil
            local xywh, gfxx
            for lp = 1, loop do
              if clickedon == true then
                break
              end

              for i = #strips[tracks[track_select].strip][page].graphics,1,-1 do
                gfxx = strips[tracks[track_select].strip][page].graphics[i]

                if loop == 1 or (lp == 1 and gfxx.gfxtype == lvar.gfxtype.txt) or (lp == 2 and gfxx.gfxtype == lvar.gfxtype.img) then
                  xywh = {x = gfxx.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                          y = gfxx.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                          w = gfxx.stretchw*lvar.zoom,
                          h = gfxx.stretchh*lvar.zoom,
                          p = gfxx.gfxpage or 0}

                  if xywh.w < 16 then
                    xywh.x = xywh.x - 8
                    xywh.w = 16
                  end
                  if xywh.h < 16 then
                    xywh.y = xywh.y - 8
                    xywh.h = 16
                  end

                  if xywh.p == 0 and MOUSE_click(xywh) and Switcher_CtlsHidden(gfxx.switcher, gfxx.grpid) == false then
                    clickedon = true
                    gfx2_select = i
                    break

                  --elseif lp == 1 and MOUSE_click_RB(xywh) then
                    --GFXMenu()
                    --clickxywh = true
                    --break

                  end

                end

              end

              --if lp == 1 and clickxywh == false and MOUSE_click_RB(obj.sections[10]) then
              --  GFXMenu()
              --end
            end

            if gfx2_select then
              local i = gfx2_select
              local dflag

              if i ~= lvar.gfxpreview_sel then
                lvar.gfxpreview_sel = i
                lupd.update_surface = true
              end

              if not gfx4_select then
                gfx4_select = {}
                gfx4_selectidx = {}
              end
              if mouse.ctrl then
                if gfx4_selectidx[i] then
                  gfx4_select = Table_RemoveEntry(gfx4_select, #gfx4_select, gfx4_selectidx[i])
                  gfx4_selectidx = {}
                  if #gfx4_select > 0 then
                    for g = 1, #gfx4_select do
                      gfx4_selectidx[gfx4_select[g]] = g
                    end
                  else
                    gfx4_select = nil
                    gfx4_selectidx = nil
                  end
                  dflag = true
                else
                  local gidx = #gfx4_select+1
                  gfx4_select[gidx] = i
                  gfx4_selectidx[i] = gidx
                end
              else
                if not gfx4_selectidx[i] then
                  gfx4_select = {}
                  gfx4_selectidx = {}
                  gfx4_select[1] = i
                  gfx4_selectidx[i] = 1
                end
              end

              glob_gfxselrect = CalcGFX4SelRect()

              if dflag then
                mouse.context = contexts.dummy
                poslock_select = false
                show_lbloptions = false
                show_gfxoptions = false
                if gfx4_select then
                  for g = 1, #gfx4_select do
                    local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
                    if gfxx.poslock then
                      poslock_select = true
                    end
                    if gfxx.gfxtype == lvar.gfxtype.txt then
                      show_lbloptions = true
                    else
                      show_gfxoptions = true
                    end
                  end
                end
                if show_lbloptions == true and show_gfxoptions == true then
                  show_lbloptions = false
                  show_gfxoptions = false
                elseif show_lbloptions == true then
                  SetGfx4SelectVals()
                elseif show_gfxoptions == true then
                  SetGfx4SelectVals2()
                end

              elseif gfx4_select then

                --poslock_select = strips[tracks[track_select].strip][page].graphics[gfx2_select].poslock or false
                mouse.context = contexts.draggfx2_timer
                dg2_timer = reaper.time_precise()+0.2

                lvar.dg2 = {mx = mouse.mx, my = mouse.my}
                poslock_select = false
                show_lbloptions = false
                show_gfxoptions = false

                --draggfx2 = 'draggfx'
                --GenGFX4DragPreview(gui)
                --dragoff = {mx = mouse.mx, my = mouse.my, x = {}, y = {}}
                for g = 1, #gfx4_select do
                  local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
                  --[[dragoff.x[g] = gfxx.x
                  dragoff.y[g] = gfxx.y
                  gfxx.hide = true]]

                  if gfxx.poslock then
                    poslock_select = true
                  end
                  if gfxx.gfxtype == lvar.gfxtype.txt then
                    show_lbloptions = true
                  else
                    show_gfxoptions = true
                  end

                end
                clickxywh = true


                if show_lbloptions == true and show_gfxoptions == true then
                  show_lbloptions = false
                  show_gfxoptions = false
                elseif show_lbloptions == true then
                  SetGfx4SelectVals()
                elseif show_gfxoptions == true then
                  SetGfx4SelectVals2()
                end

              elseif mouse.LB and clicklblopts ~= true then

                clicklblopts = false
                gfx4_select = nil
                gfx4_selectidx = nil
                lupd.update_surface = true

              end
              lupd.update_surface = true

              if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
                dclick = true
              end

            end

            if dclick then
              local i = gfx2_select
              local gfxx = strips[tracks[track_select].strip][page].graphics[i]
              if gfxx and gfxx.gfxtype == lvar.gfxtype.txt then
                OpenEB(7,'Please enter text for label:',gfx_text_select)
              end
            end
          end

        end

      end
    end

    if mouse.context and mouse.context == contexts.draggfx2_timer then

      if reaper.time_precise() > dg2_timer and gfx4_select then
 
        Undo_Set({'x','y'})
        mouse.context = contexts.draggfx2

        draggfx2 = 'draggfx'
        GenGFX4DragPreview(gui)
        --dragoff = {mx = mouse.mx, my = mouse.my, x = {}, y = {}}
        dragoff = {mx = lvar.dg2.mx, my = lvar.dg2.my, x = {}, y = {}, relx = {}, rely = {}}
        lvar.dg2 = nil

        local l, t = lvar.maxdim, lvar.maxdim
        for g = 1, #gfx4_select do
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
          dragoff.x[g] = gfxx.x
          dragoff.y[g] = gfxx.y
          dragoff.relx[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].x - gfxx.x
          dragoff.rely[g] = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]].y - gfxx.y
          l = math.min(l, gfxx.x)
          t = math.min(t, gfxx.y)
          gfxx.hide = true
        end
        dragoff.left = l
        dragoff.top = t
        lupd.update_gfx = true
      end

    elseif mouse.context and mouse.context == contexts.draggfx2 then
    
      local ctls = strips[tracks[track_select].strip][page].controls
      newgrp = nil
      vert = true
      local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
      if c then
        local i = c
        local ctl = strips[tracks[track_select].strip][page].controls[i]
        if ctl.ctlcat == ctlcats.switcher and SwitcherInSelected(ctl.switcherid) == false then
          local swid = ctl.switcherid
          if swid and switchers[swid].switchmode ~= 1 then
            local x = mouse.mx -obj.sections[10].x+surface_offset.x*lvar.zoom
            local y = mouse.my -obj.sections[10].y+surface_offset.y*lvar.zoom

            if x > (ctl.x*lvar.zoom)+(ctl.w*lvar.zoom)/2 then
              vert = false
            end
            newgrp = {grpid = switchers[ctl.switcherid].current,
                      switchid = i,
                      vert = vert}
          end
        end
      end

      if newgrp then

        local rl, rt, rr, rb = GetLTRBControlInGrp(newgrp.grpid, newgrp.switchid)

        if math.floor(mouse.mx) ~= math.floor(mouse.last_x) or math.floor(mouse.my) ~= math.floor(mouse.last_y) then
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[1]]

          local zx, zy = rl, rb
          if newgrp.vert == false then
            zx, zy = rr, rt
          end

          local mrelx, mrely = 0,0
          if gfx4_select then
            for cs = 1, #gfx4_select do
              mrelx = math.max(mrelx, dragoff.relx[cs])
              mrely = math.max(mrely, dragoff.rely[cs])
            end
          end

          local zzx, zzy = zx, zy
          zx = zx + mrelx
          zy = zy + mrely

          local dx, dy
          if gfxx.poslock or false == false then
            gfxx.x = zx
            gfxx.y = zy
          end

          if #gfx4_select > 1 then
            for i = 2, #gfx4_select do
              local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[i]]

              if gfxx.poslock or false == false then
                gfxx.x = zx - dragoff.relx[i]
                gfxx.y = zy - dragoff.rely[i]
              end
            end
          end
          glob_gfxselrect = CalcGFX4SelRect()
          lupd.update_surface = true
        end
      else
      
        if math.floor(mouse.mx/grids) ~= math.floor(mouse.last_x/grids) or math.floor(mouse.my/grids) ~= math.floor(mouse.last_y/grids) then
          local i
          local ddx = (dragoff.mx - mouse.mx)/lvar.zoom
          local ddy = (dragoff.my - mouse.my)/lvar.zoom
          local dx = (math.floor((dragoff.left-ddx)/grids)*grids)-dragoff.left
          local dy = (math.floor((dragoff.top-ddy)/grids)*grids)-dragoff.top
          for g = 1, #gfx4_select do
            local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
            if gfxx.poslock == false and poslock_select == false then
  
              --gfxx.x = math.floor((dragoff.x[g]-dx)/grids)*grids
              --gfxx.y = math.floor((dragoff.y[g]-dy)/grids)*grids
              if (lvar.lockx or false) == false then
                gfxx.x = dragoff.x[g]+dx
              end
              if (lvar.locky or false) == false then
                gfxx.y = dragoff.y[g]+dy
              end
  
            end
          end
          glob_gfxselrect = CalcGFX4SelRect()
          lupd.update_surface = true
        end
      end
      
    elseif not mouse.context and draggfx2 ~= nil and keycontext == nil and wheelcontext == nil then

      if MOUSE_over(obj.sections[60]) and draggfx2 == 'draggfx' then
        --delete
        ctl_select = nil
        DeleteSelectedCtls()
        lupd.update_gfx = true
      else
        local strip = tracks[track_select].strip
        if strips and strips[strip] then
          if gfx4_select then
            if newgrp and (newgrp.grpid == nil or newgrp.grpid == -1) then
              newgrp.grpid = Switcher_AddPage(newgrp.switchid)
            end
            local ctls = strips[strip][page].controls
            for g = 1, #gfx4_select do
              local gfxx = strips[strip][page].graphics[gfx4_select[g]]
              if gfxx then
                gfxx.hide = nil
                if newgrp then
                  gfxx.switcher = ctls[newgrp.switchid].switcherid
                  gfxx.grpid = newgrp.grpid
                end
              end
            end
            
          end
        end
        newgrp = nil
        lupd.update_gfx = true
      end
      draggfx2 = nil

    elseif mouse.context and mouse.context == contexts.dragsep_gfx then

      local dy = mouse.my - dragsep_gfx.y
      gx_h = math.min(math.max(dragsep_gfx.oh + dy, tb_butt_h*2),gfx1.main_h-obj.sections[531].y-2-8)
      def_gx_h = gx_h

      obj = GetObjects()
      lupd.update_sidebar = true

    elseif mouse.context and mouse.context == contexts.draglasso then
      if math.abs(lasso.l - mouse.mx) > 10 or math.abs(lasso.t - mouse.my) > 10 then
        lasso.r = mouse.mx
        lasso.b = mouse.my
        lasso.trig = true
        Lasso_Select_Gfx(false)
        glob_gfxselrect = CalcGFX4SelRect()

        lupd.update_surface = true
        lupd.update_cbox = true
      end
    elseif lasso ~= nil then

      if gfx4_select then
        poslock_select = false
        show_lbloptions = false
        show_gfxoptions = false
        for g = 1, #gfx4_select do
          local gfxx = strips[tracks[track_select].strip][page].graphics[gfx4_select[g]]
          if gfxx.poslock then
            poslock_select = true
          end
          if gfxx.gfxtype == lvar.gfxtype.txt then
            show_lbloptions = true
          else
            show_gfxoptions = true
          end
        end
        if show_lbloptions == true and show_gfxoptions == true then
          show_lbloptions = false
          show_gfxoptions = false
        elseif show_lbloptions == true then
          SetGfx4SelectVals()
        elseif show_gfxoptions == true then
          SetGfx4SelectVals2()
        end
      end
      if lasso.trig ~= true then
        GFXMenu()
      end
      lasso = nil
      lupd.update_surface = true
      lupd.update_cbox = true
    end


    return noscroll

  end

  function AutoSnap_SortStripLocs(s)
      local t = s
      table.sort(t, function(a, b)
          if a.t ~= b.t then
              return a.t < b.t
          end

          return a.l < b.l
      end)
      return t
  end

  function AutoSnap_CopyElement(e)

    local r = {stripid = e.stripid,
               l = e.l, t = e.t, r = e.r, b = e.b, w = e.w, h = e.h}
    return r

  end

  function AutoSnap_ReorderStripLocs(i,j,stlay_data)

    local ro = table.copy(stlay_data.sorted)
    local r = ro[i]
    local cnt = #ro
    ro = Table_RemoveEntry(ro,cnt,i)
    --if i < j then
      --j=j-1
    --end
    table.insert(ro,j,r)

    local rotab = {}
    local runx, runy = 0, 0
    local runx_s = 0
    for i = 1, #ro do

      if i == 1 then
        rotab[i] = {ro = ro[i],
                    stripid = stlay_data.loc[ro[i]].stripid,
                    l = 0,
                    t = 0,
                    r = stlay_data.loc[ro[i]].w,
                    b = stlay_data.loc[ro[i]].h,
                    w = stlay_data.loc[ro[i]].w,
                    h = stlay_data.loc[ro[i]].h,
                    runx_s = runx_s,
                    runx_e = runx_s + stlay_data.loc[ro[i]].w}
      else
        rotab[i] = {ro = ro[i],
                    stripid = stlay_data.loc[ro[i]].stripid,
                    l = runx+autosnap_itemgap,
                    t = runy,
                    r = runx+autosnap_itemgap+stlay_data.loc[ro[i]].w,
                    b = runy+stlay_data.loc[ro[i]].h,
                    w = stlay_data.loc[ro[i]].w,
                    h = stlay_data.loc[ro[i]].h,
                    runx_s = runx_s,
                    runx_e = runx_s + stlay_data.loc[ro[i]].w}
        if rotab[i].r > surface_size.w then
          rotab[i].l = 0
          rotab[i].r = rotab[i].w
          rotab[i].t = rotab[i].t + autosnap_rowheight
          rotab[i].b = rotab[i].t + rotab[i].h
        end

      end
      runx = rotab[i].l+rotab[i].w
      runy = rotab[i].t
      runx_s = runx_s + rotab[i].w + gallery_itemgap

    end

    local ot
    local itgap,sidx,eidx

    for i = 1, #ro do
      if i == 1 then
        ot = math.floor(rotab[i].t / autosnap_rowheight)
        stripw = rotab[i].w
        sidx = 1
      elseif math.floor(rotab[i].t / autosnap_rowheight) ~= ot or i == #ro then
        if i == #ro and math.floor(rotab[i].t / autosnap_rowheight) ~= ot then

          eidx = i-1
          local eg = math.min((surface_size.w - stripw) / ((eidx-(sidx-1))+2),autosnap_itemgapmax)
          for j = sidx, eidx do
            if j == sidx then
              rotab[j].l = eg
            else
              rotab[j].l = rotab[j-1].l+rotab[j-1].w+eg
            end
          end

          stripw2 = rotab[i].w
          local eg = math.min((surface_size.w - stripw2) / 2,autosnap_itemgapmax)
          rotab[i].l = eg

        else
          if i == #ro then
            stripw = stripw + rotab[i].w
            eidx = i
          else
            eidx = i-1
          end
          local eg = math.min((surface_size.w - stripw) / ((eidx-(sidx-1))+2),autosnap_itemgapmax)
          for j = sidx, eidx do
            if j == sidx then
              rotab[j].l = eg
            else
              rotab[j].l = rotab[j-1].l+rotab[j-1].w+eg
            end
          end
          ot = math.floor(rotab[i].t / autosnap_rowheight)
          stripw = rotab[i].w
          sidx = i
        end
      else
        stripw = stripw + rotab[i].w
      end
    end

    stlay_data.reordered = rotab
    return stlay_data

  end

  function AutoSnap_MoveStrips()

    local strip = tracks[track_select].strip
    for i = 1, #stlay_data.loc do

      local stripid = stlay_data.loc[i].stripid
      local ro
      for r = 1, #stlay_data.reordered do
        if stlay_data.reordered[r].stripid == stripid then
          ro = r
          break
        end
      end


      for c = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[c]
        if ctl.id == stripid then

          ctl.x = (ctl.x - stlay_data.loc[i].l) + stlay_data.reordered[ro].l
          ctl.y = (ctl.y - stlay_data.loc[i].t) + stlay_data.reordered[ro].t
          ctl.xsc = (ctl.xsc - stlay_data.loc[i].l) + stlay_data.reordered[ro].l
          ctl.ysc = (ctl.ysc - stlay_data.loc[i].t) + stlay_data.reordered[ro].t
        end
      end
      for g = 1, #strips[strip][page].graphics do
        local ctl = strips[strip][page].graphics[g]
        if ctl.id == stripid then
          ctl.x = (ctl.x - stlay_data.loc[i].l) + stlay_data.reordered[ro].l
          ctl.y = (ctl.y - stlay_data.loc[i].t) + stlay_data.reordered[ro].t
        end
      end

    end

  end

  function AutoSnap_GetStripLocs(force)

    local strip = tracks[track_select].strip
    if strips[strip] then
      local xflag = false
      local xpos
      if stlay_data and stlay_data.xpos then
        xpos = stlay_data.xpos
      end

      if force == true then stlay_data = nil end
      if stlay_data == nil then
        xflag = true
        stlay_data = {stripidx = {},
                      loc = {},
                      xpos = strips[strip][page].xpos or 0}
      end

      if lvar.stripdim and lvar.stripdim.data then
        for i = 1, #lvar.stripdim.data do

          local id = lvar.stripdim.data[i].id
          local l = lvar.stripdim.data[i].l
          local t = lvar.stripdim.data[i].t
          local r = lvar.stripdim.data[i].r
          local b = lvar.stripdim.data[i].b
          local w = r-l
          local h = b-t

          local cnt = #stlay_data.loc+1
          stlay_data.stripidx[id] = true
          stlay_data.loc[cnt] = {stripid = id,
                                l=l,t=t,r=r,b=b,w=w,h=h}

        end
      else
        local ctls = strips[strip][page].controls
        local gfxs = strips[strip][page].graphics
        for i = 1, #ctls do
          local ctl = ctls[i]
          if ctl.id then
            if stlay_data.stripidx[ctl.id] == nil then

              local l,t,r,b = ctl.xsc,ctl.ysc,ctl.xsc+ctl.wsc,ctl.ysc+ctl.hsc
              for c = 1, #ctls do
                local sctl = ctls[c]
                if sctl.id == ctl.id then

                  l = math.min(l,sctl.xsc)
                  r = math.max(r,sctl.xsc+sctl.wsc)
                  t = math.min(t,sctl.ysc)
                  b = math.max(b,sctl.ysc+sctl.hsc)

                end
              end

              for c = 1, #gfxs do
                local sctl = gfxs[c]
                if sctl.id == ctl.id then

                  l = math.min(l,sctl.x)
                  r = math.max(r,sctl.x+sctl.stretchw)
                  t = math.min(t,sctl.y)
                  b = math.max(b,sctl.y+sctl.stretchh)

                end
              end
              local cnt = #stlay_data.loc+1
              stlay_data.stripidx[ctl.id] = true
              stlay_data.loc[cnt] = {stripid = ctl.id,
                                    l=l,t=t,r=r,b=b,w=r-l,h=b-t}
            end
          end
        end
      end

      local sloc = AutoSnap_SortStripLocs(stlay_data.loc)

      stlay_data.loc = sloc

      stlay_data.sorted = {}
      stlay_data.reordered = {}
      local runx = 0
      stlay_data.hmax = 0
      for i = 1,#sloc do

        stlay_data.sorted[i] = i
        stlay_data.reordered[i] = {stripid = stlay_data.loc[i].stripid,
                                 l = stlay_data.loc[i].l,
                                 t = stlay_data.loc[i].t,
                                 r = stlay_data.loc[i].r,
                                 b = stlay_data.loc[i].b,
                                 w = stlay_data.loc[i].w,
                                 h = stlay_data.loc[i].h}

        stlay_data.loc[i].runx_s = runx
        stlay_data.reordered[i].runx_s = runx
        runx = runx + stlay_data.loc[i].w + gallery_itemgap
        stlay_data.loc[i].runx_e = runx
        stlay_data.reordered[i].runx_e = runx
        stlay_data.hmax = math.max(stlay_data.loc[i].h, stlay_data.hmax)
      end

      if xflag then
        if stlay_data.reordered[1] then
          stlay_data.xpos = strips[strip][page].xpos or -math.floor(obj.sections[10].w/2 - stlay_data.reordered[1].w/2)
        else
          stlay_data.xpos = strips[strip][page].xpos or 0
        end
      else
        if obj then
          stlay_data.xpos = math.floor(obj.sections[10].w/2 - stlay_data.reordered[1].w/2)
        end
      end
    end

    return stlay_data
  end

  function AutoSnap_GetStLayIdx(stripid)

    if stlay_data then
      for i = 1, #stlay_data.reordered do
        if stlay_data.reordered[i].stripid == stripid then
          return i
        end
      end
    end
  end

  function AutoSnap_GetEndInsertPos(strip_w,strip_h)

    local t, l = 0,0
    if stlay_data then
      for i = 1, #stlay_data.loc do

        t = math.max(stlay_data.loc[i].t)
        l = math.max(stlay_data.loc[i].r)+autosnap_itemgap

      end
      if l+strip_w > surface_size.w then
        t = t + autosnap_rowheight
        l = 0
      end
    end

    return l, t

  end

  function A_Run_Submode2(noscroll, rt, char)

    local contexts = contexts
    local mouse = mouse
    local lvar = lvar
    local lupd = lupd

    if striplayout_mt then
      striplayout_mp = 1-(((striplayout_mt-reaper.time_precise()))/striplayout_mtime)
      if striplayout_mp >= 1 then
        striplayout_mp = 1
        striplayout_mt = nil
      else
        --striplayout_mp = macScale(3,striplayout_mp)
      end
      lupd.update_surface = true
    end

    if gfx.mouse_wheel ~= 0 then
      local v = mousewheel_val()
      if MOUSE_over(obj.sections[512]) then
        slist_offset = F_limit(slist_offset - v, 0, #strip_files)
        lupd.update_sidebar = true
        gfx.mouse_wheel = 0
      end
      if MOUSE_over(obj.sections[510]) then
        sflist_offset = F_limit(sflist_offset - v, 0, #strip_folders)
        lupd.update_sidebar = true
        gfx.mouse_wheel = 0
      end
    end

    --[[if keycontext ~= nil and gfx_keydragtimer and gfx_keydragtimer < reaper.time_precise() then
      ArrowKey_Shift(0,ctl_select,gfx3_select)
      gfx_keydragtimer = nil
    elseif keycontext ~= nil and char == 0 and not gfx_keydragtimer then
      gfx_keydragtimer = reaper.time_precise() + 0.3
    elseif gfx_keydragtimer and char ~= 0 then
      gfx_keydragtimer = nil
    end]]
          
    if (ctl_select ~= nil or gfx3_select ~= nil) and (char ~= 0 or keycontext) then

      ArrowKey_Shift(char,ctl_select,gfx3_select)

    elseif MOUSE_click(obj.sections[511]) then
      SaveStrip()
      lupd.update_gfx = true
    end

    if show_striplayout == true then

      noscroll = A_Run_StripLayout(noscroll, rt)

    elseif mouse.mx > obj.sections[10].x then
      if mouse.context == nil and MOUSE_click(obj.sections[10]) then
        if strips and tracks[track_select] and strips[tracks[track_select].strip] then

          local strip = tracks[track_select].strip
          local ctls = strips[strip][page].controls
          local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)
          local grpid, switchid
          local ctl = ctls[c]
          if ctl then
            grpid = ctl.grpid
            switchid = ctl.switcherid
          end


          --local ctls = strips[tracks[track_select].strip][page].controls
          --for i = 1, #ctls do

            --local ctl = ctls[i]

            --local xywh
            --[[xywh = {x = ctl.x*lvar.zoom - surface_offset.x*lvar.zoom + obj.sections[10].x,
                    y = ctl.y*lvar.zoom - surface_offset.y*lvar.zoom + obj.sections[10].y,
                    w = ctl.w*lvar.zoom,
                    h = ctl.ctl_info.cellh*lvar.zoom,
                    p = ctl.gfxpage or 0}
            if xywh.p == 0 and MOUSE_click(xywh) then]]

              --local hidden = Switcher_CtlsHidden(ctl.switcher, ctl.grpid)
              --local stripid, grpid
              --[[if hidden == false then
                stripid = ctl.id
                grpid = ctl.grpid
                switchid = ctl.switcherid
              end]]
              if stripid ~= nil or grpid ~= nil or switchid ~= nil then

                --if switchid then
                --  SelectSwitchElements(switchid, i)  --cannot do this as a simple click on switcher moves all controls to visible switcher page
                --[[else]]if mouse.shift then
                  ctl_select = SelectGroupElements(grpid)
                else
                  SelectStripElements(stripid)
                end

                dragoff = {x = mouse.mx - ctls[ctl_select[1].ctl].x*lvar.zoom - 0.5*ctls[ctl_select[1].ctl].w*lvar.zoom + surface_offset.x*lvar.zoom - obj.sections[10].x,
                           y = mouse.my - ctls[ctl_select[1].ctl].y*lvar.zoom - 0.5*ctls[ctl_select[1].ctl].ctl_info.cellh*lvar.zoom + surface_offset.y*lvar.zoom}

                if ctl_select ~= nil and not mouse.ctrl then --and not mouse.alt then
                  dragctl = 'dragctl'
                  Undo_Set({'x','xsc','y','ysc','grpid'})
                  
                  mouse.context = contexts.dragctl
                  GenCtlDragPreview(gui)
                  A_HideSelectedCtls(true, ctl_select, gfx3_select)

                  --[[for i = 1, #ctl_select do
                    ctls[ctl_select[i].ctl].hide = true
                  end
                  if gfx3_select and #gfx3_select > 0 then
                    local gfxx = strips[tracks[track_select].strip][page].graphics
                    for i = 1, #gfx3_select do
                      gfxx[gfx3_select[i].ctl].hide = true
                    end
                  end]]
                  SetCtlBitmapRedraw()
                end
                lupd.update_gfx = true
                --break
              end

            --end
          --end
          if not mouse.context then
            --A_HideSelectedCtls(false, ctl_select, gfx3_select)
            ClearSelected(ctl_select)
            
            ctl_select = nil
            gfx3_select = nil
          end
        end
      end
    end

    if mouse.context and mouse.context == contexts.dragctl then

      local x = mouse.mx -obj.sections[10].x-surface_offset.x
      local y = mouse.my -obj.sections[10].y-surface_offset.y
      local ctls = strips[tracks[track_select].strip][page].controls
      newgrp = nil
      vert = true
      local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
      if c then
        local i = c
        local ctl = strips[tracks[track_select].strip][page].controls[i]
        if ctl.ctlcat == ctlcats.switcher and SwitcherInSelected(ctl.switcherid) == false then
          local swid = ctl.switcherid
          if swid and switchers[swid].switchmode ~= 1 then
            local x = mouse.mx -obj.sections[10].x+surface_offset.x
            local y = mouse.my -obj.sections[10].y+surface_offset.y
            if x > ctl.x+ctl.w/2 then
              vert = false
            end
            newgrp = {grpid = switchers[ctl.switcherid].current,
                      switchid = i,
                      vert = vert}
          end
        end
      end

      if newgrp then
        local rl, rt, rr, rb = GetLTRBControlInGrp(newgrp.grpid, newgrp.switchid)
        --local rl, rt, rr, rb = GetLTRBControlInSel(newgrp.switchid)
        local dl, dt, _, _ = GetGFXOffsetInSel()
        if math.floor(mouse.mx) ~= math.floor(mouse.last_x) or math.floor(mouse.my) ~= math.floor(mouse.last_y) then
          local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
          local scale = ctl.scale

          local zx, zy = rl, rb
          if newgrp.vert == false then
            zx, zy = rr, rt
          end

          local mrelx, mrely = 0,0
          if #ctl_select > 1 then
            for cs = 2, #ctl_select do
              mrelx = math.max(mrelx, ctl_select[cs].relx)
              mrely = math.max(mrely, ctl_select[cs].rely)
            end
            if gfx3_select then
              for cs = 1, #gfx3_select do
                mrelx = math.max(mrelx, gfx3_select[cs].relx)
                mrely = math.max(mrely, gfx3_select[cs].rely)
              end
            end
          end
          zx = zx + mrelx
          zy = zy + mrely

          if nz(ctl.poslock,false) == false then
            ctl.x = zx
            ctl.y = zy
            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end

          if #ctl_select > 1 then
            for i = 2, #ctl_select do
              local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

              if nz(ctl.poslock,false) == false then
                scale = ctl.scale
                ctl.x = zx - ctl_select[i].relx
                ctl.y = zy - ctl_select[i].rely
                ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
                ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              end
            end
          end

          if gfx3_select and #gfx3_select > 0 then
            for i = 1, #gfx3_select do
              local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]
              ctl.x = zx - gfx3_select[i].relx
              ctl.y = zy - gfx3_select[i].rely
            end
          end
          lupd.update_surface = true
        end
      else
        if math.floor(mouse.mx/settings_gridsize) ~= math.floor(mouse.last_x/settings_gridsize) or math.floor(mouse.my/settings_gridsize) ~= math.floor(mouse.last_y/settings_gridsize) then
          local i
          local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl]
          local scale = ctl.scale
          local zx, zy = 0.5*ctl.w, 0.5*ctl.ctl_info.cellh

          local mxx, myy = (mouse.mx - dragoff.x - obj.sections[10].x + surface_offset.x*lvar.zoom)/lvar.zoom,
                           (mouse.my - dragoff.y - obj.sections[10].y + surface_offset.y*lvar.zoom)/lvar.zoom

          if nz(ctl.poslock,false) == false then
            ctl.x = math.floor((mxx-zx)/settings_gridsize)*settings_gridsize
            ctl.y = math.floor((myy-zy)/settings_gridsize)*settings_gridsize
            --ctl.x = math.floor((mouse.mx-zx - surface_offset.x)/settings_gridsize)*settings_gridsize
            --                                                                   - math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
            --ctl.y = math.floor((mouse.my-zy - surface_offset.y)/settings_gridsize)*settings_gridsize
            --                                                                   - math.floor((dragoff.y)/settings_gridsize)*settings_gridsize

            ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
            ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
          end
          if #ctl_select > 1 then
            for i = 2, #ctl_select do
              local ctl = strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl]

              if nz(ctl.poslock,false) == false then
                scale = ctl.scale
                ctl.x = math.floor((mxx-zx)/settings_gridsize)*settings_gridsize - ctl_select[i].relx
                ctl.y = math.floor((myy-zy)/settings_gridsize)*settings_gridsize - ctl_select[i].rely

                --ctl.x = math.floor((mouse.mx-zx - surface_offset.x)/settings_gridsize)*settings_gridsize
                --         - math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
                --         - ctl_select[i].relx
                --ctl.y = math.floor((mouse.my-zy - surface_offset.y)/settings_gridsize)*settings_gridsize
                --         - math.floor((dragoff.y)/settings_gridsize)*settings_gridsize
                --         - ctl_select[i].rely
                ctl.xsc = ctl.x + math.floor(ctl.w/2 - (ctl.w*scale)/2)
                ctl.ysc = ctl.y + math.floor(ctl.ctl_info.cellh/2 - (ctl.ctl_info.cellh*scale)/2)
              end
            end
          end
          if gfx3_select and #gfx3_select > 0 then
            for i = 1, #gfx3_select do
              local ctl = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]
              ctl.x = math.floor((mxx-zx)/settings_gridsize)*settings_gridsize - gfx3_select[i].relx
              ctl.y = math.floor((myy-zy)/settings_gridsize)*settings_gridsize - gfx3_select[i].rely

              --ctl.x = math.floor((mouse.mx-zx - surface_offset.x)/settings_gridsize)*settings_gridsize
              --               - math.floor((dragoff.x)/settings_gridsize)*settings_gridsize
              --               - gfx3_select[i].relx
              --ctl.y = math.floor((mouse.my-zy - surface_offset.y)/settings_gridsize)*settings_gridsize
              --               - math.floor((dragoff.y)/settings_gridsize)*settings_gridsize
              --               - gfx3_select[i].rely
            end
          end
          lupd.update_surface = true
        end
      end

    elseif mouse.context == nil and dragctl ~= nil and keycontext == nil then
      dragctl = nil
      if MOUSE_over(obj.sections[60]) then
        --delete
        DeleteSelectedCtls(true)
        lupd.update_gfx = true
      else
        DropCtls()
      end
      UnhideCtls()
      SetCtlBitmapRedraw()
    end

    if MOUSE_click(obj.sections[515]) and (SF_butt_cnt-1 < #strip_folders+1) then

      local msbh = obj.sections[515].h
      local p1 = 1 / (#strip_folders+1)
      local sbh = math.ceil(F_limit(p1*(SF_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(sflist_offset * p2)

      sby = math.min(sby,msbh-sbh-1)

      if mouse.my >= obj.sections[515].y + sby and mouse.my <= obj.sections[515].y + sby+sbh then

        if SF_butt_cnt-1 < #strip_folders+1 then
          mouse.context = contexts.scrollstripfols
          scrollsidebar = {y = mouse.my-obj.sections[515].y, lo = sflist_offset}
          lupd.update_sidebar = true
        else
          sflist_offset = 0
        end

      elseif mouse.my < obj.sections[515].y + sby then

      elseif mouse.my > obj.sections[515].y + sby+sbh then

      end

    elseif MOUSE_click(obj.sections[510]) then
      local i = math.floor(((mouse.my - obj.sections[510].y)) / tb_butt_h)-1
      if i == -1 then
        if mouse.mx < obj.sections[510].w/2 then
          sflist_offset = sflist_offset - math.max(SF_butt_cnt-1,1)
          if sflist_offset < 0 then
            sflist_offset = 0
          end
        else
          if sflist_offset + SF_butt_cnt-1 < #strip_folders then
            sflist_offset = sflist_offset + math.max(SF_butt_cnt-1,1)
          end
        end
        lupd.update_gfx = true
      elseif strip_folders[i + sflist_offset] then
        stripfol_select = i + sflist_offset
        PopulateStrips()
        lupd.update_gfx = true
      end

    elseif MOUSE_click_RB(obj.sections[510]) then

      local mstr = 'New folder'
      gfx.x = mouse.mx
      gfx.y = mouse.my
      local res = gfx.showmenu(mstr)
      if res > 0 then
        if res == 1 then
          OpenEB(121, 'Please enter folder name:')
        end
      end

    elseif MOUSE_click(obj.sections[514]) and (S_butt_cnt-1 < #strip_files+1) then

      local msbh = obj.sections[514].h
      local p1 = 1 / (#strip_files+1)
      local sbh = math.ceil(F_limit(p1*(S_butt_cnt-1) * msbh,20,msbh))
      local p2 = p1*msbh
      local sby = math.floor(slist_offset * p2)

      sby = math.min(sby,msbh-sbh-1)

      if mouse.my >= obj.sections[514].y + sby and mouse.my <= obj.sections[514].y + sby+sbh then

        if S_butt_cnt-1 < #strip_files+1 then
          mouse.context = contexts.scrollstripfiles
          scrollsidebar = {y = mouse.my-obj.sections[514].y, lo = slist_offset}
          lupd.update_sidebar = true
        else
          slist_offset = 0
        end

      elseif mouse.my < obj.sections[514].y + sby then

      elseif mouse.my > obj.sections[514].y + sby+sbh then

      end

    elseif MOUSE_click(obj.sections[512]) then
      local i = math.floor(((mouse.my - obj.sections[512].y)) / tb_butt_h)
      local xneg = 0
      if S_butt_cnt-1 < #strip_files+1 then
        --scrollbar visible
        xneg = obj.sections[514].w
      end

      if i == 0 then
        if mouse.mx < obj.sections[512].w/2 then
          slist_offset = slist_offset - math.max((S_butt_cnt-1),1)
          if slist_offset < 0 then
            slist_offset = 0
          end
        else
          if slist_offset + S_butt_cnt-1 < #strip_files then
            slist_offset = slist_offset + math.max((S_butt_cnt-1),1)
          end
        end
        lupd.update_gfx = true

      elseif strip_files[i-1 + slist_offset] then

        if mouse.mx <= obj.sections[512].w - butt_h - xneg then
          strip_select = i-1 + slist_offset
          --gen preview
          loadstrip = LoadStrip(strip_select)
          if loadstrip then

            loadstrip.strip_w, loadstrip.strip_h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)

            --if settings_stripautosnap == true then
              stlay_data = AutoSnap_GetStripLocs(true)
            --end
            mouse.context = contexts.dragstrip
          end
          lupd.update_gfx = true

        else
          local fsp = i-1 + slist_offset
          if InFavs(strip_folders[stripfol_select].fn..'/'..strip_files[fsp].fn) then
            RemoveFav(strip_folders[stripfol_select].fn..'/'..strip_files[fsp].fn)
          else
            strip_favs[#strip_favs+1] = strip_folders[stripfol_select].fn..'/'..strip_files[fsp].fn
          end
          lupd.update_sidebar = true
        end
      end

    elseif MOUSE_click_RB(obj.sections[512]) then

      if strip_select then
        local i = math.floor(((mouse.my - obj.sections[512].y)) / tb_butt_h)
        if strip_select == i-1 + slist_offset then
          local sd_m, sd_g, sd = '', '', ''
          if strip_default_mast then
            sd_m = '!'
          end
          if strip_default_glob then
            sd_g = '!'
          end
          if strip_default then
            sd = '!'
          end
          local sepids = ''
          if lvar.addstrip_keepseparateids == true then
            sepids = '!'
          end
          mstr = sd..'Set Default (Track)|'..sd_m..'Set Default (Master)|'..sd_g..'Set Default (Global)||Clear Default (Track)|Clear Default (Master)|Clear Default (Global)||Save (Overwrite)'
                      ..'||Add to favorites||Export Shareable Strip File|Import Shared Strip File||Set Plugin Default (single plugin strips only)|Set Plugin Default By Name (single plugin strips only)||'..sepids..'Load Strip: Keep Separate Strip IDs'
                       ..'||Strip: Enable Quick Load|Strip: Disable Quick Load||Strip Folder: Enable Quick Load|Strip Folder: Disable Quick Load'
        else
          local sepids = ''
          if lvar.addstrip_keepseparateids == true then
            sepids = '!'
          end
          mstr = '#Set Default (Track)|#Set Default (Master)|#Set Default (Global)||Clear Default (Track)|Clear Default (Master)|Clear Default (Global)||'
                 ..'#Save (Overwrite)||#Add to favorites||#Export Shareable Strip File|Import Shared Strip File||#Set Plugin Default (single plugin strips only)|#Set Plugin Default By Name (single plugin strips only)||'..sepids..'Load Strip: Keep Separate Strip IDs'
                 ..'||#Strip: Enable Quick Load|#Strip: Disable Quick Load||Strip Folder: Enable Quick Load|Strip Folder: Disable Quick Load'
        end
        gfx.x, gfx.y = mouse.mx, mouse.my
        res = OpenMenu(mstr)
        if res ~= 0 then
          if res == 1 then

            strip_default = {strip_select = strip_select,
                             stripfol_select = stripfol_select}
          elseif res == 2 then
            strip_default_mast = {strip_select = strip_select,
                                  stripfol_select = stripfol_select}
          elseif res == 3 then
            strip_default_glob = {strip_select = strip_select,
                                  stripfol_select = stripfol_select}
          elseif res == 4 then
            strip_default = nil
          elseif res == 5 then
            strip_default_mast = nil
          elseif res == 6 then
            strip_default_glob = nil
          elseif res == 7 then

            local ostoff = slist_offset
            SaveStrip3(string.sub(strip_files[strip_select].fn,1,string.len(strip_files[strip_select].fn)-6))
            slist_offset = ostoff
          elseif res == 8 then
            strip_favs[#strip_favs+1] = strip_folders[stripfol_select].fn..'/'..strip_files[strip_select].fn
          elseif res == 9 then
            StripShare_Export(strip_folders[stripfol_select].fn..'/', strip_files[strip_select].fn)
          elseif res == 10 then
            StripShare_Import()

          elseif res == 11 then
            Strip_SetPlugDef(strip_select, stripfol_select)
          elseif res == 12 then
            Strip_SetPlugDef2(strip_select, stripfol_select)
          elseif res == 13 then
            lvar.addstrip_keepseparateids = not lvar.addstrip_keepseparateids
          elseif res == 14 then
            SetStripQuickLoadSetting_ss(stripfol_select, strip_select, true)
          elseif res == 15 then
            SetStripQuickLoadSetting_ss(stripfol_select, strip_select, false)
          elseif res == 16 then
            SetStripQuickLoadSetting_ss(stripfol_select, nil, true)
          elseif res == 17 then
            SetStripQuickLoadSetting_ss(stripfol_select, nil, false)
          end
        end
      end
    elseif MOUSE_click(obj.sections[513]) then

      mouse.context = contexts.dragsep_strip
      dragsep_strip = {y = mouse.my, oh = sf_h}

    end

    if mouse.context == contexts.scrollstripfiles then

      local my = mouse.my - (obj.sections[514].y)
      local lstcnt = #strip_files+1

      local oos = slist_offset
      slist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[514].h) * lstcnt),0,lstcnt-(S_butt_cnt-1))
      if slist_offset ~= oos then
        lupd.update_sidebar = true
      end

    elseif mouse.context == contexts.scrollstripfols then

      local my = mouse.my - (obj.sections[515].y)
      local lstcnt = #strip_folders+1

      local oos = sflist_offset
      sflist_offset = F_limit(math.floor(scrollsidebar.lo + ((my-scrollsidebar.y)/obj.sections[515].h) * lstcnt),0,lstcnt-(SF_butt_cnt-1))
      if sflist_offset ~= oos then
        lupd.update_sidebar = true
      end

    elseif mouse.context and mouse.context == contexts.dragstrip then
      dragstripx = true --to force dropped action even if not
      if mouse.mx ~= mouse.last_x or mouse.my ~= mouse.last_y then

        if settings_stripautosnap == true or stripgallery_view == 1 then
          local x,y = AutoSnap_GetEndInsertPos(loadstrip.strip_w,loadstrip.strip_h)
          dragstrip = {x = x+obj.sections[10].x-surface_offset.x, y = y+obj.sections[10].y-surface_offset.y, xx = x, yy = y}
          lupd.update_surface = true
        else
          newgrp = nil
          local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
          if c then
            local i = c
            local ctl = strips[tracks[track_select].strip][page].controls[i]
            if ctl.ctlcat == ctlcats.switcher and show_striplayout == false then
              local swid = ctl.switcherid
              if swid and switchers[swid].switchmode ~= 1 then
                local x = mouse.mx -obj.sections[10].x +surface_offset.x
                local y = mouse.my -obj.sections[10].y +surface_offset.y
                vert = true
                if x > ctl.x+ctl.w/2 then
                  vert = false
                end
                newgrp = {grpid = switchers[ctl.switcherid].current,
                          switchid = i,
                          vert = vert}

                local rl, rt, rr, rb = GetLTRBControlInGrp(newgrp.grpid, newgrp.switchid)
                local zx, zy = rl, rb
                if newgrp.vert == false then
                  zx, zy = rr, rt
                end
                dragstrip = {x = zx+obj.sections[10].x-surface_offset.x, y = zy+obj.sections[10].y-surface_offset.y,xx = zx,yy = zy}
              else
                dragstrip = {x = mouse.mx, y = mouse.my, xx=mouse.mx,yy=mouse.my}
              end
            else
              dragstrip = {x = mouse.mx, y = mouse.my, xx=mouse.mx,yy=mouse.my}
            end
          else
            dragstrip = {x = mouse.mx, y = mouse.my, xx=mouse.mx,yy=mouse.my}
          end
          lupd.update_surface = true

        end
      end

    elseif dragstripx ~= nil then
      --Dropped
      --image_count = image_count_add
      if dragstrip and newgrp == nil then
        local ignore = nil
        if settings_stripautosnap == true then
          ignore = true
        end
        if show_striplayout == true then
          if settings_stripautosnap == true or stripgallery_view == 1 then
            if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].h then
              Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y,ignore)
              SetASLocs()
            end
          else
            if mouse.mx >= obj.sections[10].x+striplayout_data.x and mouse.mx <= obj.sections[10].x+striplayout_data.x+striplayout_data.w and
               mouse.my >= obj.sections[10].y+striplayout_data.y and mouse.my <= obj.sections[10].y+striplayout_data.y+striplayout_data.h then

              local x = mouse.mx- (obj.sections[10].x+striplayout_data.x)
              local y = mouse.my- (obj.sections[10].y+striplayout_data.y)
              x = (x/striplayout_data.w)*surface_size.w
              y = (y/striplayout_data.h)*surface_size.h
              Strip_AddStrip(loadstrip, x-surface_offset.x, y-surface_offset.y, false)
              SetASLocs()

            end
          end
        else
          if dragstrip.x >= obj.sections[10].x and dragstrip.x < obj.sections[10].x+obj.sections[10].w and dragstrip.y >= obj.sections[10].y and dragstrip.y < obj.sections[10].y+obj.sections[10].h then
            if mouse.mx >= obj.sections[10].x and mouse.mx < obj.sections[10].x+obj.sections[10].w and mouse.my >= obj.sections[10].y and mouse.my < obj.sections[10].y+obj.sections[10].h then
              Strip_AddStrip(loadstrip, (dragstrip.x-obj.sections[10].x+surface_offset.x*lvar.zoom)/lvar.zoom - surface_offset.x,
                                        (dragstrip.y-obj.sections[10].y+surface_offset.y*lvar.zoom)/lvar.zoom - surface_offset.y,ignore)
              --DBG('ASDF')
            end
          end
        end
      elseif dragstrip and newgrp then
        if dragstrip.x > obj.sections[10].x and dragstrip.x < obj.sections[10].w and dragstrip.y > obj.sections[10].y and dragstrip.y < obj.sections[10].h then
          local stripid, _, grpid = Strip_AddStrip(loadstrip, dragstrip.x-obj.sections[10].x, dragstrip.y-obj.sections[10].y, true)

          local ctls = strips[tracks[track_select].strip][page].controls
          local gfxx = strips[tracks[track_select].strip][page].graphics
          local switchid = ctls[newgrp.switchid].switcherid
          local ctl_sw = ctls[newgrp.switchid]

          local x,y = ctl_sw.x - surface_offset.x, ctl_sw.y - surface_offset.y
          y = y + ctl_sw.ctl_info.cellh

          local sw_cur = #switchers[switchid].grpids+1
          switchers[switchid].grpids[sw_cur] = {}
          switchers[switchid].grpids[sw_cur].id = grpid
          switchers[switchid].grpids[sw_cur].name = string.match(strip_files[strip_select].fn,'(.-).strip')

          if ctl_sw then
            ctl_sw.param_info.paramname = string.format('%i',sw_cur)..': '..switchers[switchid].grpids[sw_cur].name
          end
          switchers[switchid].current = grpid

          for c = 1, #ctls do
            if ctls[c].grpid == grpid then
              ctls[c].switcher = switchid

              if ctls[c].ctlcat == ctlcats.switcher then
                --add parent info
                local sid = ctls[c].switcherid
                switchers[sid].parent = {switcherid = switchid,
                                         grpid = grpid}
              end
            end
          end
          for c = 1, #gfxx do
            if gfxx[c].grpid == grpid then
              gfxx[c].switcher = switchid
            end
          end

          lupd.update_bg = true
        end
      end
      loadstrip = nil
      dragstrip = nil
      dragstripx = nil
      ctl_select = nil
      lupd.update_gfx = true

      SetCtlBitmapRedraw()
      reaper.MarkProjectDirty(0)

    elseif mouse.context and mouse.context == contexts.dragsep_strip then

      local dy = mouse.my - dragsep_strip.y
      sf_h = math.min(math.max(dragsep_strip.oh + dy, tb_butt_h*2),gfx1.main_h-obj.sections[510].y-4-8)
      def_sf_h = sf_h
      obj = GetObjects()
      lupd.update_sidebar = true

    end

    --[[if lvar.ss3_bmp and reaper.time_precise() > lvar.ss3_bmp.delay then
      SaveStrip_CreateThumb2(lvar.ss3_bmp)
      lvar.ss3_bmp = nil
    end]]

    return noscroll

  end

  function A_HideSelectedCtls(hide, ctl_select, gfx_select, gfx4_select)
    UnhideCtls()
    if hide then
      if not lvar.ctlshidden then
        lvar.ctlshidden = {}
      end
      lvar.ctlshidden.gfx = nil
      local idx = #lvar.ctlshidden+1
      
      local ctls = strips[tracks[track_select].strip][page].controls
      if ctl_select and #ctl_select > 0 then
        for i = 1, #ctl_select do
          ctls[ctl_select[i].ctl].hide = hide
          lvar.ctlshidden[idx] = {ctl = ctls[ctl_select[i].ctl], c = ctl_select[i].ctl}
          idx = idx + 1
        end
      end
      if gfx_select and #gfx_select > 0 then
        local gfxx = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx_select do
          gfxx[gfx_select[i].ctl].hide = hide
          lvar.ctlshidden[idx] = {ctl = gfxx[gfx_select[i].ctl], c = gfx_select[i].ctl}
          idx = idx + 1
        end
      end
      if gfx4_select and #gfx4_select > 0 then
        local gfxx = strips[tracks[track_select].strip][page].graphics
        for i = 1, #gfx4_select do
          gfxx[gfx4_select[i]].hide = hide
          lvar.ctlshidden[idx] = {ctl = gfxx[gfx4_select[i]], c = gfx4_select[i]}
          idx = idx + 1
        end
        lvar.ctlshidden.gfx = true
      end

    end
  end
  
  function UnhideCtls()
   
    if lvar.ctlshidden then
      for c = 1, #lvar.ctlshidden do
        if lvar.ctlshidden[c].ctl then
          lvar.ctlshidden[c].ctl.hide = nil
          SetCtlDirty(lvar.ctlshidden[c].c)
        end
      end
      if lvar.ctlshidden.gfx == true then
        lupd.update_gfx = true
      else
        lupd.update_ctls = true
      end
      lvar.ctlshidden = nil
      dragctl = nil
      draggfx2 = nil
      --dragoff = nil
      --lupd.update_surface = true
      if lvar.ctlsmoved then
        SetCtlBitmapRedraw()
        lvar.ctlsmoved = nil
      end
    end
  end

  function A_Run_XXYMode(rt)

    local contexts = contexts
    local mouse = mouse

    if mouse.context == nil and (MOUSE_click(obj.sections[221])) then
      local i = math.floor((mouse.my - obj.sections[221].y)/butt_h)
      if i == 0 then

        xxymode = xxymode + 1
        if xxymode > #lvar.xxymode_table-1 then
          xxymode = 0
        end
        xxypath_edit = false
        XXYRecord_Set(false)
        lupd.update_snaps = true
        lupd.update_xxy = true
      end

      local mx, my = mouse.mx, mouse.my
      mouse.mx, mouse.my = mouse.mx - obj.sections[221].x, mouse.my - obj.sections[221].y
      if MOUSE_click(obj.sections[235]) then

        XXYRecord_Set(not xxyrecord)
        lupd.update_gfx = true

      end

      mouse.mx, mouse.my = mx, my

    elseif mouse.context == nil and MOUSE_click(obj.sections[222]) then
      show_xxy = false
      XXYRecord_Set(false)

      --SaveSingleStrip(tracks[track_select].strip)
      reaper.MarkProjectDirty(0)
      lupd.update_gfx = true
    end

    if xxymode == 0 then

      if gfx.mouse_wheel ~= 0 then
        xywh = {x = obj.sections[221].x+obj.sections[223].x,
                y = obj.sections[221].y+obj.sections[223].y,
                w = obj.sections[223].w,
                h = obj.sections[223].h}

        if MOUSE_over(xywh) then
          local v = mousewheel_val()
          xxylist_offset = F_limit(xxylist_offset - v,0,#snapshots[tracks[track_select].strip][page][sstype_select].snapshot-1)
          lupd.update_gfx = true
        end

        gfx.mouse_wheel = 0
      end

      if mouse.context == nil and (MOUSE_click(obj.sections[220]) or MOUSE_click_RB(obj.sections[220])) then

        if mouse.LB then
          local strip = tracks[track_select].strip
          if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
            mouse.context = contexts.xxy_drag
          end

        elseif mouse.RB then
          local strip = tracks[track_select].strip
          if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then

            for p = 1, #xxy[strip][page][sstype_select].points do

              xywh = {x = obj.sections[220].x + xxy[strip][page][sstype_select].points[p].x*obj.sections[220].w - 8,
                      y = obj.sections[220].y + xxy[strip][page][sstype_select].points[p].y*obj.sections[220].h - 8,
                      w = 16,
                      h = 16}
              if MOUSE_click_RB(xywh) and mouse.shift == false and mouse.ctrl == false then
                mouse.context = contexts.xxy_movesnap
                movesnap = {xoff = mouse.mx - xywh.x, yoff = mouse.my - xywh.y, p = p}
                break
              elseif MOUSE_click_RB(xywh) and mouse.shift == true then
                XXY_PtToggleActive(p)
                lupd.update_xxy = true
                break

              elseif MOUSE_click_RB(xywh) and mouse.ctrl == true then

                DeleteXXY_pt(p)
                lupd.update_xxy = true
                break
              end

            end

          end

        end

      elseif mouse.context == nil and (MOUSE_click(obj.sections[221]) or MOUSE_click_RB(obj.sections[221])) then
        local mx,my = mouse.mx,mouse.my
        mouse.mx = mouse.mx-obj.sections[221].x
        mouse.my = mouse.my-obj.sections[221].y

        local strip = tracks[track_select].strip

        if MOUSE_click(obj.sections[223]) then
          local i = math.floor((mouse.my - obj.sections[223].y)/butt_h)

          if i == 0 then
            if mouse.mx < obj.sections[223].x + obj.sections[223].w/2 then
              xxylist_offset = math.max(xxylist_offset - SSXXY_butt_cnt,0)
              lupd.update_gfx = true
            else
              xxylist_offset = math.min(xxylist_offset + SSXXY_butt_cnt, math.max(#snapshots[strip][page][sstype_select].snapshot - SSXXY_butt_cnt,0))
              lupd.update_gfx = true
            end
          else
            if snapshots[strip][page][sstype_select][i+xxylist_offset] or
               snapshots[strip][page][sstype_select].snapshot[i+xxylist_offset] then
                mouse.context = contexts.xxy_dragsnap
                ss_select = i+xxylist_offset
                lupd.update_gfx = true
                dragsnap = {x = mouse.mx, y = mouse.my, ss = i+xxylist_offset}
            end
          end

        elseif MOUSE_click(obj.sections[225]) then
          mouse.context = contexts.xxy_gravityslider

        elseif mouse.context == nil and MOUSE_click(obj.sections[226]) then

          if snapshots[tracks[track_select].strip] then
            sstype_select = F_limit(sstype_select + 1, 2, #snapshots[tracks[track_select].strip][page])
            if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
              xxypath_select = xxy[tracks[track_select].strip][page][sstype_select].pathidx
            else
              xxypath_select = nil
            end
          end
          ss_select = nil
          xxylist_offset = 0
          lupd.update_gfx = true

        elseif mouse.context == nil and MOUSE_click_RB(obj.sections[226]) then

          if snapshots[tracks[track_select].strip] then
            sstype_select = F_limit(sstype_select - 1, 2, #snapshots[tracks[track_select].strip][page])
            if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
              xxypath_select = xxy[tracks[track_select].strip][page][sstype_select].pathidx
            else
              xxypath_select = nil
            end
          end
          ss_select = nil
          xxylist_offset = 0
          lupd.update_gfx = true

        elseif MOUSE_click(obj.sections[232]) then

          if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
            local f = {targettype = 0,
                       strip = tracks[track_select].strip,
                       page = page,
                       sstype = sstype_select,
                       xy = 0}

            mouse.mx, mouse.my = mx, my
            local fad = SetAutomationFader(f, xxy[tracks[track_select].strip][page][sstype_select].xfader, true)
            if fad == -2 then
              DeleteFader(xxy[tracks[track_select].strip][page][sstype_select].xfader)
              lupd.update_gfx = true
            elseif fad ~= -1 then
              --[[if xxy[tracks[track_select].strip][page][sstype_select].xfader and xxy[tracks[track_select].strip][page][sstype_select].xfader ~= fad then
                faders[xxy[tracks[track_select].strip][page][sstype_select].xfader] = {}
              end
              xxy[tracks[track_select].strip][page][sstype_select].xfader = fad]]
              AssignFader(fad, f)
              lupd.update_gfx = true
            end
          end

        elseif MOUSE_click(obj.sections[233]) then

          if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
            local f = {targettype = 0,
                       strip = tracks[track_select].strip,
                       page = page,
                       sstype = sstype_select,
                       xy = 1}

            mouse.mx, mouse.my = mx, my
            local fad = SetAutomationFader(f, xxy[tracks[track_select].strip][page][sstype_select].yfader, true)
            if fad == -2 then
              DeleteFader(xxy[tracks[track_select].strip][page][sstype_select].yfader)
              lupd.update_gfx = true
            elseif fad ~= -1 then
              --if xxy[tracks[track_select].strip][page][sstype_select].yfader and xxy[tracks[track_select].strip][page][sstype_select].yfader ~= fad then
              --  faders[xxy[tracks[track_select].strip][page][sstype_select].yfader] = {}
              --end
              --xxy[tracks[track_select].strip][page][sstype_select].yfader = fad
              AssignFader(fad, f)
              lupd.update_gfx = true
            end
          end

        end

        mouse.mx, mouse.my = mx, my
      end

      if mouse.context and mouse.context == contexts.xxy_drag then
        local ox, oy = xxy[tracks[track_select].strip][page][sstype_select].x, xxy[tracks[track_select].strip][page][sstype_select].y
        xxy[tracks[track_select].strip][page][sstype_select].x = F_limit((mouse.mx - obj.sections[220].x) / obj.sections[220].w,0,1)
        xxy[tracks[track_select].strip][page][sstype_select].y = F_limit((mouse.my - obj.sections[220].y) / obj.sections[220].h,0,1)

        if xxy[tracks[track_select].strip][page][sstype_select].x ~= ox or xxy[tracks[track_select].strip][page][sstype_select].y ~= oy then
          XXY_Set(tracks[track_select].strip, page, sstype_select)
          lupd.update_xxypos = true
        end

      elseif mouse.context and mouse.context == contexts.xxy_movesnap then
        local x = (mouse.mx - obj.sections[220].x)/obj.sections[220].w
        local y = (mouse.my - obj.sections[220].y)/obj.sections[220].h

        xxy[tracks[track_select].strip][page][sstype_select].points[movesnap.p].x = F_limit(x,0,1)
        xxy[tracks[track_select].strip][page][sstype_select].points[movesnap.p].y = F_limit(y,0,1)

        local strip = tracks[track_select].strip
        if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
          XXY_Set(tracks[track_select].strip, page, sstype_select)
        end
        lupd.update_xxy = true

      elseif mouse.context and mouse.context == contexts.xxy_gravityslider then
        local mx,my = mouse.mx,mouse.my
        mouse.mx = mouse.mx-obj.sections[221].x
        mouse.my = mouse.my-obj.sections[221].y

        local val = F_limit(MOUSE_sliderHBar(obj.sections[225]),0,1)
        if val ~= nil then
          xxy_gravity = val*3+1
          local strip = tracks[track_select].strip
          if xxy and xxy[strip] and xxy[strip][page] and xxy[strip][page][sstype_select] then
            XXY_Set(tracks[track_select].strip, page, sstype_select)
          end
          lupd.update_gfx = true
        end
        mouse.mx, mouse.my = mx, my

      elseif mouse.context and mouse.context == contexts.xxy_dragsnap then
        dragsnap.x = mouse.mx
        dragsnap.y = mouse.my
        lupd.update_xxy = true

      elseif dragsnap ~= nil then
        if MOUSE_over(obj.sections[220]) then
          local strip = tracks[track_select].strip
          local x,y = mouse.mx - obj.sections[220].x, mouse.my - obj.sections[220].y
          x = x/obj.sections[220].w
          y = y/obj.sections[220].h

          XXY_INIT(strip, page, sstype_select)
          pt_cnt = #xxy[strip][page][sstype_select].points + 1
          xxy[strip][page][sstype_select].points[pt_cnt] = {x = x, y = y, ss = dragsnap.ss}

          XXY_Set(tracks[track_select].strip, page, sstype_select)
        end
        lupd.update_gfx = true
        dragsnap = nil
      end
    elseif xxymode == 1 then

      if mouse.context == nil and MOUSE_click(obj.sections[230]) then

        mouse.context = contexts.xxypath_posslider

      elseif mouse.context == nil and xxypath_edit and (MOUSE_click(obj.sections[220]) or MOUSE_click_RB(obj.sections[220])) then

        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then

          --add point
          local x = (mouse.mx - obj.sections[220].x)/obj.sections[220].w
          local y = (mouse.my - obj.sections[220].y)/obj.sections[220].h

          XXYPATH_addpoint(x,y)
          lupd.update_gfx = true

        elseif MOUSE_click(obj.sections[220]) then

          if xxypath[xxypath_select] then
            local fnd = false
            local fnd_p, fnd_sp
            for p = 1, #xxypath[xxypath_select].points do

              for sp = 1, #xxypath[xxypath_select].points[p].x do

                local xywh = {x = obj.sections[220].x + (xxypath[xxypath_select].points[p].x[sp] * obj.sections[220].w) - 5,
                              y = obj.sections[220].y + (xxypath[xxypath_select].points[p].y[sp] * obj.sections[220].h) - 5,
                              w = 10,
                              h = 10}
                if MOUSE_click(xywh) then
                  fnd = true
                  fnd_p = p
                  fnd_sp = sp
                  break
                end
              end

              if fnd then
                break
              end
            end
            if fnd then

              if fnd_sp == 2 or fnd_sp == 3 then

                mouse.context = contexts.xxypath_dragcontrolpt

                local hyp
                if fnd_sp == 2 then
                  if fnd_p > 1 then
                    hyp = math.sqrt((xxypath[xxypath_select].points[fnd_p-1].x[4]-xxypath[xxypath_select].points[fnd_p-1].x[3])^2 +
                                    (xxypath[xxypath_select].points[fnd_p-1].y[4]-xxypath[xxypath_select].points[fnd_p-1].y[3])^2)
                  end
                else
                  if fnd_p < #xxypath[xxypath_select].points-1 then
                    hyp = math.sqrt((xxypath[xxypath_select].points[fnd_p+1].x[2]-xxypath[xxypath_select].points[fnd_p+1].x[1])^2 +
                                    (xxypath[xxypath_select].points[fnd_p+1].y[2]-xxypath[xxypath_select].points[fnd_p+1].y[1])^2)
                  end
                end

                dragcontrolpt = {p = fnd_p, sp = fnd_sp, hyp = hyp}

              else

                mouse.context = contexts.xxypath_dragpt

                local dx2,dy2,dx3,dy3
                if fnd_sp == 1 and #xxypath[xxypath_select].points > 1 then
                  dx2 = xxypath[xxypath_select].points[fnd_p].x[2]-xxypath[xxypath_select].points[fnd_p].x[1]
                  dy2 = xxypath[xxypath_select].points[fnd_p].y[2]-xxypath[xxypath_select].points[fnd_p].y[1]
                  if fnd_p > 1 then
                    dx3 = xxypath[xxypath_select].points[fnd_p-1].x[4]-xxypath[xxypath_select].points[fnd_p-1].x[3]
                    dy3 = xxypath[xxypath_select].points[fnd_p-1].y[4]-xxypath[xxypath_select].points[fnd_p-1].y[3]
                  end
                elseif #xxypath[xxypath_select].points > 1 then
                  dx3 = xxypath[xxypath_select].points[fnd_p].x[4]-xxypath[xxypath_select].points[fnd_p].x[3]
                  dy3 = xxypath[xxypath_select].points[fnd_p].y[4]-xxypath[xxypath_select].points[fnd_p].y[3]
                  if fnd_p < #xxypath[xxypath_select].points-1 then
                    dx2 = xxypath[xxypath_select].points[fnd_p+1].x[2]-xxypath[xxypath_select].points[fnd_p+1].x[1]
                    dy2 = xxypath[xxypath_select].points[fnd_p+1].y[2]-xxypath[xxypath_select].points[fnd_p+1].y[1]
                  end
                end

                dragpt = {p = fnd_p, sp = fnd_sp, dx2 = dx2, dy2 = dy2, dx3 = dx3, dy3 = dy3}

              end

            end
          end

        end

      elseif mouse.context == nil and (MOUSE_click(obj.sections[221]) or MOUSE_click_RB(obj.sections[221])) then
        local mx,my = mouse.mx,mouse.my
        mouse.mx = mouse.mx-obj.sections[221].x
        mouse.my = mouse.my-obj.sections[221].y

        if MOUSE_click(obj.sections[227]) then

          xxypath_edit = not xxypath_edit
          lupd.update_xxy = true
          lupd.update_snaps = true

        elseif MOUSE_click(obj.sections[228]) then

          if xxypath and xxypath[xxypath_select] then
            OpenEB(18,'Please enter a filename for the path:')
          end

        elseif MOUSE_click(obj.sections[229]) then

          LoadPath()

        elseif MOUSE_click(obj.sections[231]) then

          if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
            local f = {targettype = 1,
                       strip = tracks[track_select].strip,
                       page = page,
                       sstype = sstype_select}

            mouse.mx, mouse.my = mx, my
            local fad = SetAutomationFader(f, xxy[tracks[track_select].strip][page][sstype_select].pathfader, true)
            if fad == -2 then
              DeleteFader(xxy[tracks[track_select].strip][page][sstype_select].pathfader)
              lupd.update_gfx = true
            elseif fad ~= -1 then
              --if xxy[tracks[track_select].strip][page][sstype_select].pathfader and xxy[tracks[track_select].strip][page][sstype_select].pathfader ~= fad then
              --  faders[xxy[tracks[track_select].strip][page][sstype_select].pathfader] = {}
              --end
              --xxy[tracks[track_select].strip][page][sstype_select].pathfader = fad
              AssignFader(fad,f)
              lupd.update_gfx = true
            end
          end

        end
        mouse.mx, mouse.my = mx, my

      end

      if mouse.context and mouse.context == contexts.xxypath_dragcontrolpt then
        local x = (mouse.mx - obj.sections[220].x) / obj.sections[220].w
        local y = (mouse.my - obj.sections[220].y) / obj.sections[220].h
        XXYPATH_movectlpt(dragcontrolpt,x,y)
        lupd.update_gfx = true

      elseif mouse.context and mouse.context == contexts.xxypath_dragpt then
        local x = (mouse.mx - obj.sections[220].x) / obj.sections[220].w
        local y = (mouse.my - obj.sections[220].y) / obj.sections[220].h
        XXYPATH_movept(dragpt,x,y)
        lupd.update_gfx = true

      elseif mouse.context and mouse.context == contexts.xxypath_posslider then

        local pos = F_limit((mouse.mx-obj.sections[230].x)/obj.sections[230].w,0,1)
        if pos ~= oxxysliderpos then
          oxxysliderpos = pos
          XXYPath_SetPos(tracks[track_select].strip,page,sstype_select,pos)
          lupd.update_xxypos = true
        end

      elseif mouse.context == nil and dragpt ~= nil or dragcontrolpt ~= nil then

        dragpt = nil
        dragcontrolpt = nil
        xxypath[xxypath_select].pathlen = XXYPath_CalcPathLen(xxypath_select)

      end

    end
  end

  function A_Run_SnapshotsLearn()

    if show_fsnapshots or show_xysnapshots then
      show_fsnapshots = false
      show_xysnapshots = false
      lupd.update_surface = true
      RedrawGUIBitmap()      
    end

    if sstype_select > 1 then
      if mouse.context == nil and (MOUSE_click(obj.sections[10])) then -- or MOUSE_click_RB(obj.sections[10])) then
        if mouse.mx > obj.sections[10].x then
          if strips and tracks[track_select] and strips[tracks[track_select].strip] then
            for i = 1, #strips[tracks[track_select].strip][page].controls do

              local ctl = strips[tracks[track_select].strip][page].controls[i]

              ctlxywh = {x = ctl.xsc*lvar.zoom - surface_offset.x*lvar.zoom +obj.sections[10].x,
                         y = ctl.ysc*lvar.zoom - surface_offset.y*lvar.zoom +obj.sections[10].y,
                         w = ctl.wsc*lvar.zoom,
                         h = ctl.hsc*lvar.zoom}
              if strips[tracks[track_select].strip][page].controls[i].fxfound then
                if MOUSE_click(ctlxywh) then

                  if Switcher_CtlsHidden(ctl.switcher, ctl.grpid) == false then

                    if ctl.ctlcat == ctlcats.fxparam or
                       ctl.ctlcat == ctlcats.trackparam or
                       ctl.ctlcat == ctlcats.tracksend or
                       ctl.ctlcat == ctlcats.fxoffline or
                       ctl.ctlcat == ctlcats.fxmulti or
                       ctl.ctlcat == ctlcats.midictl or
                       ctl.ctlcat == ctlcats.takeswitcher or
                       ctl.ctlcat == ctlcats.macro or
                       ctl.ctlcat == ctlcats.rs5k or 
                       ctl.ctlcat == ctlcats.switcher_pagesel then
                      local strip = tracks[track_select].strip
                      --Add / Remove
                      local ctlidx = GetSnapshotCtlIdx(strip, page, sstype_select, i)
                      if ctlidx then
                        --already added - remove?
                        if snapshots[strip][page][sstype_select].ctls[ctlidx].delete then
                          snapshots[strip][page][sstype_select].ctls[ctlidx].delete = not snapshots[strip][page][sstype_select].ctls[ctlidx].delete
                        else
                          snapshots[strip][page][sstype_select].ctls[ctlidx].delete = true
                        end
                      else
                        --add
                        local ctlidx = #snapshots[strip][page][sstype_select].ctls + 1
                        snapshots[strip][page][sstype_select].ctls[ctlidx] = {c_id = strips[strip][page].controls[i].c_id,
                                                                              ctl = i,
                                                                              id = GenID(),
                                                                              stage = 1,
                                                                              morph = true,
                                                                              mem = false}
                      end

                    elseif ctl.ctlcat == ctlcats.switcher then

                      switcher_select = i
                      SwitcherMenu_LB()

                    end
                  end
                end
              end
            end
          end
        end
      elseif mouse.context == nil and (MOUSE_click_RB(obj.sections[10])) then
        mouse.context = contexts.draglasso
        lasso = {l = mouse.mx, t = mouse.my, r = mouse.mx+5, b = mouse.my+5}
      elseif lasso ~= nil then
        --Dropped
        Lasso_Select(false)
        if ctl_select ~= nil then

          local strip = tracks[track_select].strip

          for c = 1, #ctl_select do
            local i = ctl_select[c].ctl

            if strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxparam or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.trackparam or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.tracksend or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxoffline or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.fxmulti or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.midictl or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.takeswitcher or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.macro or
               strips[tracks[track_select].strip][page].controls[i].ctlcat == ctlcats.rs5k then
              --Add / Remove
              local ctlidx = GetSnapshotCtlIdx(strip, page, sstype_select, i)
              if ctlidx then
                --re-add deleted
                if snapshots[strip][page][sstype_select].ctls[ctlidx].delete then
                  snapshots[strip][page][sstype_select].ctls[ctlidx].delete = false
                  strips[tracks[track_select].strip][page].controls[i].dirty = true
                end
              else
                --add
                local ctlidx = #snapshots[strip][page][sstype_select].ctls + 1
                snapshots[strip][page][sstype_select].ctls[ctlidx] = {c_id = strips[tracks[track_select].strip][page].controls[i].c_id,
                                                                      ctl = i,
                                                                      id = GenID(),
                                                                      stage = 1,
                                                                      morph = true,
                                                                      mem = false}
                strips[tracks[track_select].strip][page].controls[i].dirty = true
              end
            end

          end
        end

        lasso = nil
        ctl_select = nil
        lupd.update_ctls = true
        lupd.update_surface = true

      end
    end

  end

  function A_Run_SnapshotsWin(rt)

    local contexts = contexts
    local mouse = mouse

    if show_fsnapshots or show_xysnapshots then
      show_fsnapshots = false
      show_xysnapshots = false
      lupd.update_surface = true
      RedrawGUIBitmap()      
    end

    xywh = {x = obj.sections[160].x,
            y = obj.sections[160].y,
            w = obj.sections[160].w,
            h = butt_h*pnl_scale}
    --[[xywh2 = {x = obj.sections[160].x+obj.sections[1160].x,
                y = obj.sections[160].y+obj.sections[1160].y,
                w = obj.sections[160].w,
                h = butt_h}]]
    xywh2 = {x = obj.sections[160].x+obj.sections[1160].x,
                y = obj.sections[160].y+obj.sections[1160].y,
                w = obj.sections[1160].w,
                h = obj.sections[1160].h}
    xywh3 = {x = obj.sections[160].x+obj.sections[1161].x,
                y = obj.sections[160].y+obj.sections[1161].y,
                w = obj.sections[1161].w,
                h = obj.sections[1161].h}

    if mouse.context == nil and MOUSE_click(xywh2) then
      settings_ssdock = not settings_ssdock
      if settings_ssdock == true then
        osnaph = snaph
      elseif osnaph then
        snaph = math.max(math.min(osnaph,obj.sections[10].h,lvar.maxdim),252*pnl_scale)
        obj.sections[160].h = snaph
        resize_display = true
      else
        snaph = math.max(obj.sections[10].h,252*pnl_scale)
        obj.sections[160].h = snaph
        resize_display = true
      end
      obj = GetObjects()
      lupd.update_gfx = true

      return

    elseif mouse.context == nil and MOUSE_click(xywh3) then
      if sstype_select > 1 then
        snap_edit_mode = true
        lvar.snapedit = {snapedit_poffs = 0,
                         snapedit_ss = ss_select,
                         monitor = false,
                         SToffs = 0}
        local strip = tracks[track_select].strip
        if snapshots[strip][page][sstype_select].sorted ~= true then
          CleanSortSS(strip,page,sstype_select)
        end
        lupd.update_gfx = true
        RedrawGUIBitmap()
      end

    elseif mouse.context == nil and MOUSE_click(xywh) and settings_ssdock ~= true then
      mouse.context = contexts.movesnapwindow
      movesnapwin = {offx = mouse.mx - obj.sections[160].x,
                     offy = mouse.my - obj.sections[160].y}
    end

    local snapmx, snapmy = mouse.mx, mouse.my
    mouse.mx = mouse.mx - obj.sections[160].x
    mouse.my = mouse.my - obj.sections[160].y

    if snaplrn_mode == false then

      if mouse.context == nil and MOUSE_click(obj.sections[168]) and mouse.shift == false then
        --lupd.update_gfx = true
        knob_select = def_snapshotctl
        if ctl_files[knob_select].imageidx ~= nil then
          local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
          local h = ctl_files[knob_select].cellh
          if w == 0 or h == 0 then
            ksel_size = {w = 50, h = 50}
          else
            ksel_size = {w = (w*lvar.zoom)/2, h = h*lvar.zoom/2}
          end
        else
          ksel_size = {w = 50, h = 50}
        end
        mouse.context = contexts.addsnapctl

      elseif mouse.context == nil and MOUSE_click(obj.sections[1010]) then

        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          if snapshots[tracks[track_select].strip][page][sstype_select].morph_sync == false then
            if snapshots[tracks[track_select].strip][page][sstype_select].morph_time == nil then
              snapshots[tracks[track_select].strip][page][sstype_select].morph_time = 0
            end
            mouse.context = contexts.morph_time
            dragmorphtime = snapshots[tracks[track_select].strip][page][sstype_select].morph_time
            oms = mouse.shift
            mouse.slideoff = obj.sections[1010].y+obj.sections[1010].h/2 - mouse.my
          else
            snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv = math.min(snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv + 1,#lvar.sync_table)
            lupd.update_snaps = true
          end
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[1010]) and mouse.ctrl == false then

        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          if snapshots[tracks[track_select].strip][page][sstype_select].morph_sync == false then
            if mouse.shift == true then
              snapshots[tracks[track_select].strip][page][sstype_select].morph_time = 0
              lupd.update_snaps = true
            else
              OpenEB(1010,'Enter no. of bars:','')
            end
          else
            snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv = math.max(snapshots[tracks[track_select].strip][page][sstype_select].morph_syncv - 1,1)
            lupd.update_snaps = true
          end
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[1010]) and mouse.ctrl == true then

        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          local snap = snapshots[tracks[track_select].strip][page][sstype_select]
          local res, lastp = FaderMenu_2(snap.morph_time_fader,mouse.mx+obj.sections[160].x,mouse.my+obj.sections[160].y)
          if res > 0 then
            if res == lastp then
              DeleteFader(snap.morph_time_fader)
            else
              local f = {targettype = 8,
                         strip = tracks[track_select].strip,
                         page = page,
                         sstype = sstype_select}
              AssignFader(res, f)
            end

          end
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[1011]) then

        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          snapshots[tracks[track_select].strip][page][sstype_select].morph_sync = not snapshots[tracks[track_select].strip][page][sstype_select].morph_sync
          lupd.update_snaps = true
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[1012]) then

        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          snapshots[tracks[track_select].strip][page][sstype_select].morph_scale = nz(snapshots[tracks[track_select].strip][page][sstype_select].morph_scale,1) + 1
          if snapshots[tracks[track_select].strip][page][sstype_select].morph_scale > #lvar.macroscale_table then
            snapshots[tracks[track_select].strip][page][sstype_select].morph_scale = 1
          end
          if #morph_data > 0 then
            for i = 1, #morph_data do
              if morph_data[i].strip == tracks[track_select].strip and
                 morph_data[i].page == page and
                 morph_data[i].sstype == sstype_select then
                morph_data[i].morph_scale = snapshots[tracks[track_select].strip][page][sstype_select].morph_scale
                break
              end
            end
          end

          lupd.update_snaps = true
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[1013]) then

        for i = 1, #morph_data do
          if morph_data[i].strip == tracks[track_select].strip and
             morph_data[i].page == page and
             morph_data[i].sstype == sstype_select then
            if not morph_data[i].paused then
              morph_data[i].paused = morph_data[i].end_time-reaper.time_precise()
            else
              morph_data[i].end_time = reaper.time_precise() + morph_data[i].paused
              morph_data[i].start_time = morph_data[i].end_time - morph_data[i].morph_time
              morph_data[i].paused = nil
            end
            lupd.update_snaps = true
            break
          end
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[1014]) then

        for i = 1, #morph_data do
          if morph_data[i].strip == tracks[track_select].strip and
             morph_data[i].page == page and
             morph_data[i].sstype == sstype_select then
            local dir = nz(morph_data[i].dir, 0)
            morph_data[i].dir = 1-dir
            morph_data[i].origst = morph_data[i].start_time
            local t = reaper.time_precise()
            if morph_data[i].dir ~= 1 then
              if morph_data[i].paused then
                morph_data[i].paused = morph_data[i].morph_time - morph_data[i].paused
              else
                morph_data[i].start_time = t - (morph_data[i].morph_time*morph_data[i].p)
                morph_data[i].end_time = morph_data[i].start_time + morph_data[i].morph_time
              end
            else
              if morph_data[i].paused then
                morph_data[i].paused = morph_data[i].morph_time - morph_data[i].paused
              else
                morph_data[i].start_time = t - (morph_data[i].morph_time*(1-morph_data[i].p))
                morph_data[i].end_time = morph_data[i].start_time + morph_data[i].morph_time
              end
            end
            lupd.update_snaps = true
            break
          end
        end

        --[[for i = 1, #morph_data do
          if morph_data[i].strip == tracks[track_select].strip and
             morph_data[i].page == page and
             morph_data[i].sstype == sstype_select and
             morph_data[i].paused then
            morph_data[i].end_time = reaper.time_precise() + morph_data[i].paused
            morph_data[i].start_time = morph_data[i].end_time - morph_data[i].morph_time
            morph_data[i].paused = nil
            break
          end
        end
        ]]

      elseif mouse.context == nil and MOUSE_click(obj.sections[1015]) then

        local snaps
        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          snaps = snapshots[tracks[track_select].strip][page][sstype_select]
        end

        if snaps then
          local nl = (snaps.morph_loop or 1) + 1
          if (snaps.stages or 1) > 1 and nl == 3 then
            nl = 4
          end
          if nl > 5 then
            nl = 2
          end
          snaps.morph_loop = nl
          if #morph_data > 0 then
            for i = 1, #morph_data do
              if morph_data[i].strip == tracks[track_select].strip and
                 morph_data[i].page == page and
                 morph_data[i].sstype == sstype_select then
                morph_data[i].morph_loop = nl
                break
              end
            end
          end
          lupd.update_snaps = true
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[1015]) then

        local snaps
        if snapshots[tracks[track_select].strip] and snapshots[tracks[track_select].strip][page][sstype_select] then
          snaps = snapshots[tracks[track_select].strip][page][sstype_select]
        end

        if snaps then
          nl = 1
          snaps.morph_loop = nl
          if #morph_data > 0 then
            for i = 1, #morph_data do
              if morph_data[i].strip == tracks[track_select].strip and
                 morph_data[i].page == page and
                 morph_data[i].sstype == sstype_select then
                morph_data[i].morph_loop = nl
                break
              end
            end
          end
          lupd.update_snaps = true
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[1012]) then

        snapshots[tracks[track_select].strip][page][sstype_select].morph_scale = nz(snapshots[tracks[track_select].strip][page][sstype_select].morph_scale,1) - 1
        if snapshots[tracks[track_select].strip][page][sstype_select].morph_scale < 1 then
          snapshots[tracks[track_select].strip][page][sstype_select].morph_scale = #lvar.macroscale_table
        end
        if #morph_data > 0 then
          for i = 1, #morph_data do
            if morph_data[i].strip == tracks[track_select].strip and
               morph_data[i].page == page and
               morph_data[i].sstype == sstype_select then
              morph_data[i].morph_scale = snapshots[tracks[track_select].strip][page][sstype_select].morph_scale
              break
            end
          end
        end

        lupd.update_snaps = true

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[168]) and mouse.shift == false then

        RBMenu_Snapshot(snapmx, snapmy)

      elseif mouse.context == nil and MOUSE_click(obj.sections[168]) and mouse.shift == true then

        if sstype_select > 1 then
          knob_select = def_xyctl
          if ctl_files[knob_select].imageidx ~= nil then
            local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
            local h = ctl_files[knob_select].cellh
            if w == 0 or h == 0 then
              ksel_size = {w = 50, h = 50}
            else
             ksel_size = {w = w/2, h = h/2}
            end
          else
            ksel_size = {w = 50, h = 50}
          end
          mouse.context = contexts.addxyctl
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[165]) and settings_ssdock ~= true then
        mouse.context = contexts.resizesnapwindow
        resizesnapwin = {origh = obj.sections[160].h,
                         offy = mouse.my}

      elseif mouse.context == nil and MOUSE_click(obj.sections[161]) then

        if snapshots[tracks[track_select].strip] then
          sstype_select = F_limit(sstype_select + 1, 1, #snapshots[tracks[track_select].strip][page])
          if snapshots[tracks[track_select].strip][page][sstype_select] then
            ss_select = snapshots[tracks[track_select].strip][page][sstype_select].selected
          else
            ss_select = nil
          end
        else
          Snapshots_INIT()
          sstype_select = 1
          ss_select = nil
        end
        ssoffset = 0
        lupd.update_snaps = true

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[161]) then

        if snapshots[tracks[track_select].strip] then
          sstype_select = F_limit(sstype_select - 1, 1, #snapshots[tracks[track_select].strip][page])
          if snapshots[tracks[track_select].strip][page][sstype_select] then
            ss_select = snapshots[tracks[track_select].strip][page][sstype_select].selected
          else
            ss_select = nil
          end
        else
          Snapshots_INIT()
          sstype_select = 1
          ss_select = nil
        end
        ssoffset = 0
        lupd.update_snaps = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[1016]) then

        local ss
        if sstype_select == 1 then
          ss = snapshots[tracks[track_select].strip][page][sstype_select]
        else
          ss = snapshots[tracks[track_select].strip][page][sstype_select].snapshot
        end

        local msbh = obj.sections[1016].h
        local p1 = 1 / #ss
        local sbh = math.ceil(F_limit(p1*SS_butt_cnt * msbh,20,msbh))
        local p2 = p1*msbh
        local sby = math.floor(ssoffset * p2)

        sby = math.min(sby,msbh-sbh-1)

        if mouse.my >= obj.sections[1016].y + sby and mouse.my <= obj.sections[1016].y + sby+sbh then

          if SS_butt_cnt < #ss then
            mouse.context = contexts.scrollsswin
            scrollss = {y = mouse.my-obj.sections[1016].y, lo = ssoffset, ss = ss}
            lupd.update_snaps = true
          else
            ssoffset = 0
          end

        elseif mouse.my < obj.sections[1016].y + sby then

        elseif mouse.my > obj.sections[1016].y + sby+sbh then

        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[162]) then

        Snapshots_CREATE(tracks[track_select].strip, page, sstype_select)
        lupd.update_snaps = true
        lupd.update_ctls = true --to update snapshot ctls

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[162]) then

        RBMenu_Capture()

      elseif mouse.context == nil and MOUSE_click(obj.sections[169]) then
        if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
          local respectminmax = true
          if mouse.ctrl then respectminmax = false end
          Snapshot_RANDOMIZE(tracks[track_select].strip, page, sstype_select, respectminmax)
          lupd.update_ctls = true --to update snapshot ctls
        end

      elseif mouse.context == nil and MOUSE_click_RB(obj.sections[169]) then

        knob_select = def_boxctl
        if ctl_files[knob_select].imageidx ~= nil then
          local w,_ = gfx.getimgdim(ctl_files[knob_select].imageidx)
          local h = ctl_files[knob_select].cellh
          if w == 0 or h == 0 then
            ksel_size = {w = 50, h = 50}
          else
           ksel_size = {w = w/2, h = h/2}
          end
        else
          ksel_size = {w = 50, h = 50}
        end
        mouse.context = contexts.snapshot_rand

      elseif mouse.context == nil and MOUSE_click(obj.sections[224]) then
        if sstype_select > 1 then
          show_xxy = true
          if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then
            xxypath_select = xxy[tracks[track_select].strip][page][sstype_select].pathidx
          else
            xxypath_select = nil
          end
          lupd.update_gfx = true
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[166]) then
        if lvar.livemode ~= 2 then
          local strip = tracks[track_select].strip
          if strips[strip] and #strips[strip][page].controls > 0 then
            if snapshots[tracks[track_select].strip] then
              sstype_select = math.max(#snapshots[tracks[track_select].strip][page]+1,2)
            else
              Snapshots_INIT()
              sstype_select = 2
              ssoffset = 0
            end
            Snapshots_CREATE(tracks[track_select].strip, page, sstype_select)
            lupd.update_snaps = true
          end
        end
      elseif mouse.context == nil and MOUSE_click(obj.sections[167]) then
        if lvar.livemode ~= 2 then
          if sstype_select > 1 then
            local ok = true
            if morph_data and #morph_data > 0 then
              for i = 1, #morph_data do
                if morph_data[i].strip == tracks[track_select].strip and
                   morph_data[i].page == page and
                   morph_data[i].sstype == sstype_select and
                   morph_data[i].active then
                  ok = false
                end
              end
            end
            if ok then
              snaplrn_mode = true
              if lvar.livemode >= 1 then
                surface_offset.x = 0
                surface_offset.y = 0
                SetSurfaceSize2(obj)
                obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])
              end
              navigate = false
              lupd.update_bg = true
              lupd.update_gfx = true
            end
          end
        end
        
      elseif mouse.context == nil and MOUSE_click(obj.sections[164]) then

        if sstype_select > 1 then
          OpenEB(15,'Please enter new subset name:')
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[163]) then
        if snapshots and snapshots[tracks[track_select].strip] then
          local i = math.floor((mouse.my-obj.sections[163].y)/(butt_h*pnl_scale))

          if i == 0 then
            local ix = math.floor((mouse.mx-obj.sections[163].x)/(obj.sections[160].w/2))
            if ix == 0 then
              ssoffset = ssoffset-SS_butt_cnt
              if ssoffset < 0 then ssoffset = 0 end
            else
              if sstype_select == 1 then
                ssoffset = F_limit(ssoffset+SS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][sstype_select]-SS_butt_cnt))
              elseif sstype_select > 1 then
                ssoffset = F_limit(ssoffset+SS_butt_cnt,0,math.max(0,#snapshots[tracks[track_select].strip][page][sstype_select].snapshot-SS_butt_cnt))
              end
            end
            lupd.update_ctls = true
            lupd.update_snaps = true
          elseif i > 0 then
            if snapshots and snapshots[tracks[track_select].strip] then
              local maxss
              if sstype_select == 1 then
                maxss = #snapshots[tracks[track_select].strip][page][sstype_select]
                --ss_select = F_limit(ssoffset+i,1,#snapshots[tracks[track_select].strip][page][sstype_select])
              else
                maxss = #snapshots[tracks[track_select].strip][page][sstype_select].snapshot
                --ss_select = F_limit(ssoffset+i,1,#snapshots[tracks[track_select].strip][page][sstype_select].snapshot)
              end
              if ssoffset+i <= maxss then
              --if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.20 then
                ss_select = ssoffset+i

                if not mouse.shift then
                  --DBG()
                  --DBG()

                  Snapshot_Set(tracks[track_select].strip, page, sstype_select, ss_select)
                end
              --end
                lupd.update_ctls = true --to update snapshot ctls
                lupd.update_snaps = true

                if mouse.shift then
                  --Start Moving
                  snap_move = {}
                  snap_move.spos = ssoffset+i
                  snap_move.epos = snap_move.spos
                  mouse.context = contexts.snap_move
                  ssshiftto = reaper.time_precise()
                end
              end
            end
          end
        end
      --elseif mouse.context == nil and MOUSE_click(obj.sections[163]) and mouse.shift then

      elseif MOUSE_click_RB(obj.sections[163]) then
        if ss_select then
          local st = ''
          if settings_followsnapshot then
            st = '!'
          end
          local sp = ''
          if settings_savesnapafterselected then
            sp = '!'
          end
          mstr = 'Rename||Delete||Delete All|Delete All Except Selected||Capture (Overwrite)||'..sp..'Save Snapshot After Selected||'..st..'Follow Selected||Render All Snapshots (use last render settings)|Render Single Snapshot'
          gfx.x, gfx.y = snapmx, snapmy
          res = OpenMenu(mstr)
          if res ~= 0 then
            if res == 1 then
              --EditSSName(11)
              OpenEB(11,'Please enter new snapshot name:')
            elseif res == 2 then
              morph_data = {}
              snapstage_data = {}
              DeleteSS()
              lupd.update_snaps = true
            elseif res == 3 then
              morph_data = {}
              snapstage_data = {}
              DeleteSnaps()
              lupd.update_snaps = true
            elseif res == 4 then
              morph_data = {}
              snapstage_data = {}
              DeleteSnaps(1)
              lupd.update_snaps = true
            elseif res == 5 then
              Snapshots_CREATE(tracks[track_select].strip, page, sstype_select, ss_select)
            elseif res == 6 then
              settings_savesnapafterselected = not settings_savesnapafterselected
            elseif res == 7 then
              settings_followsnapshot = not settings_followsnapshot
            elseif res == 8 then
              RenderSnaps2()
            elseif res == 9 then
              RenderSnap(ss_select)
            end
          end
        else
          local st = ''
          if settings_followsnapshot then
            st = '!'
          end
          local sp = ''
          if settings_savesnapafterselected then
            sp = '!'
          end
          mstr = sp..'Save Snapshot After Selected||'..st..'Follow Selected'
          gfx.x, gfx.y = snapmx, snapmy
          res = OpenMenu(mstr)
          if res ~= 0 then
            if res == 2 then
              settings_followsnapshot = not settings_followsnapshot
            elseif res == 1 then
              settings_savesnapafterselected = not settings_savesnapafterselected
            end
          end
        end
      end
    elseif mouse.context == nil and MOUSE_click(obj.sections[167]) then

      snaplrn_mode = false

      SetSurfaceSize2(obj)
      obj = DockableWindows(obj, obj.sections[160], obj.sections[1350])

      Snap_RemoveDeletedSS(tracks[track_select].strip,page,sstype_select)
      CleanSortSS(tracks[track_select].strip, page, sstype_select)
      CheckRandom(tracks[track_select].strip, page, sstype_select)
      navigate = true

      lupd.update_gfx = true

    end

    mouse.mx = snapmx
    mouse.my = snapmy

  end

  function RenderSnaps()

    if reaper.JS_Dialog_BrowseForFolder and reaper.GetSetProjectInfo_String then
      local retval, fol = reaper.JS_Dialog_BrowseForFolder('Select folder', lvar.lastrenderfolder or '')

      if retval == 1 and fol then
        lvar.lastrenderfolder = fol
        local strip = tracks[track_select].strip
        local snapcnt
        local snaps
        if sstype_select == 1 then
          snaps = snapshots[strip][page][sstype_select]
        else
          snaps = snapshots[strip][page][sstype_select].snapshot
        end

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_FILE', fol, true)
        snapcnt = #snaps

        --local rendercancelled
        --reaper.SetExtState(SCRIPT, 'cancelrender', '0', false)

        for ss = 1, snapcnt do
          --DBG('Rendering: '..(snaps[ss].name or ss))
          Progress('Rendering: '..(snaps[ss].name or ss),ss/snapcnt)
          Snapshot_Set(strip, page, sstype_select, ss, true)

          local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_PATTERN', string.format('%03d',ss)..'_'..snaps[ss].name, true)
          reaper.Main_OnCommand(42230, 0)

          --if reaper.GetExtState(SCRIPT, 'cancelrender') == '1' then
          --  rendercancelled = true
          --  break
          --end
        end
        --if not rendercancelled then
          Progress('Rendering Complete',1)
        --else
        --  Progress('Rendering Cancelled',1)
        --end
        --DBG('*** Done ***')
      end
    end
  end

  function RenderSnaps2()

    if reaper.JS_Dialog_BrowseForFolder and reaper.GetSetProjectInfo_String then
      local retval, fol = reaper.JS_Dialog_BrowseForFolder('Select folder', lvar.lastrenderfolder or '')

      if retval == 1 and fol then
        lvar.lastrenderfolder = fol
        local strip = tracks[track_select].strip
        local snapcnt
        local snaps
        if sstype_select == 1 then
          snaps = snapshots[strip][page][sstype_select]
        else
          snaps = snapshots[strip][page][sstype_select].snapshot
        end

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_FILE', fol, true)
        snapcnt = #snaps

        local rendercancelled
        reaper.SetExtState(lvar.SCRIPT, 'cancelrender', '0', false)

        lvar.rendersnaps = {}
        lvar.rendersnaps.ss = 1
        lvar.rendersnaps.snaps = snaps
        lvar.rendersnaps.snapcnt = snapcnt
        lvar.rendersnaps.timer = reaper.time_precise()
        lvar.rendersnaps.fol = fol

      end
    end
  end

  function RenderSnap2(ss, fol)

    --if reaper.JS_Dialog_BrowseForFolder and reaper.GetSetProjectInfo_String then
    --  local retval, fol = reaper.JS_Dialog_BrowseForFolder('Select folder', lvar.lastrenderfolder or '')

      if fol then
        lvar.lastrenderfolder = fol
        local strip = tracks[track_select].strip
        local snaps = lvar.rendersnaps.snaps
        local snapcnt = lvar.rendersnaps.snapcnt

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_FILE', fol, true)
          
        --DBG('Rendering: '..(snaps[ss].name or ss))
        Progress('Rendering: '..(snaps[ss].name or ss),ss/snapcnt)
        Snapshot_Set(strip, page, sstype_select, ss, true)

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_PATTERN', string.format('%03d',ss)..'_'..snaps[ss].name, true)
        reaper.Main_OnCommand(42230, 0)

        --Progress('Rendering Complete',1)
        --DBG('*** Done ***')
      end
    --end
  end

  function RenderSnap(ss)

    if reaper.JS_Dialog_BrowseForFolder and reaper.GetSetProjectInfo_String then
      local retval, fol = reaper.JS_Dialog_BrowseForFolder('Select folder', lvar.lastrenderfolder or '')

      if retval == 1 and fol then
        lvar.lastrenderfolder = fol
        local strip = tracks[track_select].strip
        local snaps
        if sstype_select == 1 then
          snaps = snapshots[strip][page][sstype_select]
        else
          snaps = snapshots[strip][page][sstype_select].snapshot
        end

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_FILE', fol, true)

        --DBG('Rendering: '..(snaps[ss].name or ss))
        Progress('Rendering: '..(snaps[ss].name or ss),1)
        Snapshot_Set(strip, page, sstype_select, ss, true)

        local retval, val = reaper.GetSetProjectInfo_String(0, 'RENDER_PATTERN', string.format('%03d',ss)..'_'..snaps[ss].name, true)
        reaper.Main_OnCommand(42230, 0)

        Progress('Rendering Complete',1)
        --DBG('*** Done ***')
      end
    end
  end

  function A_Run_MacroLearn()

    -- MACRO LEARN

    if MOUSE_click(obj.sections[250]) then

      navigate = true
      macro_lrn_mode = false

      show_lfoedit = oslfoeedit
      show_snapshots = ossnaps
      RedrawGUIBitmap()
      
      obj = GetObjects()
      Macro_UpdateCtls(tracks[track_select].strip, page, macroctl_select)

      lupd.update_surface = true

    elseif mouse.context == nil and (MOUSE_click(obj.sections[10])) then -- or MOUSE_click_RB(obj.sections[10])) then
      if mouse.mx > obj.sections[10].x then
        if strips and tracks[track_select] and strips[tracks[track_select].strip] then
          local i
          local c = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)
          if c then
            i = c
            local ctl = strips[tracks[track_select].strip][page].controls[i]
            ctlxywh = {x = ctl.xsc*lvar.zoom - surface_offset.x*lvar.zoom +obj.sections[10].x,
                       y = ctl.ysc*lvar.zoom - surface_offset.y*lvar.zoom +obj.sections[10].y,
                       w = ctl.wsc*lvar.zoom,
                       h = ctl.hsc*lvar.zoom}
          --end

          --if i then

            if ctl.fxfound then
              if MOUSE_click(ctlxywh) then

                if ctl.ctlcat == ctlcats.fxparam or
                   ctl.ctlcat == ctlcats.trackparam or
                   ctl.ctlcat == ctlcats.tracksend or
                   ctl.ctlcat == ctlcats.fxoffline or
                   ctl.ctlcat == ctlcats.midictl or
                   ctl.ctlcat == ctlcats.action or
                   ctl.ctlcat == ctlcats.statectl or
                   ctl.ctlcat == ctlcats.switcher_pagesel or
                   ctl.ctlcat == ctlcats.snapshotrand or
                   (ctl.ctlcat == ctlcats.macro and macroedittype_select == 1) then
                  local strip = tracks[track_select].strip

                  --Add / Remove
                  local ctlidx = GetMacroCtlIdx(strip, page, macroctl_select, i)
                  if ctlidx then
                    --already added - remove?
                    local mctl = strips[strip][page].controls[macroctl_select].macroctl[ctlidx]
                    if mctl.delete then
                      mctl.delete = not mctl.delete
                    else
                      mctl.delete = true
                    end

                  else
                    --add
                    if strips[strip][page].controls[macroctl_select].macroctl == nil then
                      strips[strip][page].controls[macroctl_select].macroctl = {}
                    end
                    local ctlidx = #strips[strip][page].controls[macroctl_select].macroctl + 1
                    strips[strip][page].controls[macroctl_select].macroctl[ctlidx] = {c_id = ctl.c_id,
                                                                                      ctl = i,
                                                                                      A_val = 0,
                                                                                      B_val = 1,
                                                                                      shape = 1,
                                                                                      bi = false}
                  end
                end
              end
            end
          end
        end
      end

    elseif mouse.context == nil and (MOUSE_click_RB(obj.sections[10])) then
      mouse.context = contexts.draglasso
      lasso = {l = mouse.mx, t = mouse.my, r = mouse.mx+5, b = mouse.my+5}

    --[[elseif mouse.context and mouse.context == contexts.draglasso then

      if math.abs(lasso.l - mouse.mx) > 10 or math.abs(lasso.t - mouse.my) > 10 then
        lasso.r = mouse.mx
        lasso.b = mouse.my

        Lasso_Select(false)
        lupd.update_surface = true
      end]]

    elseif lasso ~= nil then
      --Dropped

      Lasso_Select(false)
      if ctl_select ~= nil then

        local strip = tracks[track_select].strip

        for c = 1, #ctl_select do
          local i = ctl_select[c].ctl
          local ctl = strips[tracks[track_select].strip][page].controls[i]
          if ctl.ctlcat == ctlcats.fxparam or
                   ctl.ctlcat == ctlcats.trackparam or
                   ctl.ctlcat == ctlcats.tracksend or
                   ctl.ctlcat == ctlcats.fxoffline or
                   ctl.ctlcat == ctlcats.midictl or
                   ctl.ctlcat == ctlcats.action or
                   ctl.ctlcat == ctlcats.statectl or
                   ctl.ctlcat == ctlcats.switcher_pagesel or
                   ctl.ctlcat == ctlcats.snapshotrand or
                   (ctl.ctlcat == ctlcats.macro and macroedittype_select == 1) then
            --Add / Remove
            local ctlidx = GetMacroCtlIdx(strip, page, macroctl_select, i)
            if ctlidx then
              --re-add deleted
              local mctl = strips[strip][page].controls[macroctl_select].macroctl[ctlidx]
              if mctl.delete then
                mctl.delete = false
                ctl.dirty = true
              end
            else
              --add
              if strips[strip][page].controls[macroctl_select].macroctl == nil then
                strips[strip][page].controls[macroctl_select].macroctl = {}
              end
              local ctlidx = #strips[strip][page].controls[macroctl_select].macroctl + 1
              strips[strip][page].controls[macroctl_select].macroctl[ctlidx] = {c_id = ctl.c_id,
                                                                                ctl = i,
                                                                                A_val = 0,
                                                                                B_val = 1,
                                                                                shape = 1,
                                                                                bi = false}
              ctl.dirty = true
            end
          end

        end
      end

      lasso = nil
      ctl_select = nil
      lupd.update_ctls = true
      lupd.update_surface = true

    end
  end

  function A_Run_SnapEdit(noscroll, rt)

    navigate = false
    noscroll = true

    local xywh = {x = obj.sections[300].x+obj.sections[401].x,
                  y = obj.sections[300].y+obj.sections[401].y,
                  w = obj.sections[401].w,
                  h = obj.sections[401].h}
    if mouse.context == nil and MOUSE_click(xywh) then

      navigate = true
      snap_edit_mode = false

      CleanSortSS(tracks[track_select].strip,page,sstype_select)

      lupd.update_gfx = true
      RedrawGUIBitmap()

    else

      local mx, my = mouse.mx, mouse.my
      mouse.mx = mouse.mx - obj.sections[300].x
      mouse.my = mouse.my - obj.sections[300].y

      local snaps = snapshots[tracks[track_select].strip][page][sstype_select]
      local snapctl = snaps.snapshot[lvar.snapedit.snapedit_ss]
      local sctls = snaps.ctls

      if mouse.context == nil then

        if sctls and gfx.mouse_wheel ~= 0 and MOUSE_over(obj.sections[300],mx,my) then

          v = mousewheel_val()
          if mouse.ctrl then
            lvar.macrosech = F_limit(math.floor(lvar.macrosech + v*2),26,60)
            PopMacroEditSec(obj,lvar.macrosech)
          else
            if MOUSE_over(obj.sections[431],mx,my) then
              lvar.snapedit.SToffs = F_limit(lvar.snapedit.SToffs - v,0,math.floor(((snaps.stages or 1)-1)/10))
            else
              lvar.snapedit.snapedit_poffs = F_limit(lvar.snapedit.snapedit_poffs-v,0,#sctls-1)
            end
          end
          lupd.update_macrobutt = true
        end

        local xywh_423 = {x = obj.sections[423].x - (macroedit.sliderw*0.5),
                          y = obj.sections[423].y,
                          w = obj.sections[423].w + macroedit.sliderw,
                          h = obj.sections[423].h}

        if mouse.context == nil and MOUSE_click(xywh_423) then
          local yy = math.floor((mouse.my - obj.sections[423].y)/macroedit.sech)
          if snapctl.data[(yy+1)+lvar.snapedit.snapedit_poffs] then

            local val = snapctl.data[(yy+1)+lvar.snapedit.snapedit_poffs].val
            local xywh = {x = obj.sections[423].x + (val*obj.sections[423].w) -(macroedit.sliderw*0.5),
                          y = obj.sections[423].y + (yy*macroedit.sech) + (macroedit.sech*0.5) - (macroedit.sliderh*0.5),
                          w = macroedit.sliderw,
                          h = macroedit.sliderh}
            if MOUSE_over(xywh) then
              mouse.context = contexts.snapslider
              snapslide = {xoff = mouse.mx-(xywh.x+(xywh.w*0.5)), snapparamidx = (yy+1)+lvar.snapedit.snapedit_poffs}
            end

          end

        elseif MOUSE_click(obj.sections[428]) then
          if mouse.ctrl then
            local val = not (sctls[1].morph or false)
            for i = 1, #sctls do
              sctls[i].morph = val
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click_RB(obj.sections[428]) then
          if mouse.ctrl then
            for i = 1, #sctls do
              sctls[i].morph = false
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click(obj.sections[427]) then
          if mouse.ctrl then
            for i = 1, #sctls do
              sctls[i].stage = 1
            end
            lupd.update_macrobutt = true
          else
            CleanSortSS(tracks[track_select].strip,page,sstype_select)
            lupd.update_macrobutt = true
          end

        elseif MOUSE_click(obj.sections[429]) then

          local snaptype = snapshots[tracks[track_select].strip][page][sstype_select]
          snaptype.stages = math.min(snaptype.stages+1, lvar.snapstages)
          lvar.snapedit.SToffs = F_limit(lvar.snapedit.SToffs,0,math.floor((snaptype.stages-1)/10))
          lupd.update_macrobutt = true

        elseif MOUSE_click(obj.sections[432]) then

          local snaptype = snapshots[tracks[track_select].strip][page][sstype_select]
          snaptype.mult = not snaptype.mult
          if snaptype.mult == true then
            for i = 1, #snaps.deltype do
              if snaps.deltype[i] == 2 then
                snaps.deltype[i] = 1
              end
            end
          end
          lupd.update_macrobutt = true

        elseif MOUSE_click_RB(obj.sections[429]) then

          local snaptype = snapshots[tracks[track_select].strip][page][sstype_select]
          snaptype.stages = math.max(snaptype.stages-1, 1)
          lvar.snapedit.SToffs = F_limit(lvar.snapedit.SToffs,0,math.floor((snaptype.stages-1)/10))
          lupd.update_macrobutt = true

        elseif MOUSE_click(obj.sections[433]) then

          SnapEditSSMenu(mx,my)

        elseif MOUSE_click(obj.sections[425]) then

          local strip = tracks[track_select].strip
          lvar.snapedit.snapedit_ss = math.min((lvar.snapedit.snapedit_ss or 1)+ 1,#snapshots[strip][page][sstype_select].snapshot)
          if lvar.snapedit.monitor == true then
            local strip = tracks[track_select].strip
            Snapshot_Set(strip,page,sstype_select,lvar.snapedit.snapedit_ss, true)
          end
          lupd.update_macrobutt = true

        elseif MOUSE_click_RB(obj.sections[425]) then

          local strip = tracks[track_select].strip
          lvar.snapedit.snapedit_ss = math.max((lvar.snapedit.snapedit_ss or 1) - 1,1)
          if lvar.snapedit.monitor == true then
            local strip = tracks[track_select].strip
            Snapshot_Set(strip,page,sstype_select,lvar.snapedit.snapedit_ss, true)
          end
          lupd.update_macrobutt = true

        elseif MOUSE_click(obj.sections[426]) then

          lvar.snapedit.monitor = not lvar.snapedit.monitor
          if lvar.snapedit.monitor == true then
            local strip = tracks[track_select].strip
            Snapshot_Set(strip,page,sstype_select,lvar.snapedit.snapedit_ss, true)
          end
          lupd.update_macrobutt = true

        elseif MOUSE_click(obj.sections[435]) then
          local yy = math.floor((mouse.my - obj.sections[435].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            if mouse.ctrl then
              local stage = sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage
              local val = not (sctls[(yy+1)+lvar.snapedit.snapedit_poffs].mem or false)
              for i = 1, #sctls do
                if sctls[i].stage == stage then
                  sctls[i].mem = val
                end
              end
            else
              sctls[(yy+1)+lvar.snapedit.snapedit_poffs].mem = not sctls[(yy+1)+lvar.snapedit.snapedit_poffs].mem
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click(obj.sections[422]) then
          local yy = math.floor((mouse.my - obj.sections[422].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            if mouse.ctrl then
              local stage = sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage
              local val = not (sctls[(yy+1)+lvar.snapedit.snapedit_poffs].morph or false)
              for i = 1, #sctls do
                if sctls[i].stage == stage then
                  sctls[i].morph = val
                end
              end
            else
              sctls[(yy+1)+lvar.snapedit.snapedit_poffs].morph = not sctls[(yy+1)+lvar.snapedit.snapedit_poffs].morph
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click(obj.sections[421]) then
          local yy = math.floor((mouse.my - obj.sections[421].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            local stages = snapshots[tracks[track_select].strip][page][sstype_select].stages
            sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage = F_limit(sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage+1,1,stages)
            --lupd.update_macroedit = true
            lupd.update_macrobutt = true
          end

        elseif MOUSE_click_RB(obj.sections[421]) then
          local yy = math.floor((mouse.my - obj.sections[421].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            local stages = snapshots[tracks[track_select].strip][page][sstype_select].stages
            sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage = F_limit(sctls[(yy+1)+lvar.snapedit.snapedit_poffs].stage-1,1,stages)
            --lupd.update_macroedit = true
            lupd.update_macrobutt = true
          end

        elseif MOUSE_click(obj.sections[431]) then
          local xx = math.floor((mouse.mx - obj.sections[431].x)/(obj.sections[431].w/5))
          local yy = math.floor((mouse.my - obj.sections[431].y)/(obj.sections[431].h/2))
          local idx = (lvar.snapedit.SToffs*10) + xx+(yy*5)+1
          local snaptype = snapshots[tracks[track_select].strip][page][sstype_select]
          if idx <= snaptype.stages then
            if mouse.ctrl then
              snaptype.deltype[idx] = 1-snaptype.deltype[idx]
            elseif mouse.alt then
              if snaptype.mult == false then
                snaptype.deltype[idx] = 2
              end
            elseif snaptype.deltype[idx] == 0 then
              snaptype.delay[idx] = round(math.min(snaptype.delay[idx] + 0.1,2),1)
            elseif snaptype.deltype[idx] == 1 then
              snaptype.mtime[idx] = math.min(snaptype.mtime[idx] + 1,#lvar.sync_table)
            elseif snaptype.deltype[idx] == 2 then
              snaptype.deltype[idx] = 1
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click_RB(obj.sections[431]) then
          local xx = math.floor((mouse.mx - obj.sections[431].x)/(obj.sections[431].w/5))
          local yy = math.floor((mouse.my - obj.sections[431].y)/(obj.sections[431].h/2))
          local idx = (lvar.snapedit.SToffs*10) + xx+(yy*5)+1
          local snaptype = snapshots[tracks[track_select].strip][page][sstype_select]
          if idx <= snaptype.stages then
            if snaptype.deltype[idx] == 0 then
              snaptype.delay[idx] = round(math.max(snaptype.delay[idx] - 0.1,0),1)
            elseif snaptype.deltype[idx] == 1 then
              snaptype.mtime[idx] = math.max(snaptype.mtime[idx] - 1,1)
            end
            lupd.update_macroedit = true
          end

        elseif MOUSE_click(obj.sections[420]) then
          local yy = math.floor((mouse.my - obj.sections[420].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            lvar.snapedit.selected = yy+1+lvar.snapedit.snapedit_poffs
            mouse.context = contexts.snapparamdrag
            local iidx = 980
            --local rt = reaper.time_precise()
            snapparamdrag = {iidx = 980, p = lvar.snapedit.selected, yy = yy, xoff = mouse.mx - obj.sections[420].x, yoff = mouse.my - obj.sections[420].y - (yy*macroedit.sech)}

            Img_SetDim(iidx,obj.sections[420].w+4,macroedit.sech, true)
            gfx.dest = iidx
            gfx.blit(1008,1,0,obj.sections[420].x-2,obj.sections[420].y+yy*macroedit.sech,obj.sections[420].w+4,macroedit.sech,0,0)
            f_Get_SSV(gui.color.yellow)
            gfx.rect(2,
                     2,
                     obj.sections[420].w,
                     macroedit.sech-4, 0)
            lupd.update_macrobutt = true

          end
        elseif snapparamdrag then

          local yy = math.floor((mouse.my - obj.sections[420].y)/macroedit.sech)
          local np = F_limit((yy+1)+lvar.snapedit.snapedit_poffs,1,#snaps.ctls)
          if np ~= p then
            local id = snaps.ctls[snapparamdrag.p].id or snaps.ctls[snapparamdrag.p].c_id
            snaps.ctls = Table_Move(snaps.ctls,snapparamdrag.p,np)
            CleanSortSS(tracks[track_select].strip,page,sstype_select)
            for i = 1, #snaps.ctls do
              if snaps.ctls[i].id == id or snaps.ctls[i].c_id == id then
                lvar.snapedit.selected = i
                break
              end
            end
          end

          snapparamdrag = nil
          lupd.update_macrobutt = true

        elseif MOUSE_click_RB(obj.sections[420]) then
          local yy = math.floor((mouse.my - obj.sections[420].y)/macroedit.sech)
          if sctls[(yy+1)+lvar.snapedit.snapedit_poffs] then
            lvar.snapedit.selected = yy+1+lvar.snapedit.snapedit_poffs
            lupd.update_macrobutt = true
            lupd = GUI_draw(obj, gui)
            gfx.update()
            SnapEditParamMenu(mx,my)
          end
        end

      else

        if mouse.context == contexts.snapslider then

          local strip = tracks[track_select].strip
          local v = F_limit((mouse.mx - snapslide.xoff - obj.sections[423].x)/obj.sections[423].w,0,1)
          if v ~= snapctl.data[snapslide.snapparamidx].val then
            snapctl.data[snapslide.snapparamidx].val = v

            local c = snapctl.data[snapslide.snapparamidx].ctl
            local ctl = strips[strip][page].controls[c]

            local track = GetTrack(nz(ctl.tracknum,strips[strip].track.tracknum))
            local cc = ctl.ctlcat
            local fxnum = ctl.fxnum
            local param = ctl.param
            local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,c)
            local dval = DenormalizeValue(min,max,v)

            snapctl.data[snapslide.snapparamidx].dval = dval

            if lvar.snapedit.monitor then
              ctl.oval = ctl.val
              ctl.val = v
              A_SetParam(tracks[track_select].strip, page, c, ctl)
              snapctl.data[snapslide.snapparamidx].dispval = ctl.dval
            end
            lupd.update_macroedit = true
          end

        elseif mouse.context == contexts.snapparamdrag then

          local yy = math.floor((mouse.my - obj.sections[420].y)/macroedit.sech)
          local np = F_limit((yy+1)+lvar.snapedit.snapedit_poffs,1,#snaps.ctls)
          local hh = macroedit.pcnt2-1 --math.floor(obj.sections[420].h/macroedit.sech)-1

          if (yy < 0 or yy >= hh) and snapparamdrag.t == nil then
            snapparamdrag.t = reaper.time_precise()
          elseif yy < 0 and snapparamdrag.t then
            if reaper.time_precise() > snapparamdrag.t + 0.1 then
              lvar.snapedit.snapedit_poffs = F_limit(lvar.snapedit.snapedit_poffs -1,0,#snaps.ctls-1)
              snapparamdrag.t = reaper.time_precise()
              lupd.update_macrobutt = true
            end
          elseif yy >= hh then
            if reaper.time_precise() > snapparamdrag.t + 0.1 then
              lvar.snapedit.snapedit_poffs = F_limit(lvar.snapedit.snapedit_poffs +1,0,#snaps.ctls-1-hh)
              snapparamdrag.t = reaper.time_precise()
              lupd.update_macrobutt = true
            end
          elseif yy >= 0 and yy < #snaps.ctls then
            snapparamdrag.t = nil
          end

          if mouse.mx ~= omx or mouse.my ~= omy then
            lupd.update_surface = true
          end
          omx, omy = mouse.mx, mouse.my

        end

      end

      mouse.mx, mouse.my = mx, my

    end
    return noscroll

  end

  function SnapEditSSMenu(mx,my)
    local snaps = snapshots[tracks[track_select].strip][page][sstype_select]
    gfx.x = mx
    gfx.y = my
    local str = 'Rename Snapshot||Duplicate Snapshot'
    local res = gfx.showmenu(str)
    if res > 0 then
      if res == 1 then
        if snaps.snapshot[lvar.snapedit.snapedit_ss] then
          ss_select = lvar.snapedit.snapedit_ss
          OpenEB(11,'Please enter new snapshot name:')
        end
      elseif res == 2 then
        if snaps.snapshot[lvar.snapedit.snapedit_ss] then
          local snew = #snaps.snapshot+1
          snaps.snapshot[snew] = table.deepcopy(snaps.snapshot[lvar.snapedit.snapedit_ss])

          local copy = string.match(snaps.snapshot[snew].name,'.+ %- Copy (%d+)')
          local nm = string.match(snaps.snapshot[snew].name,'(.+) %- Copy %d+')

          if nm and copy then
            local cn = tonumber(copy)+1
            nm = nm ..' - Copy '..string.format('%i',cn)
          else
            nm = snaps.snapshot[snew].name..' - Copy 1'
          end
          snaps.snapshot[snew].name = nm
          lvar.snapedit.snapedit_ss = snew
          lupd.update_gfx = true
        end
      end
    end
  end

  function SnapEditParamMenu(mx,my)
    local p = lvar.snapedit.selected
    local snaps = snapshots[tracks[track_select].strip][page][sstype_select]
    gfx.x = mx
    gfx.y = my
    local str = 'Duplicate Param|Duplicate Stage||Insert Stage|Lower Stages||Delete Param|Delete Stage'
    local res = gfx.showmenu(str)
    if res > 0 then
      if res == 1 then

        if snaps.stages < lvar.snapstages then
          local nstage = (snaps.stages or 1) + 1
          local nctl = #snaps.ctls + 1
          local id = GenID()
          snaps.ctls[nctl] = table.copy(snaps.ctls[p])
          snaps.ctls[nctl].id = id
          snaps.ctls[nctl].stage = nstage
          for i = 1, #snaps.snapshot do
            snaps.snapshot[i].data[nctl] = table.copy(snaps.snapshot[i].data[p])
            snaps.snapshot[i].data[nctl].id = id
          end
          snaps.stages = snaps.stages + 1

          CleanSortSS(tracks[track_select].strip,page,sstype_select)
          lupd.update_gfx = true
        end

      elseif res == 2 then

        if snaps.stages < lvar.snapstages then
          local sstage = snaps.ctls[p].stage
          local nstage = (snaps.stages or 1) + 1
          for sc = 1, #snaps.ctls do
            if snaps.ctls[sc].stage == sstage then
              local nctl = #snaps.ctls + 1
              local id = GenID()
              snaps.ctls[nctl] = table.copy(snaps.ctls[sc])
              snaps.ctls[nctl].id = id
              snaps.ctls[nctl].stage = nstage
              for i = 1, #snaps.snapshot do
                snaps.snapshot[i].data[nctl] = table.copy(snaps.snapshot[i].data[sc])
                snaps.snapshot[i].data[nctl].id = id
              end
            end
          end
          snaps.stages = snaps.stages + 1

          CleanSortSS(tracks[track_select].strip,page,sstype_select)
          lupd.update_gfx = true
        end

      elseif res == 3 then

        if snaps.stages < lvar.snapstages then
          local sstage = snaps.ctls[p].stage

          for sc = 1, #snaps.ctls do
            if snaps.ctls[sc].stage >= sstage then
              snaps.ctls[sc].stage = snaps.ctls[sc].stage+1
            end
          end
          snaps.stages = snaps.stages + 1
          CleanSortSS(tracks[track_select].strip,page,sstype_select)
          lupd.update_gfx = true
        end

      elseif res == 4 then

        local sstage = snaps.ctls[p].stage
        for sc = 1, #snaps.ctls do
          if snaps.ctls[sc].stage >= sstage then
            snaps.ctls[sc].stage = snaps.ctls[sc].stage-1
          end
        end
        snaps.stages = snaps.stages - 1
        CleanSortSS(tracks[track_select].strip,page,sstype_select)
        lupd.update_gfx = true

      elseif res == 5 then

        snaps.ctls[p].delete = true

        Snap_RemoveDeletedSS(tracks[track_select].strip,page,sstype_select)
        CleanSortSS(tracks[track_select].strip, page, sstype_select)
        CheckRandom(tracks[track_select].strip, page, sstype_select)

        lupd.update_gfx = true

      elseif res == 6 then

        local sstage = snaps.ctls[p].stage
        for sc = 1, #snaps.ctls do
          if snaps.ctls[sc].stage == sstage then
            snaps.ctls[sc].delete = true
          end
        end
        for sc = 1, #snaps.ctls do
          if snaps.ctls[sc].stage > sstage then
            snaps.ctls[sc].stage = snaps.ctls[sc].stage-1
          end
        end
        snaps.stages = snaps.stages - 1

        Snap_RemoveDeletedSS(tracks[track_select].strip,page,sstype_select)
        CleanSortSS(tracks[track_select].strip, page, sstype_select)
        CheckRandom(tracks[track_select].strip, page, sstype_select)

        lupd.update_gfx = true

      end
    end
  end

  function Table_Test()

    local t = {1,2,3,4,5,6,7,8,9,10}
    local d = Table_Move(t,8,4)
    DBG('')
    for i = 1, #d do
      DBG(i..':  '..d[i])
    end
  end

  function Table_Move(t,s,d)

    local tmp = {}

    local cnt = #t
    local offs = 0

    if s < d then
      for i = 1, cnt do
        if i == s then
          offs = offs + 1
          tmp[i] = t[i+offs]
        elseif i == d then
          tmp[i] = t[s]
          offs = offs - 1
        else
          tmp[i] = t[i+offs]
        end
      end
      return tmp

    elseif d < s then
      for i = 1, cnt do
        if i == s then
          tmp[i] = t[i+offs]
          offs = offs + 1
        elseif i == d then
          tmp[i] = t[s]
          offs = offs - 1
        else
          tmp[i] = t[i+offs]
        end
      end
      return tmp

    else
      return t
    end
  end

  function A_Run_MacroEdit(noscroll, rt)

    if strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[macroctl_select] and
       strips[tracks[track_select].strip][page].controls[macroctl_select].ctlcat == ctlcats.macro or
       strips[tracks[track_select].strip][page].controls[macroctl_select].ctlcat == ctlcats.macro_updateparam then

      navigate = false
      noscroll = true

      local xywh = {x = obj.sections[300].x+obj.sections[401].x,
                    y = obj.sections[300].y+obj.sections[401].y,
                    w = obj.sections[401].w,
                    h = obj.sections[401].h}
      if mouse.context == nil and MOUSE_click(xywh) then

        lvar.delayfunction.exit_macro_edit = true

      else

        local macroctl = strips[tracks[track_select].strip][page].controls[macroctl_select].macroctl
        if macroctl and gfx.mouse_wheel ~= 0 and MOUSE_over(obj.sections[300]) then

          v = mousewheel_val()
          if mouse.ctrl then
            lvar.macrosech = F_limit(math.floor(lvar.macrosech + v*2),26,60)
            PopMacroEditSec(obj,lvar.macrosech)
          else
            macroedit_poffs = F_limit(macroedit_poffs-v,0,#macroctl-1)
          end

          lupd.update_gfx = true
        end

        local mx, my = mouse.mx, mouse.my
        mouse.mx, mouse.my = mouse.mx - obj.sections[300].x, mouse.my - obj.sections[300].y

        if mouse.context == nil then
          local xywh_403 = {x = obj.sections[403].x - (macroedit.sliderw*0.5),
                            y = obj.sections[403].y,
                            w = obj.sections[403].w + macroedit.sliderw,
                            h = obj.sections[403].h}
          local xywh_404 = {x = obj.sections[404].x - (macroedit.sliderw*0.5),
                            y = obj.sections[404].y,
                            w = obj.sections[404].w + macroedit.sliderw,
                            h = obj.sections[404].h}
  
          
          if MOUSE_click(obj.sections[410]) and macroedittype_select == 0 then --macro test knob
  
            if mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.15 then
              local i = macroctl_select
              strips[tracks[track_select].strip][page].controls[i].val = strips[tracks[track_select].strip][page].controls[i].defval
              SetMacro(tracks[track_select].strip,page,i)
              lupd.update_macroedit = true
            else
              local i = macroctl_select
              macctlactive = i
              mouse.context = contexts.macctl2
              mouse.slideoff = obj.sections[410].y+obj.sections[410].h/2 - mouse.my
              ctlpos = ctlScaleInv(nz(strips[tracks[track_select].strip][page].controls[i].scalemode,8),
                                   strips[tracks[track_select].strip][page].controls[i].val)
              oms = mouse.shift
            end
  
          elseif MOUSE_click(xywh_403) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[403].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
  
              local val = macroctl[(yy+1)+macroedit_poffs].A_val
              local xywh = {x = obj.sections[403].x + (val*obj.sections[403].w) -(macroedit.sliderw*0.5),
                            y = obj.sections[403].y + (yy*macroedit.sech) + (macroedit.sech*0.5) - (macroedit.sliderh*0.5),
                            w = macroedit.sliderw,
                            h = macroedit.sliderh}
              if MOUSE_over(xywh) then
  
                mouse.context = contexts.macsliderA
                macslide = {xoff = mouse.mx-(xywh.x+(xywh.w*0.5)), macparamidx = (yy+1)+macroedit_poffs}
  
              end
  
            end
  
          elseif MOUSE_click(xywh_404) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[404].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
  
              local val = macroctl[(yy+1)+macroedit_poffs].B_val
              local xywh = {x = obj.sections[404].x + (val*obj.sections[404].w) -(macroedit.sliderw*0.5),
                            y = obj.sections[404].y + (yy*macroedit.sech) + (macroedit.sech*0.5) - (macroedit.sliderh*0.5),
                            w = macroedit.sliderw,
                            h = macroedit.sliderh}
              if MOUSE_over(xywh) then
  
                mouse.context = contexts.macsliderB
                macslide = {xoff = mouse.mx-(xywh.x+(xywh.w*0.5)), macparamidx = (yy+1)+macroedit_poffs}
  
              end
  
            end

          elseif MOUSE_click(obj.sections[4051]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[405].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local i = macroctl_select
              strips[tracks[track_select].strip][page].controls[i].macromon = (yy+1)+macroedit_poffs
              lupd.update_macrobutt = true
            end
            
          elseif MOUSE_click(obj.sections[405]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[405].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
  
              macroctl[(yy+1)+macroedit_poffs].shape = macroctl[(yy+1)+macroedit_poffs].shape + 1
              if macroctl[(yy+1)+macroedit_poffs].shape > #lvar.macroscale_table then
                macroctl[(yy+1)+macroedit_poffs].shape = 1
              end
              lupd.update_gfx = true
  
            end
  
          elseif MOUSE_click_RB(obj.sections[405]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[405].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
  
              macroctl[(yy+1)+macroedit_poffs].shape = macroctl[(yy+1)+macroedit_poffs].shape - 1
              if macroctl[(yy+1)+macroedit_poffs].shape < 1 then
                macroctl[(yy+1)+macroedit_poffs].shape = #lvar.macroscale_table
              end
              lupd.update_gfx = true
  
            end
  
          elseif MOUSE_click(obj.sections[406]) then
            local yy = math.floor((mouse.my - obj.sections[406].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local xywh = {x = obj.sections[406].x,
                            y = obj.sections[406].y + yy*macroedit.sech + 0.5*macroedit.sech - 10,
                            w = obj.sections[406].w,
                            h = 20}
              if MOUSE_over(xywh) then
  
                macroctl[(yy+1)+macroedit_poffs].mute = not nz(macroctl[(yy+1)+macroedit_poffs].mute,false)
                lupd.update_macrobutt = true
  
              end
            end
  
          elseif MOUSE_click(obj.sections[414]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[414].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local xywh = {x = obj.sections[414].x,
                            y = obj.sections[414].y + yy*macroedit.sech + 0.5*macroedit.sech - 10,
                            w = obj.sections[414].w,
                            h = 20}
              if MOUSE_over(xywh) then
  
                macroctl[(yy+1)+macroedit_poffs].bi = not nz(macroctl[(yy+1)+macroedit_poffs].bi,false)
                if settings_macroeditmonitor then
                  SetMacro(tracks[track_select].strip,page,macroctl_select,true)
                end
  
                lupd.update_macrobutt = true
  
              end
            end
  
          elseif MOUSE_click(obj.sections[415]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[415].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local xywh = {x = obj.sections[415].x,
                            y = obj.sections[415].y + yy*macroedit.sech + 0.5*macroedit.sech - 10,
                            w = obj.sections[415].w,
                            h = 20}
              if MOUSE_over(xywh) then
  
                macroctl[(yy+1)+macroedit_poffs].inv = not nz(macroctl[(yy+1)+macroedit_poffs].inv,false)
                if settings_macroeditmonitor then
                  SetMacro(tracks[track_select].strip,page,macroctl_select,true)
                end
  
                lupd.update_macrobutt = true
  
              end
            end
  
          elseif MOUSE_click(obj.sections[416]) and macroedittype_select == 0 then
            local yy = math.floor((mouse.my - obj.sections[416].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local xywh = {x = obj.sections[416].x,
                            y = obj.sections[416].y + yy*macroedit.sech + 0.5*macroedit.sech - 10,
                            w = obj.sections[416].w,
                            h = 20}
              if MOUSE_over(xywh) then
  
                macroctl[(yy+1)+macroedit_poffs].relative = not nz(macroctl[(yy+1)+macroedit_poffs].relative,false)
                if macroctl[(yy+1)+macroedit_poffs].relative == false and settings_macroeditmonitor then
                  SetMacro(tracks[track_select].strip,page,macroctl_select,true)
                end
  
                lupd.update_macrobutt = true
  
              end
            end
  
          elseif MOUSE_click(obj.sections[407]) then -- delete param
            local yy = math.floor((mouse.my - obj.sections[407].y)/macroedit.sech)
            if macroctl[(yy+1)+macroedit_poffs] then
              local xywh = {x = obj.sections[407].x,
                            y = obj.sections[407].y + yy*macroedit.sech + 0.5*macroedit.sech - 10,
                            w = obj.sections[407].w,
                            h = 20}
              if MOUSE_over(xywh) then
  
                local mcnt = #macroctl
                macroctl[(yy+1)+macroedit_poffs] = nil
                local mtab = Table_RemoveNils(macroctl, mcnt)
                strips[tracks[track_select].strip][page].controls[macroctl_select].macroctl = mtab
                lupd.update_gfx = true
  
              end
            end
  
          elseif MOUSE_click(obj.sections[408]) and macroedittype_select == 0 then
  
            local f = {targettype = 2,
                       strip = tracks[track_select].strip,
                       page = page,
                       ctl = macroctl_select,
                       c_id = strips[tracks[track_select].strip][page].controls[macroctl_select].c_id}
            if lvar.livemode == 2 then
              f.dm_trn = lvar.dynamicmode_trn
              f.dm_guid = lvar.dynamicmode_guid
            end
            mouse.mx, mouse.my = mx, my
            local fad = SetAutomationFader(f, strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader, true)
            if fad == -2 then
              DeleteFader(strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader)
              lupd.update_gfx = true
            elseif fad ~= -1 then
              --if strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader and strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader ~= fad then
              --  faders[strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader] = {}
              --end
              --strips[tracks[track_select].strip][page].controls[macroctl_select].macrofader = fad
              AssignFader(fad, f)
              lupd.update_gfx = true
            end
  
          elseif MOUSE_click(obj.sections[409]) then
  
            macro_lrn_mode = true
            oslfoeedit = show_lfoedit
            ossnaps = show_snapshots
            show_lfoedit = false
            show_snapshots = false
            RedrawGUIBitmap()
            
            obj = GetObjects()
            lupd.update_gfx = true
  
          elseif MOUSE_click(obj.sections[411]) and macroedittype_select == 0 then
  
            Macro_Capture(tracks[track_select].strip,page,macroctl_select,0)
            if settings_macroeditmonitor then
              SetMacro(tracks[track_select].strip,page,macroctl_select,true)
            end
            lupd.update_macroedit = true
  
          elseif MOUSE_click(obj.sections[412]) and macroedittype_select == 0 then
  
            Macro_Capture(tracks[track_select].strip,page,macroctl_select,1)
            if settings_macroeditmonitor then
              SetMacro(tracks[track_select].strip,page,macroctl_select,true)
            end
            lupd.update_macroedit = true
  
          elseif MOUSE_click(obj.sections[413]) and macroedittype_select == 0 then
  
            settings_macroeditmonitor = not settings_macroeditmonitor
            lupd.update_gfx = true
  
          end
        end        
        
        noscroll = true
        mouse.mx, mouse.my = mx, my

      end
    else
      navigate = true
      macro_edit_mode = false
      macroctl_select = nil
      lupd.update_gfx = true
      RedrawGUIBitmap()
    end
    return noscroll

  end

  function A_Run_MacroEdit2(noscroll, rt)
  
    if strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[macroctl_select] and
       strips[tracks[track_select].strip][page].controls[macroctl_select].ctlcat == ctlcats.macro or
       strips[tracks[track_select].strip][page].controls[macroctl_select].ctlcat == ctlcats.macro_updateparam then
    
      local macroctl = strips[tracks[track_select].strip][page].controls[macroctl_select].macroctl
      if macroctl then
      
        local mx, my = mouse.mx, mouse.my
        mouse.mx, mouse.my = mouse.mx - obj.sections[300].x, mouse.my - obj.sections[300].y
        
        if mouse.context then
          if mouse.context == contexts.macctl2 then
        
            --local tfxp_s = macroctl_select
            local val = MOUSE_slider(obj.sections[410],mouse.slideoff)
            if val ~= nil then
              local ctl = strips[tracks[track_select].strip][page].controls[macroctl_select]
              if oms ~= mouse.shift then
                oms = mouse.shift
                ctlpos = ctl.val
                mouse.slideoff = ctlxywh.y+ctlxywh.h/2 - mouse.my
              else
                if mouse.shift then
                  local mult = ctl.knobsens.fine * (ctl.knobsens.m_fine or 1)
                  if mult == 0 then mult = settings_defknobsens.fine end
                  val = ctlpos + ((0.5-val)*2)*mult
                else
                  local mult = ctl.knobsens.norm * (ctl.knobsens.m_norm or 1)
                  if mult == 0 then mult = settings_defknobsens.norm end
                  val = ctlpos + (0.5-val)*mult
                end
                if val < 0 then val = 0 end
                if val > 1 then val = 1 end
                val = ctlScale(ctl.scalemode, val)
                if val ~= octlval then
                  ctl.diff = val - ctl.val
                  ctl.oval = ctl.val
                  ctl.val = val
                  SetMacro(tracks[track_select].strip, page, macroctl_select)
                  ctl.dirty = true
                  octlval = val
                  --lupd.update_ctls = true
                  lupd.update_macroedit = true
                  --lupd.update_ctls = false
                end
              end
            end  
      
          elseif mouse.context and mouse.context == contexts.macsliderA then
      
            local v = F_limit((mouse.mx - macslide.xoff - obj.sections[403].x)/obj.sections[403].w,0,1)
            macroctl[macslide.macparamidx].A_val = v
            if settings_macroeditmonitor then
              SetMacro(tracks[track_select].strip, page, macroctl_select,true)
            end
            lupd.update_macroedit = true
      
          elseif mouse.context and mouse.context == contexts.macsliderB then
      
            local v = F_limit((mouse.mx - macslide.xoff - obj.sections[404].x)/obj.sections[404].w,0,1)
            macroctl[macslide.macparamidx].B_val = v
            if settings_macroeditmonitor then
              SetMacro(tracks[track_select].strip, page, macroctl_select,true)
            end
            lupd.update_macroedit = true
      
          end
        
        else
          if macctlactive ~= nil then
          
            local strip = tracks[track_select].strip
            local mac = strips[strip][page].controls[macctlactive].macroctl
            strips[strip][page].controls[macctlactive].diff = nil
            if mac and #mac > 0 then
              for m = 1, #mac do
                --strips[strip][page].controls[mac[m].ctl].mval = nil
              end
            end
            macctlactive = nil
          end
        end
      
        noscroll = true
        mouse.mx, mouse.my = mx, my      
      end
      
    end
    
    return noscroll
  end

  function A_Run_DropDown()

    if MOUSE_over(ddlist) then
    
      local butt_h = tb_butt_h*lvar.zoom
      local over = math.floor((mouse.my - ddlist.y)/butt_h)+1
      if over ~= ddlist.over then

        ddlist.over = over
        lupd.update_dd = true
        lupd.update_surface = true

      end
      local sel

      if gfx.mouse_wheel ~= 0 then
        local v = mousewheel_val()
        if ddlist.scroll == -1 then
          ddlist.offset = F_limit(ddlist.offset - v*(ddlist.size or 1),0,#ddlist.items-ddlist.size)
        else
          ddlist.offset = F_limit(ddlist.offset - v*(ddlist.scroll or 1),0,#ddlist.items-ddlist.size)
        end
        lupd.update_dd = true
        gfx.mouse_wheel = 0
      elseif mouse.LB then
        
        if ddlist.itemdisabled == nil or ddlist.itemdisabled[over+ddlist.offset] ~= true then
          
          ddlist.select = over
          show_dd = false
          lupd.update_surface = true
          sel = true
        end
      end

      if ddlist.select and sel then
        DropDown_ItemSel(ddlist.select)
        RedrawGUIBitmap()
        ddlist = nil
      end

    else

      if ddlist.over ~= nil then
        ddlist.over = nil
        lupd.update_dd = true
        lupd.update_surface = true
      end
      if mouse.LB or mouse.RB then
        show_dd = false
        ddlist = nil
        lupd.update_surface = true
        RedrawGUIBitmap()
      end
    end
    lvar.dropenabled_timer = reaper.time_precise()+0.2

  end

  function DropDown_ItemSel(sel)

    sel = sel + ddlist.offset
    if sel then
      if ddlist.idx == 1 then

        RCM_Set(rcm_select, sel)

      elseif ddlist.idx == 2 then

        local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
        if ctl and ctl.ctlcat == ctlcats.switcher then
          if (switchers[ctl.switcherid].switchmode or 0) == 0 then
            Switcher_Set(switcher_select, sel)
          elseif switchers[ctl.switcherid].switchmode == 1 then
            if switchers[ctl.switcherid].stripfolder == '__LBXFAVS' and ddlist.items[sel] then
              if strip_favs[sel] then
                local fn = strip_favs[sel]
                local fx, trn
                if lvar.livemode == 2 then

                  fx = DM_Switcher_GetFXPos(ctl.switcherid) or 0

                  --fx = switchers[ctl.switcherid].extendpos-1
                  trn = lvar.dynamicmode_trn
                  Switcher_AddStrip(fn, switcher_select,nil,nil,trn,fx,nil,true)
                  local extid = switchers[ctl.switcherid].extendid
                  Strip_ReposSwitcher_Ext(extid, 1)
                  DM_RefreshFX()

                else
                  Switcher_AddStrip(fn, switcher_select)
                end
              end
            elseif switchers[ctl.switcherid].stripfolder and ddlist.items[sel] then
              local fn = switchers[ctl.switcherid].stripfolder ..'/'.. ddlist.items[sel]..'.strip'
              if lvar.livemode == 2 then
                fx = DM_Switcher_GetFXPos(ctl.switcherid) or 0
                --fx = switchers[ctl.switcherid].extendpos-1
                trn = lvar.dynamicmode_trn
                Switcher_AddStrip(fn, switcher_select,nil,nil,trn,fx,nil,true)
                local extid = switchers[ctl.switcherid].extendid
                Strip_ReposSwitcher_Ext(extid, 1)
                DM_RefreshFX()
              else
                Switcher_AddStrip(fn, switcher_select)
              end
            end
          end
        end

      elseif ddlist.idx == 3 then

        if sel == 1 then
          lvar.stripbrowser.favs = true
          lvar.stripbrowser.search = nil
          lvar.reloadsbimages = true
        else
          local n = sel-2
          if strip_folders[n] then
            lvar.stripbrowser.favs = false
            lvar.stripbrowser.search = nil
            stripfol_select = n
            PopulateStrips()
            lvar.reloadsbimages = true
          end
        end
        lupd.update_stripbrowser = true

      elseif ddlist.idx == 4 then

        local switchid = ddlist.switchid

        local idx2 = ddlist.data[sel]
        if idx2 then

          local fn = plugdefstrips[idx2].stripfol..'/'..plugdefstrips[idx2].stripfile

          switchers[switchid].grpids[1].stripfn = paths.strips_path..fn
          DM_RefreshPage()
        end

      elseif ddlist.idx == 5 then

        if sel > 5 then
          local trn = ddlist.data[sel] or -1
          DM_TrBtns_Folder(trn)
        elseif sel == 1 then
          DM_TrBtns_Auto()
        elseif sel == 2 then
          DM_TrBtns_MI()
        elseif sel == 3 then
          DM_TrBtns_ItemType(true)
        elseif sel == 4 then
          DM_TrBtns_ItemType(false)
        elseif sel == 5 then
          DM_TrBtns_Folders()
        end

      elseif ddlist.idx == 6 then

        if sel > 6 then
          local set = ddlist.data[sel] or -1
          DM_TrBtns_ShowSet(set)

        elseif sel == 1 then

          lvar.dm_tbidx = #lvar.dm_trackbtns+1
          lvar.dm_trackbtns[lvar.dm_tbidx] = {}
          lvar.trbtns_offs = 0
          obj = PosTrBtns(obj)
          lupd.update_trbtns = true

        elseif sel == 2 then

          lvar.dm_trackbtns[#lvar.dm_trackbtns+1] = table.copy(lvar.dm_trackbtns[lvar.dm_tbidx])
          lvar.dm_tbidx = #lvar.dm_trackbtns
          lupd.update_trbtns = true

        elseif sel == 4 then

          local ret, val = reaper.GetUserInputs('Rename Track Set',1,'Enter name:',lvar.dm_trackbtns[lvar.dm_tbidx].name or '')
          if ret then
            if val == '' then
              lvar.dm_trackbtns[lvar.dm_tbidx].name = nil
            else
              lvar.dm_trackbtns[lvar.dm_tbidx].name = val
            end
          end

        elseif sel == 5 then

          local tab = {}
          for i = 1, #lvar.dm_trackbtns do
            if i ~= lvar.dm_tbidx then
              tab[#tab+1] = lvar.dm_trackbtns[i]
            end
          end
          if tab[1] == nil then
            tab[1] = {}
          end
          lvar.dm_trackbtns = tab
          lvar.dm_tbidx = 1
          lvar.trbtns_offs = 0
          obj = PosTrBtns(obj)
          lupd.update_trbtns = true

        end
      elseif ddlist.idx == 7 then

        if sel > 3 then
          sel = sel - 3
          local ctl = ddlist.ctl
          ctl.param_info.paramidx = sel-1
          ctl.param_info.paramstr2 = lvar.sk2data_slots[ctl.param_info.paramidx].map
          lvar.sk2data_assign = nil        
          
        elseif sel == 1 then
        
          local ctl = ddlist.ctl
          if ctl_select and #ctl_select > 0 then
            local ctls = strips[tracks[track_select].strip][page].controls
            local pnum = tonumber(ctls[ctl_select[1].ctl].param_info.paramnum) or 0
            local base = pnum&2
            local str = 1-(pnum&1)
          
            for c = 1, #ctl_select do
              local ctl2 = ctls[ctl_select[c].ctl]
              if ctl2 then
                if ctl2.ctlcat == ctlcats.sk2ctl then
                  local pnum = tonumber(ctl2.param_info.paramnum) or 0
                  local base = pnum&2

                  ctl2.param_info.paramnum = base+str
                end
              end
            end
            lupd.update_gfx = true

          else
            local pnum = tonumber(ctl.param_info.paramnum) or 0
            local base = pnum&2
            local str = 1-(pnum&1)
            
            ctl.param_info.paramnum = base+str
            lupd.update_gfx = true
          end
        
        elseif sel == 2 then
        
          local ctl = ddlist.ctl
          if ctl_select and #ctl_select > 0 then
            local ctls = strips[tracks[track_select].strip][page].controls
            local pnum = tonumber(ctls[ctl_select[1].ctl].param_info.paramnum) or 0
            local base = pnum&1
            local str = 2-(pnum&2)

            for c = 1, #ctl_select do
              local ctl2 = ctls[ctl_select[c].ctl]
              if ctl2 then
                if ctl2.ctlcat == ctlcats.sk2ctl then
                  local pnum = tonumber(ctl2.param_info.paramnum) or 0
                  local base = pnum&1
            
                  ctl2.param_info.paramnum = base+str
                end
              end
            end
            lupd.update_gfx = true
          else
            local pnum = tonumber(ctl.param_info.paramnum) or 0
            local base = pnum&1
            local str = 2-(pnum&2)
            
            ctl.param_info.paramnum = base+str
            lupd.update_gfx = true
          end
        
        end
        
      elseif ddlist.idx == 8 then
      
        local fnt = fontlist[sel]
        if fnt then
          local f = CheckFont(fnt)
          if f then
            Undo_Set({'font'})
            ctlfont_select = f
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].font = ctlfont_select
            end
          end
          lupd.update_gfx = true
        end

      elseif ddlist.idx == 9 then
      
        local fnt = fontlist[sel]
        if fnt then
          local f = CheckFont(fnt)
          if f then
            Undo_Set({'font'})
  
            EditFont2(f)
            lupd.update_gfx = true
          end
        end
        
      elseif ddlist.idx == 10 then
      
        local fnt = fontlist[sel]
        if fnt then
          local f = CheckFont(fnt)
          if f then
            gauge_select.font = f
          end
          lupd.update_gfx = true
        end
        
      elseif ddlist.idx == 11 then
        local map = lvar.sk2data_slots[sel-1].map..'|'..lvar.sk2data_slots[sel-1].name
        if not lvar.sk2overlay.slot[ddlist.btn] then
          lvar.sk2overlay.slot[ddlist.btn] = {}
        end
        lvar.sk2overlay.slot[ddlist.btn].map = map
        lvar.sk2overlay.slot[ddlist.btn].dev = lvar.sk2data_slots[sel-1].map
        lvar.sk2overlay.slot[ddlist.btn].name = lvar.sk2data_slots[sel-1].name
        
        lvar.xPnlSel.updategui = true
        
        SK2SaveSlots()
        if lvar.sk2overlay_active == 1 then
          SendSK2Data()
        end
        
        --DBG(lvar.sk2data_slots[sel].map..'|'..lvar.sk2data_slots[sel].name)
        
      end

    end
    ddlist = nil
    mouse.context = contexts.dd

  end

  function DM_TrBtns_ShowSet(set)

    if set > 0 then

      lvar.dm_tbidx = set
      lvar.trbtns_offs = 0
      obj = PosTrBtns(obj)
      lupd.update_trbtns = true

    end

  end

  function DM_TrBtns_Auto()
    
    lvar.dm_tbidx = lvar.trbtns_autoidx
    local tab = {}
    local tab2 = {}
    tab[1] = {guid = nil, trn = -1}
    
    for t = 0, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      local vis = reaper.IsTrackVisible(tr, true)
      local guid = GetTrackGUID(tr)
      local _, name = reaper.GetTrackName(tr)
      tab2[t] = {guid = guid, trn = t, name = name, vis = vis}
      if vis then
        tab[#tab+1] = {guid = guid, trn = t, name = name, vis = vis}
      end
    end    
    lvar.dm_trackbtns[lvar.dm_tbidx] = tab
    lvar.dm_trackmon = tab2
    obj = PosTrBtns(obj)
    lupd.update_trbtns = true

    local cnt = math.min(#tab, lvar.trov_maxrows)
    if lvar.trbtns_offs > #tab - (cnt-1) then
      lvar.trbtns_offs = math.max(#tab - (cnt-1),0)
    end

  end
  
  function DM_TrBtns_MI()
    lvar.dm_tbidx = 0
    local tab = {}

    for t = 0, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      local item = reaper.GetTrackMediaItem(tr,0)
      if item then
        local guid = GetTrackGUID(tr)
        tab[#tab+1] = {guid = guid, trn = t}
      end
    end

    lvar.dm_trackbtns[lvar.dm_tbidx] = tab
    lvar.trbtns_offs = 0
    obj = PosTrBtns(obj)
    lupd.update_trbtns = true

  end

  function DM_TrBtns_ItemType(takeismidi)
    lvar.dm_tbidx = 0
    local tab = {}

    for t = 0, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      for item_n = 0, reaper.CountTrackMediaItems(tr)-1 do
        local fnd
        local item = reaper.GetTrackMediaItem(tr,item_n)
        for take_n = 0, reaper.CountTakes(item)-1 do
          local take = reaper.GetMediaItemTake(item, take_n)
          if take and reaper.TakeIsMIDI(take) == takeismidi then
            local guid = GetTrackGUID(tr)
            tab[#tab+1] = {guid = guid, trn = t}
            fnd = true
            break
          end
        end
        if fnd then
          break
        end
      end
    end

    lvar.dm_trackbtns[lvar.dm_tbidx] = tab
    lvar.trbtns_offs = 0
    obj = PosTrBtns(obj)
    lupd.update_trbtns = true

  end

  function DM_TrBtns_Folder(trn)

    lvar.dm_tbidx = 0
    local tab = {}
    if trn == -1 then
      tab[1] = {guid = nil, trn = -1}
    else
      local tr = GetTrack(trn)
      local guid = GetTrackGUID(tr)
      tab[1] = {guid = guid, trn = trn}
    end

    local fd = 0
    for t = trn+1, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)

      if fd >= 0 then
        local guid = GetTrackGUID(tr)
        tab[#tab+1] = {guid = guid, trn = t}
      elseif fd < 0 then
        break
      end
      local fold = reaper.GetMediaTrackInfo_Value(tr, 'I_FOLDERDEPTH')
      fd = fd + fold
    end

    lvar.dm_trackbtns[lvar.dm_tbidx] = tab
    lvar.trbtns_offs = 0
    obj = PosTrBtns(obj)
    lupd.update_trbtns = true

  end

  function DM_TrBtns_Folders()

    lvar.dm_tbidx = 0
    local tab = {}

    local fd = 0
    for t = -1, reaper.CountTracks(0)-1 do
      local tr = GetTrack(t)
      local fold = reaper.GetMediaTrackInfo_Value(tr, 'I_FOLDERDEPTH')

      if fold == 1 then
        local guid = GetTrackGUID(tr)
        tab[#tab+1] = {guid = guid, trn = t}
      end
    end

    lvar.dm_trackbtns[lvar.dm_tbidx] = tab
    lvar.trbtns_offs = 0
    obj = PosTrBtns(obj)
    lupd.update_trbtns = true

  end

  function Switcher_Set(switcher_select, sel)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[switcher_select]
    local switchid = ctl.switcherid

    if switchers[switchid].grpids[sel] then
      switchers[switchid].current = switchers[switchid].grpids[sel].id
      ctl.param_info.paramname = string.format('%i',sel)..': '..switchers[switchid].grpids[sel].name
      lupd.update_gfx = true
      lupd.update_bg = true

      if ctl.switchfader and faders[ctl.switchfader] then
        SetFader(ctl.switchfader, (sel-1+faders[ctl.switchfader].voffset)/128)
      end
      SetCtlBitmapRedraw()
    end

  end

  function Switcher_Set2(switcher_select, sel, strip, page)

    if strips[strip] then
      local ctl = strips[strip][page].controls[switcher_select]
      if ctl then
        local switchid = ctl.switcherid

        if switchers[switchid] then
          if switchers[switchid].grpids[sel] and ctl then
            switchers[switchid].current = switchers[switchid].grpids[sel].id
            ctl.param_info.paramname = string.format('%i',sel)..': '..switchers[switchid].grpids[sel].name
            lupd.update_gfx = true
            lupd.update_bg = true

            SetCtlBitmapRedraw()
          end
        else
          ctl.switcherid = nil
        end
      end
    end
  end

  function Switcher_Set_GrpID(switchid, grpid)

    local switcher_select = Switchers_FindCtl(switchid)

    if switcher_select and switchers[switchid] then
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[switcher_select]
  
      local sel
      for i = 1, #switchers[switchid].grpids do
        if switchers[switchid].grpids[i].id == grpid then
          sel = i
          break
        end
      end
  
      if sel then
        switchers[switchid].current = grpid
        ctl.param_info.paramname = string.format('%i',sel)..': '..switchers[switchid].grpids[sel].name
        lupd.update_gfx = true
        lupd.update_bg = true
  
        if ctl.switchfader and faders[ctl.switchfader] then
          SetFader(ctl.switchfader, (sel-1+faders[ctl.switchfader].voffset)/128)
        end
        SetCtlBitmapRedraw()
      end
    end
    
  end

  function A_PinMapDirty()
    if lvar.livemode == 2 then
      tr = GetTrack(lvar.dynamicmode_trn)
    else
      tr = GetTrack(tracks[track_select].tracknum)
    end
    local fxn = reaper.TrackFX_GetCount(tr)
    local chans = math.min(reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN"))

    if chans ~= pinmatrix_data.chans then return true end

    if fxn-1 ~= #pinmatrix_data then
      --DBG('x')
      return true
    else
      for i = 0, fxn-1 do

        local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,i)
        if pinmatrix_data[i] then
          if inpins ~= pinmatrix_data[i].incnt or outpins ~= pinmatrix_data[i].outcnt then
          --DBG('x1')
            return true
          else
            local pn = reaper.TrackFX_GetNumParams(tr,i)

            if pn ~= lvar.offline_paramcnt then
              for p = 0, inpins-1 do
                if pinmatrix_data[i].inpins[p] then
                  local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, i, 0, p)
                  if Low32 ~= pinmatrix_data[i].inpins[p].lo or Hi32 ~= pinmatrix_data[i].inpins[p].hi then
            --DBG('x2')
                    return true
                  end
                else
            --DBG('y2 '..p..'  '..inpins)
                  return true
                end
              end
              for p = 0, outpins-1 do
                if pinmatrix_data[i].outpins[p] then
                  local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, i, 1, p)
                  if Low32 ~= pinmatrix_data[i].outpins[p].lo or Hi32 ~= pinmatrix_data[i].outpins[p].hi then
            --DBG('x3')
                    return true
                  end
                else
            --DBG('y3')
                  return true
                end
              end
            end
          end
        end
      end
    end

    return false
  end

  function SetPinMap(tr, fxn, inLo, inHi, outLo, outHi)

    local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,fxn)
    if inLo and inHi then
      for p = 0, inpins-1 do
        if inLo[p] and inHi[p] then
          reaper.TrackFX_SetPinMappings(tr, fxn, 0, p, inLo[p], inHi[p])
        end
      end
    end

    if outLo and outHi then
      for p = 0, outpins-1 do
        if outLo[p] and outHi[p] then
          reaper.TrackFX_SetPinMappings(tr, fxn, 1, p, outLo[p], outHi[p])
        end
      end
    end

  end

  function GetPinMap(tr, fxn)

    local inLo, inHi, outLo, outHi = {}, {}, {}, {}
    local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,fxn)
    for p = 0, inpins-1 do
      inLo[p], inHi[p] = reaper.TrackFX_GetPinMappings(tr, fxn, 0, p)
    end
    for p = 0, outpins-1 do
      outLo[p], outHi[p] = reaper.TrackFX_GetPinMappings(tr, fxn, 1, p)
    end

    return inLo, inHi, outLo, outHi

  end

  function ConvertPinMap(pmLo, pmHi)

    local bitmap = {}
    for chan = 0, 31 do
      local bit = 2^(chan%32)
      bitmap[chan] = (pmLo&bit)>0
      bitmap[chan+32] = (pmHi&bit)>0
    end

    local bittxt = ''
    for i = 0, #bitmap do
      if bitmap[i] == true then
        bittxt = bittxt .. '1'
      else
        bittxt = bittxt .. '0'
      end
    end

    return bitmap, bittxt

  end

  function A_Run_PinMatrix(noscroll, rt, char)

    noscroll = true

    local mx, my = mouse.mx, mouse.my
    mouse.mx, mouse.my = mouse.mx - obj.sections[10].x, mouse.my - topbarheight

    if mouse.context == nil then

      if pinmatrix_data and reaper.time_precise() > pinmatrix_data.updatetime + 0.3 then
        if A_PinMapDirty() == true then
          lupd.update_surface = true
        end
      elseif not pinmatrix_data then
        lupd.update_surface = true
      end

      if gfx.mouse_wheel ~= 0 then
        local v = mousewheel_val()

        if mouse.shift == true then
          pinmatrix_scrollpos.x = math.min(pinmatrix_scrollpos.x + (v*40),50)
        else
          pinmatrix_zoom = F_limit(pinmatrix_zoom + (v*0.1),0.8,4)
        end
        lupd.update_surface = true

        gfx.mouse_wheel = 0

      elseif char == 52 then
        show_pinmatrix = false
        lupd.update_surface = true
        RedrawGUIBitmap()

      elseif MOUSE_click(obj.sections[1203]) then
        if lvar.livemode == 2 then
          tr = GetTrack(lvar.dynamicmode_trn)
        else
          tr = GetTrack(tracks[track_select].tracknum)
        end
        local chans = math.min(reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN"))
        if chans < 64 then
          chans = chans + 2
          reaper.SetMediaTrackInfo_Value(tr, "I_NCHAN", chans)
          lupd.update_surface = true
        end

      elseif MOUSE_click_RB(obj.sections[1203]) then
        if lvar.livemode == 2 then
          tr = GetTrack(lvar.dynamicmode_trn)
        else
          tr = GetTrack(tracks[track_select].tracknum)
        end
        local chans = math.min(reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN"))
        if chans > 2 then
          chans = chans - 2
          reaper.SetMediaTrackInfo_Value(tr, "I_NCHAN", chans)
          lupd.update_surface = true
        end

      elseif MOUSE_click(obj.sections[1200]) then

        local chan, inpin, outpin, fxn, fxheader
        if pinmatrix and #pinmatrix.fx_rect >= 0 then
          local fx = mouse.mx
          local fy = mouse.my - pinmatrix_scrollpos.y
          for i = 0, #pinmatrix.fx_rect do
            if pinmatrix.fx_rect[i] then
              if fx >= pinmatrix.fx_rect[i].x and fx <= pinmatrix.fx_rect[i].x + pinmatrix.fx_rect[i].w then
                fxn = i
                break
              end
            end
          end

          if fxn then
            if (fy >= obj.sections[1202].y and fy <= obj.sections[1202].y + obj.sections[1202].h) then

              local pinw, pinh = math.floor(22*pinmatrix_zoom), math.floor(22*pinmatrix_zoom)
              local pinadj = math.floor(2*pinmatrix_zoom)

              local x = fx - pinmatrix.fx_rect[fxn].x
              chan = math.floor((fy - obj.sections[1202].y) / pinh)

              if x < pinmatrix.fx_rect[fxn].inpins * pinw then
                inpin = math.floor(x / pinw)
              elseif x > (pinmatrix.fx_rect[fxn].inpins+1) * pinw then
                outpin = math.floor((x - (pinmatrix.fx_rect[fxn].inpins+1) * pinw) / pinw)
              end
            elseif (fy >= obj.sections[1201].y and fy <= obj.sections[1201].y + obj.sections[1201].h) and mouse.ctrl then
              fxheader = fxn
            end
          end
        end

        if fxheader then

          if lvar.livemode == 2 then
            tr = GetTrack(lvar.dynamicmode_trn)
          else
            tr = GetTrack(tracks[track_select].tracknum)
          end
          local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,fxheader)
          for p = 0, inpins do
            reaper.TrackFX_SetPinMappings(tr, fxheader, 0, p, 0, 0)
          end
          for p = 0, outpins do
            reaper.TrackFX_SetPinMappings(tr, fxheader, 1, p, 0, 0)
          end
          lupd.update_surface = true

        elseif (inpin or outpin) and chan then

          if lvar.livemode == 2 then
            tr = GetTrack(lvar.dynamicmode_trn)
          else
            tr = GetTrack(tracks[track_select].tracknum)
          end
          local pin = inpin or outpin
          local isOut = 0
          if outpin then
            isOut = 1
          end
          local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, fxn, isOut, pin)
          local bit = 2^(chan%32)
          local val
          if chan < 32 then
            val = (Low32&bit)>0
            if val then
              Low32 = Low32 - bit;
            else
              Low32 = Low32 + bit;
            end
          else
            val = (Hi32&bit)>0
            if val then
              Hi32 = Hi32 - bit;
            else
              Hi32 = Hi32 + bit;
            end
          end
          reaper.TrackFX_SetPinMappings(tr, fxn, isOut, pin, Low32, Hi32)
          if mouse.ctrl then
            local val2 = val
            local retval, inpins, outpins = reaper.TrackFX_GetIOSize(tr,fxn)
            isOut = 1-isOut
            if (isOut == 0 and pin <= inpins) or (isOut == 1 and pin <= outpins) then
              local Low32,Hi32 = reaper.TrackFX_GetPinMappings(tr, fxn, isOut, pin)
              local bit = 2^(chan%32)
              local val
              if chan < 32 then
                val = (Low32&bit)>0
                if val == val2 then
                  if val then
                    Low32 = Low32 - bit;
                  else
                    Low32 = Low32 + bit;
                  end
                end
              else
                val = (Hi32&bit)>0
                if val == val2 then
                  if val then
                    Hi32 = Hi32 - bit;
                  else
                    Hi32 = Hi32 + bit;
                  end
                end
              end
              reaper.TrackFX_SetPinMappings(tr, fxn, isOut, pin, Low32, Hi32)

            end
          end

          lupd.update_surface = true


        else
          mouse.context = contexts.scrollmatrix
          matrixoff = {dx = mouse.mx --[[- pinmatrix_scrollpos.x]], dy = mouse.my --[[- pinmatrix_scrollpos.y]],
                       x = 0, y = 0, timer = reaper.time_precise() + 0.2}
        end

      elseif matrixoff and pinmatrix_scrollpos then
        pinmatrix_scrollpos.x = pinmatrix_scrollpos.x + matrixoff.x
        pinmatrix_scrollpos.y = pinmatrix_scrollpos.y + matrixoff.y

        matrixoff = nil
        lupd.update_surface = true
      end

    --[[else

      if mouse.context == contexts.scrollmatrix then

        if mouse.mx ~= omx or mouse.my ~= omy or matrixoff.timer < reaper.time_precise() then
          if matrixoff.timer < reaper.time_precise() then
            if matrixoff.x ~= 0 or matrixoff.y ~= 0 then
              matrixoff.update = true
              pinmatrix_scrollpos.x = pinmatrix_scrollpos.x + matrixoff.x
              if settings_lockpinmatrix == false then
                pinmatrix_scrollpos.y = pinmatrix_scrollpos.y + matrixoff.y
              end
              matrixoff.x = 0
              matrixoff.y = 0
              matrixoff.dx = mouse.mx
              matrixoff.dy = mouse.my

              lupd.update_surface = true
            end
            matrixoff.timer = reaper.time_precise() + 0.2
          else
            matrixoff.update = false
            matrixoff.x = (mouse.mx - matrixoff.dx)
            if settings_lockpinmatrix == false then
              matrixoff.y = (mouse.my - matrixoff.dy)
            end
            lupd.update_surface = true
            omx, omy = mouse.mx, mouse.my
          end
        end
      end]]

    end



    mouse.mx, mouse.my = mx, my
    return noscroll

  end

  function AddStripDialog_UpdateSel(fxdata)

    fxdata.assigned = {}
    for a = 1, #fxdata do
      if fxdata[a].fxnum then
        fxdata.assigned[fxdata[a].fxnum] = true
      end
    end

  end

  function AddStripDialog_GetFxData(trn, fxtgt, swtgt)
  --fxtgt - optional - single plugin to link to
  --swtgt - optional - switcher being replaced

    local fxdata = {}
    local stripid
    local tfxi = GetTrackFXInfo(nil, lvar.addstripdialog_tracknum, swtgt)
    local sfxi = GetStripFXInfo(nil, loadstrip)

    local tr = GetTrack(trn or track_select)
    local trguid = GetTrackGUID(tr)
    local fxcnt = reaper.TrackFX_GetCount(tr)
    local fx_min = fxcnt-1
    local fxn = {}

    if fxtgt then
      local i = 1
      local fx = fxtgt
      fxdata[i] = {fxnm = sfxi[i].fxname, ofxguid = sfxi[i].fxguid, fxguid = tfxi[fx].fxguid, fxfn = tfxi[fx].fxfn, fxname = tfxi[fx].fxname,
                   fxnum = fx, trnum = lvar.addstripdialog_tracknum, trguid = trguid}
    else
      for i = 1, #sfxi do
        local fx
        if tfxi[0] then
          for f = 0, #tfxi do
            if tfxi[f].fxfn == sfxi[i].fxfn and not fxn[f] and not tfxi[f].stripinfo then
              fx = f
              fxn[f] = true
              break
            end
          end
        end
        fx_min = math.min(fx_min,fx or fxcnt)
        if fx then
          fxdata[i] = {fxnm = sfxi[i].fxname, ofxguid = sfxi[i].fxguid, fxguid = tfxi[fx].fxguid, fxfn = tfxi[fx].fxfn, fxname = tfxi[fx].fxname,
                       fxnum = fx, trnum = lvar.addstripdialog_tracknum, trguid = trguid}
        else
          fxdata[i] = {fxnm = sfxi[i].fxname, ofxguid = sfxi[i].fxguid}
        end
      end
    end

    fxdata.tfxi = tfxi
    fxdata.sel = 1
    fxdata.fx_min = fx_min
    --fxdata.dx = dx
    --fxdata.dy = dy

    return fxdata

  end

  function DM_Switcher_GetFXPos(switchid)

    local extpos = switchers[switchid].extendpos
    local trn = lvar.dynamicmode_trn

    local pos
    local extid = switchers[switchid].extendid
    local tfxguids = GetTrackFXGUIDs(trn)

    for i = 1, extpos-1 do

      local fxguids = Switchers_GetFXGUIDs(extid, i) or {}
      for fg = 1, #fxguids do
        if tfxguids[fxguids[fg]] then

          pos = (pos or 0) + 1

        end
      end

    end

    return pos
  end

  function A_RunAddStrip(noscroll, rt)

    noscroll = true
    navigate = false

    local mx, my = mouse.mx, mouse.my
    local butt_h = math.floor(butt_h*pnl_scale)
    local fxdata = lvar.fxdata

    if MOUSE_click(obj.sections[4004]) then

      --CANCEL
      lvar.show_addstripdialog = false
      RedrawGUIBitmap()
      
      fxdata = nil

      reaper.MarkProjectDirty(0)
      insertstrip = nil
      loadstrip = nil

      navigate = true
      lupd.update_surface = true

    elseif MOUSE_click(obj.sections[4005]) then



    elseif MOUSE_click(obj.sections[4006]) then

      if lvar.livemode == 0 then
        lvar.addstripdialog_tracknum = lvar.addstripdialog_tracknum - 1
        if lvar.addstripdialog_tracknum < -1 then
          lvar.addstripdialog_tracknum = reaper.CountTracks(0)-1
        end
        local ofxdata = lvar.fxdata
        local fxdata = AddStripDialog_GetFxData()
        if #fxdata > 0 then

          fxdata.dx = ofxdata.dx
          fxdata.dy = ofxdata.dy
          fxdata.insertstrip = ofxdata.insertstrip
          fxdata.loadstrip = ofxdata.loadstrip
          fxdata.mode = ofxdata.mode

          AddStripDialog_UpdateSel(fxdata)
          lvar.fxdata = fxdata
          lvar.show_addstripdialog = true
          lupd.update_gfx = true
          RedrawGUIBitmap()
          
        end
      end

    elseif MOUSE_click(obj.sections[4007]) then

      if lvar.livemode == 0 then
        lvar.addstripdialog_tracknum = lvar.addstripdialog_tracknum + 1
        if lvar.addstripdialog_tracknum >= reaper.CountTracks(0) then
          lvar.addstripdialog_tracknum = -1
        end
        local ofxdata = lvar.fxdata
        local fxdata = AddStripDialog_GetFxData()
        if #fxdata > 0 then

          fxdata.dx = ofxdata.dx
          fxdata.dy = ofxdata.dy
          fxdata.insertstrip = ofxdata.insertstrip
          fxdata.loadstrip = ofxdata.loadstrip
          fxdata.mode = ofxdata.mode

          AddStripDialog_UpdateSel(fxdata)
          lvar.fxdata = fxdata
          lvar.show_addstripdialog = true
          lupd.update_gfx = true
          RedrawGUIBitmap()
          
        end
      end

    elseif MOUSE_click(obj.sections[4003]) then

      --ADD

      insertstrip = fxdata.insertstrip
      loadstrip = fxdata.loadstrip

      local tr = GetTrack(lvar.addstripdialog_tracknum or track_select)
      local min = reaper.TrackFX_GetCount(tr)
      for i = 1, #fxdata do
        if fxdata[i].fxguid then
          min = math.min(min, fxdata[i].fxnum)
        end
      end

      if fxdata.mode == 0 then
        local tnum, tguid

        if lvar.addstripdialog_tracknum ~= track_select then
          tnum = lvar.addstripdialog_tracknum
          tguid = GetTrackGUID(tr)
        end
        Strip_AddStrip(loadstrip,math.floor(fxdata.dx/lvar.zoom),math.floor(fxdata.dy/lvar.zoom),true, tnum, tguid, math.max(min,0), nil, fxdata)
        fxdata = nil

        reaper.MarkProjectDirty(0)
        insertstrip = nil
        loadstrip = nil
        PopulateUsedTracksTable()

        if stripgallery_view == 1 then
          stlay_data = AutoSnap_GetStripLocs(true)
        end

      elseif fxdata.mode == 1 then
        local c = Switchers_FindCtl(insertstrip.target)
        if c then

          if lvar.livemode ~= 2 then
            local swok = Switcher_AddStrip(nil, c, loadstrip, fxdata)
            if swok ~= true then
              local strip = tracks[track_select].strip
              local ctls = strips[strip][page].controls
              Switcher_DeleteExt(ctls[c].switcherid)
            end
          else
            --local trn = lvar.dynamicmode_trn

            local extpos = switchers[insertstrip.target].extendpos
            local trn = lvar.dynamicmode_trn

            local pos = DM_Switcher_GetFXPos(insertstrip.target) or 0

            --[[local pos = 0
            --local extmax = Switcher_Ext_GetMaxPos(extid)
            local extid = switchers[insertstrip.target].extendid
            local tfxguids = GetTrackFXGUIDs(trn)

            for i = 1, extpos-1 do

              local fxguids = Switchers_GetFXGUIDs(extid, i)
              for fg = 1, #fxguids do
                if tfxguids[fxguids[fg] ] then

                  pos = pos + 1

                end
              end

            end
            --DBG(pos)]]
            local fx = pos
            --local fx = extpos-1            
            local swok = Switcher_AddStrip(nil, c, loadstrip, fxdata, trn, fx, nil, true)
            local extid = switchers[insertstrip.target].extendid
            Strip_ReposSwitcher_Ext(extid, 1)
            UpdateControlValues3(nil, ctls_upd, ctls_orr)
            DM_RefreshFX()

            DM_RefreshPage()
            DM_StoreStripData()
          end
        end
        insertstrip = nil
        loadstrip = nil

      elseif fxdata.mode == 2 then

        local switchid, switchid2
        local strip = tracks[track_select].strip
        local ctls = strips[strip][page].controls
        for i = 1, #ctls do
          if ctls[i].ctlcat == ctlcats.switcher then
            local swid = ctls[i].switcherid
            if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
              switchid = swid
              break
            end
          end
        end

        local extid
        local maxpos = 0
        if switchid then
          extid = switchers[switchid].extendid
          maxpos = Switcher_Ext_GetMaxPos(extid)

          for s = 1, #switchers do
            if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
               switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
              switchid2 = s
              break
            end
          end
          if switchid2 and #switchers[switchid2].grpids > 0 then
            maxpos = maxpos + 1
          end
        end

        local c = Switchers_Ext_Insert(switchid, maxpos)
        local swok = Switcher_AddStrip(nil, c, loadstrip, fxdata)
        if swok ~= true then
          Switcher_DeleteExt(ctls[c].switcherid)
        end

        fxdata = nil
        insertstrip = nil
        loadstrip = nil

      end

      navigate = true
      lvar.show_addstripdialog = false
      RedrawGUIBitmap()
      
    elseif MOUSE_click(obj.sections[4001]) then
      local yp = math.floor((my - obj.sections[4001].y) / butt_h)+1 + afxdialogS_offset
      if fxdata[yp] then
        fxdata.sel = yp
        AddStripDialog_UpdateSel(fxdata)

        lupd.update_surface = true
      end
    elseif MOUSE_click(obj.sections[4002]) then
      if fxdata[fxdata.sel] then
        local yp = math.floor((my - obj.sections[4002].y) / butt_h) + afxdialogT_offset
        if fxdata.tfxi[yp] then

          if fxdata[fxdata.sel].fxguid == fxdata.tfxi[yp].fxguid then
            fxdata[fxdata.sel].fxguid = nil
            fxdata[fxdata.sel].fxfn = nil
            fxdata[fxdata.sel].fxname = nil
            fxdata[fxdata.sel].fxnum = nil
          else
            local fnd
            for f = 1, #fxdata do
              if fxdata[f].fxguid == fxdata.tfxi[yp].fxguid then
                fnd = f
                break
              end
            end
            if not fnd then
              fxdata[fxdata.sel].fxguid = fxdata.tfxi[yp].fxguid
              fxdata[fxdata.sel].fxfn = fxdata.tfxi[yp].fxfn
              fxdata[fxdata.sel].fxname = fxdata.tfxi[yp].fxname
              fxdata[fxdata.sel].fxnum = yp
            end
          end
          lupd.update_surface = true
          AddStripDialog_UpdateSel(fxdata)
        end
      end
    end

    return noscroll
  end

  function A_Run_TemplateChooser(noscroll, rt)

    local butt_h = butt_h*pnl_scale

    local mx, my = mouse.mx, mouse.my
    mouse.mx = mouse.mx-obj.sections[5050].x
    mouse.my = mouse.my-obj.sections[5050].y-5

    local p = math.floor((mouse.my-butt_h) / lvar.tempchooser.th) + lvar.template_strips_offs
    --if p then DBG(p) return end
    if p == 0 then

      local dmemd = lvar.dm_editmode_data_tmp
      local edit_trn = dmemd.edit_trn
      local pos = dmemd.pos
      local extid = dmemd.extid
      local track = GetTrackByName('__LBXEDIT')

      if plist_w == 0 then
        plist_w = oplist_w
        show_editbar = true
        resize_display = true
      end

      setmode(2)
      ChangeTrack2(edit_trn, 1)

      local strip = tracks[track_select].strip
      for fx = 0, reaper.TrackFX_GetCount(track)-1 do
        reaper.TrackFX_Delete(track, 0)
      end
      ClearPage(page, true)

      if pos then
        local srctrack = GetTrack(lvar.dynamicmode_trn)
        local fxguids = Switchers_GetFXGUIDs(extid, pos+1)
        if fxguids and fxguids[1] then
          local fxn = GetFXNFromGUID(srctrack, fxguids[1])
          if fxn then
            reaper.TrackFX_CopyToTrack(srctrack,fxn,track,0,false)
          end
        end
      end

      lvar.dm_editmode_data = dmemd
      lvar.dm_editmode_data_tmp = nil      
      lvar.show_templatechooser = nil
      RedrawGUIBitmap()

    elseif lvar.template_strips[p] then

      local dmemd = lvar.dm_editmode_data_tmp
      local edit_trn = dmemd.edit_trn
      local pos = dmemd.pos
      local extid = dmemd.extid
      local sfn = paths.strips_path..paths.templates_folder..'/'..lvar.template_strips[p].fn
      local track = GetTrackByName('__LBXEDIT')

      if plist_w == 0 then
        plist_w = oplist_w
        show_editbar = true
        resize_display = true
      end

      setmode(2)
      ChangeTrack2(edit_trn, 1)

      local strip = tracks[track_select].strip
      for fx = 0, reaper.TrackFX_GetCount(track)-1 do
        reaper.TrackFX_Delete(track, 0)
      end
      ClearPage(page, true)

      if pos then
        local srctrack = GetTrack(lvar.dynamicmode_trn)
        local fxguids = Switchers_GetFXGUIDs(extid, pos+1)
        if fxguids and fxguids[1] then
          local fxn = GetFXNFromGUID(srctrack, fxguids[1])
          if fxn then
            reaper.TrackFX_CopyToTrack(srctrack,fxn,track,0,false)
          end
        end
      end

      --load template
      local loadstrip = LoadStripFN(nil, sfn)
      if loadstrip then

        reaper.PreventUIRefresh(1)
        local w, h = GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
        local gs = settings_gridsize
        --local x = math.floor(obj.sections[10].w/2) - math.floor(w/2)
        --local y = math.floor(obj.sections[10].h/2) - math.floor(h/2)
        surface_offset.x = 0
        surface_offset.y = 0
        local x = math.floor(lvar.maxdim/2) - math.floor(w/2)
        local y = math.floor(lvar.maxdim/2) - math.floor(h/2)

        x = round(x/gs)*gs
        y = round(y/gs)*gs
        Strip_AddStrip(loadstrip,x,y,true, nil, nil, 1, nil, nil, nil, true)

        surface_offset.x = math.floor(1024-(obj.sections[10].w/2))
        surface_offset.y = math.floor(1024-(obj.sections[10].h/2))

        reaper.PreventUIRefresh(-1)

      end

      lvar.dm_editmode_data = dmemd
      lvar.dm_editmode_data_tmp = nil
      lvar.show_templatechooser = nil
      CentreAllControls(track_select)
      --RedrawGUIBitmap()
      
    end
    mouse.mx, mouse.my = mx, my
    return noscroll
  end

  function A_Run_ModAss(noscroll, rt)
    noscroll = true

    local mx, my = mouse.mx, mouse.my
    mouse.mx = mouse.mx-obj.sections[1125].x
    mouse.my = mouse.my-obj.sections[1125].y

    if MOUSE_click(obj.sections[1127]) then

      local modass = lvar.modass
      if modass then

        local offs = modass.offset
        local strip = tracks[track_select].strip

        local mmx = mouse.mx-obj.sections[1127].x
        local mmy = mouse.my-obj.sections[1127].y

        local butt_h = math.floor(butt_h*pnl_scale)+2
        local bw = 150
        local bwc = math.max(math.floor(obj.sections[1127].w / bw),1)
        local but_cx = math.floor(obj.sections[1127].w / bwc)
        local but_cy = math.max(math.floor(obj.sections[1127].h / butt_h),1)

        local px = math.floor(mmx / but_cx)
        local py = math.floor(mmy / butt_h)

        if py < but_cy then

          local p = px*but_cy + py + 1
          if modass[p+offs] and modass[p+offs].c then

            local ctl = strips[strip][page].controls[modass[p+offs].c]
            if ctl.mod then
              Mod_RemoveAssign(strip,page,modass[p+offs].c)
              ctl.mod = nil
            else
              DragMod_Assign(mod_select,modass[p+offs].c)
            end
            lupd.update_surface = true
            lupd.update_sidebar = true
            if show_lfoedit == true and modwinsz.minimized ~= true then
              lupd.update_lfoedit = true
            end
          end

        end

      end

    elseif MOUSE_click_RB(obj.sections[1127]) then
      show_modass = false
      lupd.update_surface = true
      RedrawGUIBitmap()
    end

    mouse.mx, mouse.my = mx, my
    return noscroll
  end

  function A_Run_EQControl(noscroll, rt)

    if strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[eqcontrol_select] and
       strips[tracks[track_select].strip][page].controls[eqcontrol_select].ctlcat == ctlcats.eqcontrol then

      --EQC_UpdateVals()

      local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands

      local xywh = {x = obj.sections[300].x+obj.sections[351].x,
                    y = obj.sections[300].y+obj.sections[351].y,
                    w = obj.sections[351].w,
                    h = obj.sections[351].h}
      if mouse.context == nil and MOUSE_click(xywh) then

        navigate = true
        show_eqcontrol = false
        eq_edit = false
        eqcontrolband_select = nil
        lupd.update_gfx = true
        RedrawGUIBitmap()
      end

      local mx, my = mouse.mx, mouse.my
      mouse.mx, mouse.my = mouse.mx - obj.sections[300].x, mouse.my - obj.sections[300].y

      local xywh_pmin, xywh_pmax,xywh_gmin, xywh_gmax, xywh_main
      if bands then
        if eqcontrolband_select and bands[eqcontrolband_select] and
           bands[eqcontrolband_select].freq_param then

          local xmin = nz(bands[eqcontrolband_select].posmin,0)
          local xmax = nz(bands[eqcontrolband_select].posmax,1)

          xywh_pmin = {x = obj.sections[302].x + (xmin * obj.sections[302].w) - 4,
                       y = obj.sections[302].y + obj.sections[302].h + 2,
                       w = 8,
                       h = 8}
          xywh_pmax = {x = obj.sections[302].x + (xmax * obj.sections[302].w) - 4,
                       y = obj.sections[302].y + obj.sections[302].h + 2,
                       w = 8,
                       h = 8}

          local ymin = nz(bands[eqcontrolband_select].gmin,0)
          local ymax = nz(bands[eqcontrolband_select].gmax,1)

          xywh_gmin = {x = obj.sections[302].x-12,
                       y = obj.sections[302].y+obj.sections[302].h - (ymin * obj.sections[302].h) - 4,
                       w = 8,
                       h = 8}
          xywh_gmax = {x = obj.sections[302].x-12,
                       y = obj.sections[302].y+obj.sections[302].h - (ymax * obj.sections[302].h) - 4,
                       w = 8,
                       h = 8}
        end
      end

      local xywh_main = {x = obj.sections[302].x-10,
                         y = obj.sections[302].y-10,
                         w = obj.sections[302].w+20,
                         h = obj.sections[302].h+20}

      if gfx.mouse_wheel ~= 0 then
        if MOUSE_over(xywh_main) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)

          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].q_param

            if param then
              local mw = mousewheel_val()
              if bands[eqcontrolband_select].q_inv then
                mw = -mw
              end
              local v = F_limit(bands[eqcontrolband_select].q_val + (mw*0.05),0,1)

              if v ~= ov then
                reaper.TrackFX_SetParam(track,fxnum,param,v)
                ov = v
                lupd.update_eqcontrol = true
              end
            end
          end

        elseif MOUSE_over(obj.sections[303]) then
          local mw = mousewheel_val()
          eqcontrolband_select = F_limit(eqcontrolband_select + mw,1,#bands)
          lupd.update_gfx = true

        elseif MOUSE_over(obj.sections[325]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].freq_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].freq_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[326]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].gain_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].gain_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[327]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].q_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.05
            if mouse.shift then
              mult = 0.005
            end

            v = F_limit(bands[eqcontrolband_select].q_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[328]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].c1_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].c1_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[329]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].c2_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].c2_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[330]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].c3_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].c3_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[334]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].c4_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].c4_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        elseif MOUSE_over(obj.sections[335]) then

          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].c5_param

          if param then
            local mw = mousewheel_val()

            local v
            local mult = 0.015
            if mouse.shift then
              mult = 0.001
            end

            v = F_limit(bands[eqcontrolband_select].c5_val + (mw*mult),0,1)
            if v ~= ov then
              reaper.TrackFX_SetParam(track,fxnum,param,v)
              ov = v
              lupd.update_eqcontrol = true
            end
          end
          gfx.mouse_wheel = 0

        end

      end

      if eq_edit and xywh_pmin and mouse.context == nil and eqcontrolband_select and MOUSE_click(xywh_pmin) then
        mouse.context = contexts.eqc_pminslider
        draggraph = true
      elseif eq_edit and xywh_pmax and mouse.context == nil and eqcontrolband_select and MOUSE_click(xywh_pmax) then
        mouse.context = contexts.eqc_pmaxslider
        draggraph = true

      elseif eq_edit and xywh_gmin and mouse.context == nil and eqcontrolband_select and MOUSE_click(xywh_gmin) then
        mouse.context = contexts.eqc_gminslider
        --draggraph = true
      elseif eq_edit and xywh_gmax and mouse.context == nil and eqcontrolband_select and MOUSE_click(xywh_gmax) then
        mouse.context = contexts.eqc_gmaxslider
        --draggraph = true
      elseif mouse.context == nil and (MOUSE_click(xywh_main) or MOUSE_click_RB(xywh_main)) then
        local bs
        if bands then
          for b = 1, #bands do

            if eq_single == false or b == eqcontrolband_select then
              local fv = bands[b].freq_val
              local gv = bands[b].gain_val
              local xmin = bands[b].posmin
              local xmax = bands[b].posmax
              local ymin = bands[b].gmin
              local ymax = bands[b].gmax

              if eq_scale == false then
                xmin = 0
                xmax = 1
                ymin = 0
                ymax = 1
              end

              if fv and gv then
                local xp = (fv * (xmax-xmin)*obj.sections[302].w)+(xmin*obj.sections[302].w)
                if bands[b].gain_inv then
                  gv = 1-gv
                end
                local yp = obj.sections[302].h-(ymin*obj.sections[302].h) - (gv * (ymax-ymin)*obj.sections[302].h)
                --local yp = obj.sections[302].h - (gv * obj.sections[302].h)

                local xywh = {}
                xywh.x = obj.sections[302].x + xp - 8
                xywh.y = obj.sections[302].y + yp - 8
                xywh.w = 16
                xywh.h = 16

                if MOUSE_over(xywh) then

                  if mouse.LB and mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2 then
                    EQC_SetDefault(b)
                    break
                  end

                  if mouse.RB then
                    if bands[b].bypass_param then
                      bands[b].bypass_val =
                            1-bands[b].bypass_val
                      EQC_SetParam(b,bands[b].bypass_param,
                                   bands[b].bypass_val)
                      lupd.update_gfx = true
                    end
                    break
                  elseif mouse.ctrl then
                    EQC_SetDefault(b)
                    break
                  else
                    bs = b
                    eqcdrag = {xoff = mouse.mx - xywh.x-8, yoff = mouse.my - xywh.y-8, xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, mx = mouse.mx, my = mouse.my}
                    lupd.update_gfx = true
                    break
                  end
                end
              end
            end

          end

          if bs then
            eqcontrolband_select = bs
            lupd.update_gfx = true
            mouse.context = contexts.eqc_drag
          end
        end

      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[325]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].freq_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].freq_def then
                EQC_SetParam(b, bands[b].freq_param, bands[b].freq_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[325].y}
              mouse.context = contexts.eqc_dragfreq
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[326]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].gain_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].gain_def then
                EQC_SetParam(b, bands[b].gain_param, bands[b].gain_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[326].y}
              mouse.context = contexts.eqc_draggain
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[327]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].q_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].q_def then
                EQC_SetParam(b, bands[b].q_param, bands[b].q_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[327].y}
              mouse.context = contexts.eqc_dragq
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[328]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].c1_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].c1_def then
                EQC_SetParam(b, bands[b].c1_param, bands[b].c1_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[328].y}
              mouse.context = contexts.eqc_dragc1
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[329]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].c2_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].c2_def then
                EQC_SetParam(b, bands[b].c2_param, bands[b].c2_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[329].y}
              mouse.context = contexts.eqc_dragc2
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[330]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].c3_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].c3_def then
                EQC_SetParam(b, bands[b].c3_param, bands[b].c3_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[330].y}
              mouse.context = contexts.eqc_dragc3
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[334]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].c4_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].c4_def then
                EQC_SetParam(b, bands[b].c4_param, bands[b].c4_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[334].y}
              mouse.context = contexts.eqc_dragc4
            end
          end
        end
      elseif eq_edit == false and mouse.context == nil and MOUSE_click(obj.sections[335]) then
        if bands and
           bands[eqcontrolband_select] then
          if bands[eqcontrolband_select].c5_param then
            if mouse.ctrl or(mouse.lastLBclicktime and (rt-mouse.lastLBclicktime) < 0.2) then
              local b = eqcontrolband_select
              if bands[b].c5_def then
                EQC_SetParam(b, bands[b].c5_param, bands[b].c5_def)
              end
            else
              eqcdraginf = {my = mouse.my, yoff = mouse.my - obj.sections[335].y}
              mouse.context = contexts.eqc_dragc5
            end
          end
        end

      elseif mouse.context == nil and MOUSE_click(obj.sections[304]) then

        EQC_LoadBand()

      elseif mouse.context == nil and MOUSE_click(obj.sections[311]) then
        eq_edit = not eq_edit
        if eqcontrolband_select == nil then
          eq_edit = false
        end
        lupd.update_gfx = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[320]) then
        eq_single = not eq_single
        if eq_single == true then
          eq_scale = false
        else
          eq_scale = true
        end
        lupd.update_gfx = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[321]) then
        eq_scale = not eq_scale
        lupd.update_gfx = true

      elseif mouse.context == nil and MOUSE_click(obj.sections[345]) then
        EQC_OpenEQs(eqcontrolband_select, true)
        --lupd.update_gfx = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[340]) then

        OpenEB(32,'Please enter EQ name:')

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[312]) then

        EQC_SaveBand()

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[315]) then

        EQC_DelBand()
        if #bands == 0 then
          eqcontrolband_select = nil
          eq_edit = false
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[313]) then

        EQC_SelectBandType()

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[314]) then

        OpenEB(30,'Please enter band name:')

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[355]) then

        if bands and bands[eqcontrolband_select] then
          local retval, c = reaper.GR_SelectColor(_,ConvertColorString(bands[eqcontrolband_select].col))
          if retval ~= 0 then
            if lvar.Mac_revcol then c = MacRevC(c) end
            bands[eqcontrolband_select].col = ConvertColor(c)
            lupd.update_gfx = true
          end
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[356]) then

        if bands and bands[eqcontrolband_select] then
          local fxnum = bands[eqcontrolband_select].fxnum
          local track = GetTrack(tracks[track_select].tracknum)

          local p = bands[eqcontrolband_select].freq_param
          if p then
            bands[eqcontrolband_select].freq_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].gain_param
          if p then
            bands[eqcontrolband_select].gain_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].q_param
          if p then
            bands[eqcontrolband_select].q_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].c1_param
          if p then
            bands[eqcontrolband_select].c1_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].c2_param
          if p then
            bands[eqcontrolband_select].c2_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].c3_param
          if p then
            bands[eqcontrolband_select].c3_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].c4_param
          if p then
            bands[eqcontrolband_select].c4_def = EQC_GetParam(track, fxnum, p)
          end
          p = bands[eqcontrolband_select].c5_param
          if p then
            bands[eqcontrolband_select].c5_def = EQC_GetParam(track, fxnum, p)
          end

          OpenMsgBox(1,'Default parameter values captured.',1)
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click_RB(obj.sections[355]) then

        if bands and bands[eqcontrolband_select] then
          local col = round(math.random()*255)..' '..round(math.random()*255)..' '..round(math.random()*255)
          bands[eqcontrolband_select].col = col
          lupd.update_gfx = true
        end

      elseif mouse.context == nil and (MOUSE_click(obj.sections[303]) or MOUSE_click_RB(obj.sections[303])) then

        if bands then
          local bw = obj.sections[303].w / 20
          local bs = math.floor((mouse.mx - obj.sections[303].x)/bw)+1
          if bs <= #bands then
            if mouse.ctrl or mouse.RB then
              if bands[bs].bypass_param then
                bands[bs].bypass_val =
                      1-bands[bs].bypass_val
                EQC_SetParam(bs,bands[bs].bypass_param,
                             bands[bs].bypass_val)
                lupd.update_gfx = true
              end
            else
              eqcontrolband_select = bs
            end
            lupd.update_gfx = true
          end
        end
      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[305]) and eqcontrolband_select then
        local track = GetTrack(tracks[track_select].tracknum)
        local fxcnt = reaper.TrackFX_GetCount(track)
        local mstr = ''
        for fxn = 1, fxcnt do
          local _, fxname = reaper.TrackFX_GetFXName(track, fxn-1, '')
          mstr = mstr..fxn..': '..fxname
          if fxn < fxcnt then
            mstr = mstr..'|'
          end
        end
        gfx.x, gfx.y = mouse.mx, mouse.my
        res = OpenMenu(mstr)
        if res ~= 0 then
          local _, fxname = reaper.TrackFX_GetFXName(track, res-1, '')
          local fxguid = reaper.TrackFX_GetFXGUID(track, res-1)
          bands[eqcontrolband_select] = {}
          bands[eqcontrolband_select].fxnum = res-1
          bands[eqcontrolband_select].fxguid = fxguid
          bands[eqcontrolband_select].fxname = fxname
          bands[eqcontrolband_select].posmin = 0
          bands[eqcontrolband_select].posmax = 1
          bands[eqcontrolband_select].gmin = 0
          bands[eqcontrolband_select].gmax = 1
          bands[eqcontrolband_select].col = '160 160 160'

          --[[local s = string.find(fxname,'ReaEQ')
          if s and s > 0 then
            OpenMsgBox(1,'ReaEQ is not recommended for use with EQ Control.', 1, 'Using ReaEQ will produce unexpected control and graph behaviour.')
          end ]]
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[322]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].bypass_param = nil
            bands[eqcontrolband_select].bypass_param_name = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].bypass_param = p
            bands[eqcontrolband_select].bypass_param_name = pname
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[323]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].c1_param = nil
            bands[eqcontrolband_select].c1_param_name = nil
            bands[eqcontrolband_select].c1_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].c1_param = p
            bands[eqcontrolband_select].c1_param_name = pname
            bands[eqcontrolband_select].c1_def = EQC_GetParam(track, fxnum, p)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[324]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].c2_param = nil
            bands[eqcontrolband_select].c2_param_name = nil
            bands[eqcontrolband_select].c2_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].c2_param = p
            bands[eqcontrolband_select].c2_param_name = pname
            bands[eqcontrolband_select].c2_def = EQC_GetParam(track, fxnum, p)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[331]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].c3_param = nil
            bands[eqcontrolband_select].c3_param_name = nil
            bands[eqcontrolband_select].c3_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].c3_param = p
            bands[eqcontrolband_select].c3_param_name = pname
            bands[eqcontrolband_select].c3_def = EQC_GetParam(track, fxnum, p)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[332]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].c4_param = nil
            bands[eqcontrolband_select].c4_param_name = nil
            bands[eqcontrolband_select].c4_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].c4_param = p
            bands[eqcontrolband_select].c4_param_name = pname
            bands[eqcontrolband_select].c4_def = EQC_GetParam(track, fxnum, p)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[333]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].c5_param = nil
            bands[eqcontrolband_select].c5_param_name = nil
            bands[eqcontrolband_select].c5_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].c5_param = p
            bands[eqcontrolband_select].c5_param_name = pname
            bands[eqcontrolband_select].c5_def = EQC_GetParam(track, fxnum, p)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[306]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].freq_param = nil
            bands[eqcontrolband_select].freq_param_name = nil
            bands[eqcontrolband_select].freq_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].freq_param = p
            bands[eqcontrolband_select].freq_param_name = pname
            bands[eqcontrolband_select].freq_def = EQC_GetParam(track, fxnum, p)

            bands[eqcontrolband_select].freq_min = nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, p, true),20)
            bands[eqcontrolband_select].freq_max = nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, p, true),24000)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[307]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].gain_param = nil
            bands[eqcontrolband_select].gain_param_name = nil
            bands[eqcontrolband_select].gain_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local p = res - 1
            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, p, '')
            bands[eqcontrolband_select].gain_param = p
            bands[eqcontrolband_select].gain_param_name = pname
            bands[eqcontrolband_select].gain_def = EQC_GetParam(track, fxnum, p)

            bands[eqcontrolband_select].gain_min = nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, p),-20)
            bands[eqcontrolband_select].gain_max = nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, p),20)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[308]) and eqcontrolband_select then
        local res = EQC_SelectParam()
        if res ~= 0 then
          if res == -1 then
            bands[eqcontrolband_select].q_param = nil
            bands[eqcontrolband_select].q_param_name = nil
            bands[eqcontrolband_select].q_def = nil
          else
            local fxnum = bands[eqcontrolband_select].fxnum
            local track = GetTrack(tracks[track_select].tracknum)

            local _, pname = reaper.TrackFX_GetParamName(track, fxnum, res-1, '')
            bands[eqcontrolband_select].q_param = res-1
            bands[eqcontrolband_select].q_param_name = pname
            bands[eqcontrolband_select].q_def = EQC_GetParam(track, fxnum, res-1)
          end
          lupd.update_gfx = true
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[337]) and eqcontrolband_select then
        mouse.context = contexts.auto_delayslider
        autodelay = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[336]) and eqcontrolband_select then

        bands[eqcontrolband_select].lookmap = nil
        bands[eqcontrolband_select].gmap = nil
        lupd.update_gfx = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[357]) then
        if bands and #bands > 0 then

          for b = 1,#bands do
            EQC_AlignGraph(b)
          end
          lupd.update_gfx = true

        end

      elseif eq_edit and mouse.context == nil and MOUSE_click_RB(obj.sections[309]) and eqcontrolband_select then
        if bands[eqcontrolband_select].fxnum then
          if bands[eqcontrolband_select].freq_param then

            if bands[eqcontrolband_select].lookmap and
               mouse.ctrl == false then
              EQC_AlignGraph(eqcontrolband_select,2)
            end
          end
        end
      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[309]) and eqcontrolband_select then
        if bands[eqcontrolband_select].fxnum then
          if bands[eqcontrolband_select].freq_param then

            if bands[eqcontrolband_select].lookmap and
               mouse.ctrl == false then
              EQC_AlignGraph(eqcontrolband_select,1)
            else
              local fxnum = GetEQC_FXNum(eqcontrolband_select)
              if fxnum ~= -1 then
                local param = bands[eqcontrolband_select].freq_param
                local param2 = bands[eqcontrolband_select].gain_param

                --EQC_OpenEQs(eqcontrolband_select, true)

                --[[strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].freq_min =
                                                                    nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, param),20)
                strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].freq_max =
                                                                    nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, param, true),24000)]]

                local min = nz(bands[eqcontrolband_select].freq_min,20)
                local max = nz(bands[eqcontrolband_select].freq_max,24000)
                local khz = bands[eqcontrolband_select].khz

                --[[strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gain_min =
                                                                    nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, param2),-20)
                strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gain_max =
                                                                    nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, param2),20)]]

                local min2 = nz(bands[eqcontrolband_select].gain_min,-20)
                local max2 = nz(bands[eqcontrolband_select].gain_max,20)

                local lm, gm = calc_eqgraph(tracks[track_select].tracknum,fxnum,param,min,max,khz,param2,min2,max2)
                bands[eqcontrolband_select].lookmap = lm
                bands[eqcontrolband_select].gmap = gm

                --EQC_OpenEQs(eqcontrolband_select, false)

                EQC_AlignGraph(eqcontrolband_select,1)

                if bands[eqcontrolband_select].posmax > 1 then
                  bands[eqcontrolband_select].posmax = 1
                end
              end
              lupd.update_gfx = true
            end
          end
        end

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[310]) and eqcontrolband_select then
        --strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph = eqcontrolband_select
        --strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph = EQC_SetMain(eqcontrolband_select)
        OpenMsgBox(2,'Save/overwrite default eq graph?',2)
        lupd.update_gfx = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[317]) and eqcontrolband_select then
        bands[eqcontrolband_select].gain_inv = not bands[eqcontrolband_select].gain_inv
        lupd.update_gfx = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[318]) and eqcontrolband_select then
        bands[eqcontrolband_select].q_inv = not bands[eqcontrolband_select].q_inv
        lupd.update_gfx = true

      elseif eq_edit and mouse.context == nil and MOUSE_click(obj.sections[316]) and eqcontrolband_select then
        bands[eqcontrolband_select].khz = not bands[eqcontrolband_select].khz
        lupd.update_gfx = true

      end

      noscroll = true
      mouse.mx, mouse.my = mx, my
    
    else

      navigate = true
      show_eqcontrol = false
      eq_edit = false
      eqcontrolband_select = nil
      lupd.update_gfx = true
      RedrawGUIBitmap()
    end

    return noscroll

  end

  function A_Run_EQControl2(rt, noscroll)
    
    if strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[eqcontrol_select] and
       strips[tracks[track_select].strip][page].controls[eqcontrol_select].ctlcat == ctlcats.eqcontrol then
    
      EQC_UpdateVals()

      local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
      
      local mx, my = mouse.mx, mouse.my
      mouse.mx, mouse.my = mouse.mx - obj.sections[300].x, mouse.my - obj.sections[300].y
      
      if mouse.context then
      
        if mouse.context == contexts.eqc_drag then
        
          local mmx, fv, yy, gv
          if mouse.shift == true then
            fv = bands[eqcontrolband_select].freq_val
            gv = bands[eqcontrolband_select].gain_val
    
            local dx = mouse.mx - eqcdrag.mx
            local dy = mouse.my - eqcdrag.my
    
            fv = F_limit(fv + (dx*0.0001),0,1)
            gv = F_limit(gv - (dy*0.0001),0,1)
    
            eqcdrag.mx = mouse.mx
            eqcdrag.my = mouse.my
    
          else
            mmx = (mouse.mx-eqcdrag.xoff)-(obj.sections[302].x)
            fv = F_limit((mmx-(eqcdrag.xmin*obj.sections[302].w))/((eqcdrag.xmax-eqcdrag.xmin)*obj.sections[302].w),0,1)
    
            yy = obj.sections[302].y+(obj.sections[302].h-(eqcdrag.ymax * obj.sections[302].h))
            gv = (mouse.my-eqcdrag.yoff-yy)/((eqcdrag.ymax-eqcdrag.ymin)*obj.sections[302].h)
    
            gv = F_limit(1-gv,0,1)
    
            if bands[eqcontrolband_select].gain_inv then
              gv = 1-gv
            end
          end
    
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].freq_param
            if param and fv ~= ofv then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,fv)
    
              lupd.update_eqcontrol = true
              ofv = fv
            end
    
            param = bands[eqcontrolband_select].gain_param
            if param and gv ~= ogv then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,gv)
    
              lupd.update_eqcontrol = true
              ogv = gv
            end
          end
        elseif mouse.context == contexts.eqc_dragfreq then
    
          local v = bands[eqcontrolband_select].freq_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].freq_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
        elseif mouse.context == contexts.eqc_draggain then
    
          local v = bands[eqcontrolband_select].gain_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].gain_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragq then
    
          local v = bands[eqcontrolband_select].q_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].q_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragc1 then
    
          local v = bands[eqcontrolband_select].c1_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].c1_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragc2 then
    
          local v = bands[eqcontrolband_select].c2_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].c2_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragc3 then
    
          local v = bands[eqcontrolband_select].c3_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].c3_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragc4 then
    
          local v = bands[eqcontrolband_select].c4_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].c4_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_dragc5 then
    
          local v = bands[eqcontrolband_select].c5_val
          local dy = mouse.my - eqcdraginf.my
          if mouse.shift then
            v = F_limit(v-(dy*0.0002),0,1)
          else
            v = F_limit(v-(dy*0.0015),0,1)
          end
          local track = GetTrack(tracks[track_select].tracknum)
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
    
          if fxnum ~= -1 then
            local param = bands[eqcontrolband_select].c5_param
            if param and v ~= ov then
              reaper.TrackFX_SetParamNormalized(track,fxnum,param,v)
    
              lupd.update_eqcontrol = true
              ov = v
            end
            eqcdraginf.my = mouse.my
          end
    
        elseif mouse.context == contexts.eqc_pminslider then
          local xx = mouse.mx - obj.sections[302].x
          local pos = F_limit((xx / obj.sections[302].w),0,bands[eqcontrolband_select].posmax-0.01)
    
          if mouse.shift then
            local posdif = pos-bands[eqcontrolband_select].posmin
            local posm = bands[eqcontrolband_select].posmax + posdif
            if posm < 1 then
              bands[eqcontrolband_select].posmax = posm
              bands[eqcontrolband_select].posmin = pos
            else
              posdif = posm - 1
              posm = 1
              pos = pos - posdif
              bands[eqcontrolband_select].posmax = posm
              bands[eqcontrolband_select].posmin = pos
            end
          else
            bands[eqcontrolband_select].posmin = pos
          end
          lupd.update_gfx = true
    
        elseif mouse.context == contexts.eqc_pmaxslider then
          local xx = mouse.mx - obj.sections[302].x
          local pos = F_limit((xx / obj.sections[302].w),bands[eqcontrolband_select].posmin+0.01,1)
    
          if mouse.shift then
            local posdif = pos-bands[eqcontrolband_select].posmax
            local posm = bands[eqcontrolband_select].posmin + posdif
            if posm > 0 then
              bands[eqcontrolband_select].posmin = posm
              bands[eqcontrolband_select].posmax = pos
            else
              posdif = -posm
              posm = 0
              pos = pos + posdif
              bands[eqcontrolband_select].posmin = posm
              bands[eqcontrolband_select].posmax = pos
            end
          else
            bands[eqcontrolband_select].posmax = pos
          end
          lupd.update_gfx = true
    
        elseif mouse.context == contexts.eqc_gminslider then
          local yy = mouse.my - obj.sections[302].y
    
          local pos = 1-F_limit((yy / obj.sections[302].h),0,1)
    
          --[[if pos > strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gmax - 0.01 then
            pos = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gmax - 0.01
          end]]
          if pos > 0.5 then pos = 0.5 end
    
          if mouse.shift then
            bands[eqcontrolband_select].gmin = pos
          else
            bands[eqcontrolband_select].gmin = pos
            bands[eqcontrolband_select].gmax = 1-pos
          end
          lupd.update_gfx = true
    
        elseif mouse.context == contexts.eqc_gmaxslider then
          local yy = mouse.my - obj.sections[302].y
    
          local pos = 1-F_limit((yy / obj.sections[302].h),0,1)
    
          --[[if pos < strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gmin + 0.01 then
            pos = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].gmin + 0.01
          end   ]]
          if pos < 0.5 then pos = 0.5 end
    
          if mouse.shift then
            bands[eqcontrolband_select].gmax = pos
          else
            bands[eqcontrolband_select].gmax = pos
            bands[eqcontrolband_select].gmin = 1-pos
          end
          lupd.update_gfx = true
    
        elseif mouse.context == contexts.auto_delayslider then
          local val = F_limit(MOUSE_sliderHBar(obj.sections[337]),0,1)
          if val ~= nil then
            auto_delay = math.floor(val * 10)
            lupd.update_gfx = true
          end
        end
      
      else 
      
        if autodelay then
          autodelay = nil
          local fxnum = GetEQC_FXNum(eqcontrolband_select)
          local param = bands[eqcontrolband_select].freq_param
          local param2 = bands[eqcontrolband_select].gain_param
          bands[eqcontrolband_select].freq_min = nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, param, true),20)
          bands[eqcontrolband_select].freq_max = nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, param, true),24000)
          bands[eqcontrolband_select].gain_min = nz(calc_eqgraph_getmin(tracks[track_select].tracknum, fxnum, param2),-20)
          bands[eqcontrolband_select].gain_max = nz(calc_eqgraph_getmax(tracks[track_select].tracknum, fxnum, param2),20)
          lupd.update_gfx = true
  
        elseif eqcdrag then
          eqcdrag = nil
          lupd.update_gfx = true
        elseif draggraph then
          draggraph = nil
          lupd.update_gfx = true
        end
        
      end

      noscroll = true
      mouse.mx, mouse.my = mx, my
                    
    end
    
    return noscroll
    
  end

  function A_Run_InsertStrip()

    insertstrip.x = mouse.mx
    insertstrip.y = mouse.my

    if not mouse.shift and (lvar.livemode == 0 or mode ~= 0) then
      nx = surface_offset.x - (math.floor(surface_offset.x/settings_gridsize)*settings_gridsize)
      ny = surface_offset.y - (math.floor(surface_offset.y/settings_gridsize)*settings_gridsize)
      insertstrip.x = math.floor((insertstrip.x-obj.sections[10].x+surface_offset.x+nx)/settings_gridsize)*settings_gridsize -surface_offset.x+obj.sections[10].x-insertstrip.dx
      insertstrip.y = math.floor((insertstrip.y-obj.sections[10].y+surface_offset.y+ny)/settings_gridsize)*settings_gridsize -surface_offset.y+obj.sections[10].y-insertstrip.dy
    end

    if insertstrip.dragmode ~= true then
      if show_stripbrowser and MOUSE_click(obj.sections[1350]) then
        --cancel
        insertstrip = nil
        loadstrip = nil

      elseif MOUSE_click(obj.sections[10]) then
        --drop
        local dx, dy = insertstrip.x-obj.sections[10].x, insertstrip.y-obj.sections[10].y+math.floor(insertstrip.dy/settings_gridsize)*settings_gridsize
        Strip_AddStrip(loadstrip,dx,dy,true)
        
        lupd.update_gfx = true
        reaper.MarkProjectDirty(0)
        insertstrip = nil

        PopulateUsedTracksTable()

        if stripgallery_view == 1 then
          stlay_data = AutoSnap_GetStripLocs(true)
        end
        loadstrip = nil

      elseif mouse.RB then --MOUSE_click_RB(obj.sections[10]) then
        --cancel
        insertstrip = nil
        loadstrip = nil
      end

    elseif --[[mouse.context and]] mouse.context == contexts.sb_dragstrip2 then

      if mouse.RB then
        mouse.context = nil
        sb_drag = nil
        insertstrip = nil
        lupd.update_surface = true
      else

        if lvar.livemode == 0 then
          if insertstrip then
            insertstrip.alpha = math.min((insertstrip.alpha or 0)+0.15,0.8)
          end
        elseif lvar.livemode >= 1 then
          if insertstrip then
            insertstrip.alpha = math.min((insertstrip.alpha or 0)+0.15,0.8)
          end
          if CheckOver10() then
            Surface_EdgeDrag()
            local strip = tracks[track_select].strip
            local ctls = strips[strip][page].controls

            local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)
            local stripids = sb_drag.drags.stripids
            local locs = sb_drag.drags.locs
            local dst_switchid
            if stripid then
              dst_switchid = stripids[stripid]
            elseif c then
              local ctl = ctls[c]
              if ctl.ctlcat == ctlcats.switcher then
                if switchers[ctl.switcherid].switchmode == 1 and
                   switchers[ctl.switcherid].extendmode == true then
                   dst_switchid = ctl.switcherid
                end
              end
            end
            local ob = insertstrip.before

            local oldpos, newpos
            if dst_switchid then
              --oldpos = switchers[lvar.dragswitcher.selected].extendpos
              newpos = switchers[dst_switchid].extendpos
            end

            if dst_switchid then
              if oldpos == newpos - 1 then
                insertstrip.before = nil
              elseif oldpos == newpos + 1 then
                insertstrip.before = true
              else
                if lvar.livemode == 0 then
                  local yy = mouse.my + surface_offset.y - obj.sections[10].y
                  if yy < locs[dst_switchid].t + math.floor((locs[dst_switchid].b - locs[dst_switchid].t)/2) then
                    insertstrip.before = true
                  else
                    insertstrip.before = nil
                  end
                else
                  if lvar.showpop and lvar.popout_autoarrange then
                    local o10x = obj.sections[10].x
                    local pop = strips[strip][page].pop
                    local pidx = strips[strip][page].popidx[dst_switchid]
                    local popp = pop[pidx]
                    
                    --need to loop as not all strips may be visible
                    --[[for i = 1, #pop do
                      if dst_switchid == pop[i].swid then
                        popp = pop[i]
                        break
                      end
                    end]]
                    if popp then
                      local swdata = lvar.stripdim.swdata
                      local xp = mouse.mx - popp.x - o10x
                      local w = (swdata[dst_switchid].r - swdata[dst_switchid].l)*lvar.zoom
                      if xp < w/2 then
                        insertstrip.before = true
                      else
                        insertstrip.before = nil
                      end
                    end
                    insertstrip.pop = popp
                    
                  else
                    if lvar.mixmodedir == 0 then
                      local yy = mouse.my
                      local spos = lvar.spos[dst_switchid]
                      if spos then
                        if yy < spos.y + math.floor((spos.h)/2) then
                          insertstrip.before = true
                        else
                          insertstrip.before = nil
                        end
                      end
                    else
                      local xx = mouse.mx
                      local spos = lvar.spos[dst_switchid]
                      if spos then
                        if xx < spos.x + math.floor((spos.w)/2) then
                          insertstrip.before = true
                        else
                          insertstrip.before = nil
                        end
                      end
                    end
                  end
                end
              end
            end
            --DBG(tostring(dst_switchid)..'  '..tostring(insertstrip.before))
            
            insertstrip.target = dst_switchid
            if dst_switchid and (dst_switchid ~= oswid or insertstrip.before ~= ob or mouse.shift ~= isoms or mouse.alt ~= isoma) then
              if oswid and switchers[oswid] and switchers[oswid].dragging then
                switchers[oswid].dragging = nil
                lupd.update_surface = true
              end
              if mouse.shift or mouse.alt and not switchers[dst_switchid].dragging then
                switchers[dst_switchid].dragging = true
                lupd.update_surface = true
              end
              oswid = dst_switchid
              --lvar.dragswitcher.target = dst_switchid
              --lupd.update_surface = true
            elseif not dst_switchid then
              if oswid and switchers[oswid] and switchers[oswid].dragging then
                switchers[oswid].dragging = nil
                oswid = nil
                lupd.update_surface = true
              end
            end
            if isdt ~= insertstrip.target or isdb ~= insertstrip.before then
              lupd.update_surface = true
              isdt = insertstrip.target
              isdb = insertstrip.before
            end

            if lvar.livemode == 2 and lvar.showpop and lvar.popout_autoarrange then
              if gfx.mouse_wheel ~= 0 then
                if gfx.mouse_wheel < 0 then
                  MixMode_Swipe_Pop(0, false)
                else
                  MixMode_Swipe_Pop(1, false)
                end
                gfx.mouse_wheel = 0
              end
            end

            --DBG(lupd.update_surface)
          end
        end
        if not CheckOver10() then
          if oswid and switchers[oswid].dragging then
            switchers[oswid].dragging = nil
            lupd.update_surface = true
          end
          if insertstrip and insertstrip.target and switchers[insertstrip.target].dragging then
            switchers[insertstrip.target].dragging = nil
            lupd.update_surface = true
          end
          mouse.context = contexts.sb_dragstrip
          if sb_drag then
            if lvar.livemode >= 1 and sb_drag.showpop == true then
              ShowPop(true, nil, true)
            end
            sb_drag.alpha = 0
          end
          oswid = nil
        end

        if lvar.livemode == 0 then
          lupd.update_surface = true
        end
      end

    elseif mouse.context == nil and insertstrip then

      if CheckOver10() then

        if lvar.livemode >= 1 then
          if oswid and switchers[oswid] and switchers[oswid].dragging then
            switchers[oswid].dragging = nil
            lupd.update_surface = true
          end
          if insertstrip and insertstrip.target and switchers[insertstrip.target].dragging then
            switchers[insertstrip.target].dragging = nil
            lupd.update_surface = true
          end

          if not lvar.livemode == 2 and (mouse.shift or mouse.alt) then

            if insertstrip.target then
              --switchers[insertstrip.target].dragging = nil
              local c = Switchers_FindCtl(insertstrip.target)
              if c then
                if mouse.shift and not mouse.alt then
                  local c = Switchers_FindCtl(insertstrip.target)
                  if c then
                    local swok = Switcher_AddStrip(nil, c, loadstrip)
                    if swok ~= true then
                      local strip = tracks[track_select].strip
                      local ctls = strips[strip][page].controls
                      Switcher_DeleteExt(ctls[c].switcherid)
                    end
                  end
                else
                  --addstripdialog
                  lvar.addstripdialog_tracknum = track_select
                  local fxdata = AddStripDialog_GetFxData()
                  if #fxdata > 0 then

                    fxdata.dx = dx
                    fxdata.dy = dy
                    fxdata.insertstrip = insertstrip
                    fxdata.loadstrip = loadstrip
                    --if mouse.shift and mouse.alt then
                      fxdata.mode = 1
                    --else
                    --  fxdata.mode = 2
                    --end
                    AddStripDialog_UpdateSel(fxdata)
                    lvar.fxdata = fxdata
                    lvar.show_addstripdialog = true
                    lupd.update_gfx = true
                    retain = true
                    RedrawGUIBitmap()
                    
                  end
                end
              end
            else
              --addstripdialog
              lvar.addstripdialog_tracknum = track_select
              local fxdata = AddStripDialog_GetFxData()
              if #fxdata > 0 then

                fxdata.dx = dx
                fxdata.dy = dy
                fxdata.insertstrip = insertstrip
                fxdata.loadstrip = loadstrip
                fxdata.mode = 2

                AddStripDialog_UpdateSel(fxdata)
                lvar.fxdata = fxdata
                lvar.show_addstripdialog = true
                lupd.update_gfx = true
                retain = true
                RedrawGUIBitmap()
                
              end
            end

          else
            if insertstrip.target then
              --switchers[insertstrip.target].dragging = nil

              if mouse.shift and not mouse.alt then
                local c = Switchers_FindCtl(insertstrip.target)
                if c then
                  if lvar.livemode == 2 then
                    local extpos = switchers[insertstrip.target].extendpos
                    local trn = lvar.dynamicmode_trn

                    local pos = 0
                    --local extmax = Switcher_Ext_GetMaxPos(extid)
                    local extid = switchers[insertstrip.target].extendid
                    local tfxguids = GetTrackFXGUIDs(trn)

                    for i = 1, extpos-1 do

                      local fxguids = Switchers_GetFXGUIDs(extid, i)
                      for fg = 1, #fxguids do
                        if tfxguids[fxguids[fg]] then

                          pos = pos + 1

                        end
                      end

                    end
                    --DBG(pos)
                    local fx = pos
                    --local fx = extpos-1
                    local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, nil, true)
                    local extid = switchers[insertstrip.target].extendid
                    Strip_ReposSwitcher_Ext(extid, 1)
                    UpdateControlValues3(nil, ctls_upd, ctls_orr)
                    DM_RefreshFX()

                    --if lvar.livemode == 2 then
                      DM_StoreStripData()
                    --end
                  else
                    local swok = Switcher_AddStrip(nil, c, loadstrip)
                    if swok ~= true then
                      local strip = tracks[track_select].strip
                      local ctls = strips[strip][page].controls
                      Switcher_DeleteExt(ctls[c].switcherid)
                    end
                  end
                end

              elseif mouse.alt then --remove until working
                --addstripdialog
                lvar.addstripdialog_tracknum = lvar.dynamicmode_trn
                lvar.show_addstripdialog = true
                
                local fxdata = AddStripDialog_GetFxData(lvar.dynamicmode_trn, nil, insertstrip.target)
                if #fxdata > 0 then

                  fxdata.dx = dx
                  fxdata.dy = dy
                  fxdata.insertstrip = insertstrip
                  fxdata.loadstrip = loadstrip
                  fxdata.mode = 1
                  AddStripDialog_UpdateSel(fxdata)
                  lvar.fxdata = fxdata
                  lupd.update_gfx = true
                  retain = true
                  RedrawGUIBitmap()
                  
                else
                  lvar.show_addstripdialog = false
                  RedrawGUIBitmap()                  
                end
              else
                local extpos = switchers[insertstrip.target].extendpos
                if extpos then

                  if insertstrip.before ~= true then
                    extpos = extpos + 1
                  end
                  local strip = tracks[track_select].strip
                  local ctls = strips[strip][page].controls
                  local c = Switchers_Ext_Insert(insertstrip.target, extpos)

                  if lvar.livemode == 2 then

                    local trn = lvar.dynamicmode_trn

                    local pos = 0
                    --local extmax = Switcher_Ext_GetMaxPos(extid)
                    local extid = switchers[insertstrip.target].extendid
                    local tfxguids = GetTrackFXGUIDs(trn)

                    for i = 1, extpos-1 do

                      local fxguids = Switchers_GetFXGUIDs(extid, i)
                      for fg = 1, #fxguids do
                        if tfxguids[fxguids[fg]] then

                          pos = pos + 1

                        end
                      end

                    end
                    --DBG(pos)
                    local fx = pos
                    local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, nil, true, nil, true)
                    --local extid = switchers[insertstrip.target].extendid
                    Strip_ReposSwitcher_Ext(extid, 1)
                    UpdateControlValues3(nil, ctls_upd, ctls_orr)
                    DM_RefreshFX()

                    --if lvar.livemode == 2 then
                      DM_StoreStripData()
                    --end

                  else
                    local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx)
                    if swok ~= true then
                      Switcher_DeleteExt(ctls[c].switcherid)
                    end
                  end
                end
              end
            else

              if not mouse.alt then
                local switchid, switchid2
                local strip = tracks[track_select].strip
                local ctls = strips[strip][page].controls
                for i = 1, #ctls do
                  if ctls[i].ctlcat == ctlcats.switcher then
                    local swid = ctls[i].switcherid
                    if switchers[swid].switchmode == 1 and switchers[swid].extendmode == true then
                      switchid = swid
                      break
                    end
                  end
                end

                local extid
                local maxpos = 0
                if switchid then
                  extid = switchers[switchid].extendid
                  maxpos = Switcher_Ext_GetMaxPos(extid)

                  for s = 1, #switchers do
                    if switchers[s].switchmode == 1 and switchers[s].extendmode == true and
                       switchers[s].extendid == extid and switchers[s].extendpos == maxpos then
                      switchid2 = s
                      break
                    end
                  end
                  if switchid2 and #switchers[switchid2].grpids > 0 then
                    maxpos = maxpos + 1
                  end
                end

                local c, switchid = Switchers_Ext_Insert(switchid, maxpos)

                if lvar.livemode == 2 then

                  local trn = lvar.dynamicmode_trn
                  local track = GetTrack(trn)
                  if track then
                    local fx = reaper.TrackFX_GetCount(track) --math.max(maxpos-1,0)
                    local swok = Switcher_AddStrip(nil, c, loadstrip, nil, trn, fx, nil, true, nil, true)
                    local extid = switchers[switchid].extendid
                    Strip_ReposSwitcher_Ext(extid, 1)
                    UpdateControlValues3(nil, ctls_upd, ctls_orr)
                    DM_RefreshFX()

                    --if lvar.livemode == 2 then
                      DM_StoreStripData()
                    --end
                  end

                else
                  local swok = Switcher_AddStrip(nil, c, loadstrip)
                  if swok ~= true then
                    Switcher_DeleteExt(ctls[c].switcherid)
                  end
                end
              else
                --[[--mouse.alt
                --addstripdialog
                lvar.addstripdialog_tracknum = lvar.dynamicmode_trn
                local fxdata = AddStripDialog_GetFxData()
                if #fxdata > 0 then

                  fxdata.dx = dx
                  fxdata.dy = dy
                  fxdata.mode = 0
                  fxdata.insertstrip = insertstrip
                  fxdata.loadstrip = loadstrip

                  AddStripDialog_UpdateSel(fxdata)
                  lvar.fxdata = fxdata
                  lvar.show_addstripdialog = true
                  lupd.update_gfx = true
                  retain = true
                end]]
              end
            end

          end
          insertstrip = nil
          loadstrip = nil

        else
          local dx, dy = insertstrip.x-obj.sections[10].x, insertstrip.y-obj.sections[10].y+math.floor(insertstrip.dy/settings_gridsize)*settings_gridsize
        --DBG('drop  '..dx..'  '..dy)

          local retain

          if mouse.alt then

            --[[local fxdata = {}
            local tfxi = GetTrackFXInfo()
            local sfxi = GetStripFXInfo(nil, loadstrip)

            local tr = GetTrack(track_select)
            local fxcnt = reaper.TrackFX_GetCount(tr)
            local fx_min = fxcnt-1
            local fxn = {}
            for i = 1, #sfxi do
              local fx
              if tfxi[0] then
                for f = 0, #tfxi do
                  if tfxi[f].fxfn == sfxi[i].fxfn and not fxn[f] and not tfxi[f].stripinfo then
                    fx = f
                    fxn[f] = true
                    break
                  end
                end
              end
              fx_min = math.min(fx_min,fx or fxcnt)
              if fx then
                fxdata[i] = {fxnm = sfxi[i].fxname, ofxguid = sfxi[i].fxguid, fxguid = tfxi[fx].fxguid, fxfn = tfxi[fx].fxfn, fxname = tfxi[fx].fxname, fxnum = fx}
              else
                fxdata[i] = {fxnm = sfxi[i].fxname, ofxguid = sfxi[i].fxguid}
              end
            end]]
            lvar.addstripdialog_tracknum = track_select
            local fxdata = AddStripDialog_GetFxData()
            if #fxdata > 0 then

              fxdata.dx = dx
              fxdata.dy = dy
              fxdata.mode = 0
              fxdata.insertstrip = insertstrip
              fxdata.loadstrip = loadstrip

              AddStripDialog_UpdateSel(fxdata)
              lvar.fxdata = fxdata
              lvar.show_addstripdialog = true
              lupd.update_gfx = true
              retain = true
              RedrawGUIBitmap()
              
            else
              Strip_AddStrip(loadstrip,math.floor(dx/lvar.zoom),math.floor(dy/lvar.zoom),true, nil, nil, fx_min, nil, fxdata)
            end
          else
            Strip_AddStrip(loadstrip,math.floor(dx/lvar.zoom),math.floor(dy/lvar.zoom),true)
          end

          lupd.update_gfx = true
          insertstrip = nil
          if not retain then
            reaper.MarkProjectDirty(0)
            loadstrip = nil
            PopulateUsedTracksTable()

            if stripgallery_view == 1 then
              stlay_data = AutoSnap_GetStripLocs(true)
            end
          end
        end

      else
        loadstrip = nil
        insertstrip = nil
        lupd.update_surface = true
      end

      if lvar.livemode >= 1 and sb_drag and sb_drag.showpop then
        ShowPop(sb_drag.showpop)
      end
      sb_drag = nil

    end

    if mouse.shift ~= isoms or mouse.alt ~= isoma then
      lupd.update_surface = true
      isoms = mouse.shift
      isoma = mouse.alt
    end

  end

  function CheckOver10()

    if MOUSE_over(obj.sections[10]) and (show_stripbrowser ~= true or not MOUSE_over(obj.sections[1350]))
         and (show_snapshots ~= true or not MOUSE_over(obj.sections[160]))
         and (show_lfoedit ~= true or not MOUSE_over(obj.sections[1100]))
         and (show_mutate ~= true or not MOUSE_over(obj.sections[1120]))
         and (show_randomopts ~= true or not MOUSE_over(obj.sections[1130]))
         and (show_samplemanager ~= true or not MOUSE_over(obj.sections[1300])) then
      return true
    end
  end

  function CheckOver10_gui()
  
    gfx.dest = guibitmap
    gfx.x = mouse.mx
    gfx.y = mouse.my
    local r,g,b = gfx.getpixel()
    local rgb = math.floor(((r*255) + ((g*255) << 8) + ((b*255) << 16))+0.5)
  
    if rgb == 10 then
      return true
    else
      return false  
    end
  end
  
  function Process_MMOV()

    if lvar.mmov_offset == nil then return end

    if lvar.mixmodedir == 0 then
      if lvar.omy ~= mouse.my then
        lvar.omy = mouse.my
        local mpad = lvar.mmov_pad
        local my = mouse.my -lvar.mmov_offset - obj.sections[10].y - mpad + lvar.mmov_pos
        local scale = lvar.mmov_scale
        local h = math.floor(obj.sections[10].h * scale)
        surface_offset.mixy = F_limit(math.floor((my - h/(2*lvar.zoom)) / scale), 0-math.floor(obj.sections[10].h/(2*lvar.zoom)), lvar.mixpos_max-math.floor(obj.sections[10].h/(2*lvar.zoom)))

        local scale = lvar.mmov_scale
        local y = math.floor((surface_offset.mixy or 0)*scale)
        local h = math.floor(obj.sections[10].h*scale)
        if obj.sections[10].h < lvar.mmov_max then
          if y < lvar.mmov_pos then
            lvar.mmov_pos = math.max(y,0)
          elseif y > lvar.mmov_pos+obj.sections[10].h-h then
            lvar.mmov_pos = math.min(y-(obj.sections[10].h-h),lvar.mmov_max-obj.sections[10].h)
          end
        end

        lupd.update_surface = true
      end
    else
      if lvar.omx ~= mouse.mx then
        lvar.omx = mouse.mx
        local mpad = lvar.mmov_pad
        local mx = mouse.mx -lvar.mmov_offset - obj.sections[10].x - mpad + lvar.mmov_pos
        local scale = lvar.mmov_scale
        local w = math.floor(obj.sections[10].w * scale)
        surface_offset.mixx = F_limit(math.floor((mx - w/(2*lvar.zoom)) / scale),0-math.floor(obj.sections[10].w/(2*lvar.zoom)), lvar.mixpos_max-math.floor(obj.sections[10].w/(2*lvar.zoom)))

        local scale = lvar.mmov_scale
        local x = math.floor((surface_offset.mixx or 0)*scale)
        local w = math.floor(obj.sections[10].w*scale)
        if obj.sections[10].w < lvar.mmov_max then
          if x < lvar.mmov_pos then
            lvar.mmov_pos = math.max(x,0)
          elseif x > lvar.mmov_pos+obj.sections[10].w-w then
            lvar.mmov_pos = math.min(x-(obj.sections[10].w-w),lvar.mmov_max-obj.sections[10].w)
          end
        end
        lupd.update_surface = true
      end
    end
  end

  function Process_MMOV2(rt,lb,rb)

    if not lvar.mmov_rows then return end

    if lvar.mixmodedir == 0 then
      local mpad = lvar.mmov_pad
      --if mouse.mx < obj.sections[10].x+lvar.mmov_vsize+mpad*2 then
        gfx.dest = 950
        local zz = mouse.my -lvar.mmov_offset - obj.sections[10].y - mpad + lvar.mmov_pos
        local zzz = zz
        local rr = -1
        local rrr = 0
        for r = 0, #lvar.mmov_rows do
          rrr = rrr + lvar.mmov_rows[r]
          if zz > lvar.mmov_rows[r] then
            zz = zz - lvar.mmov_rows[r]
          else
            if zzz < rrr then
              rr = r
            end
            break
          end
        end

        if rr ~= -1 then
          gfx.x = lvar.mmov_vsize + math.floor(lvar.mmov_vsize/2) + (rr*lvar.mmov_vsize*2)
          gfx.y = zz
          local r,g,b = gfx.getpixel()
          gfx.dest = 1
          local cc = math.floor(((r*255) + ((g*255) << 8) + ((b*255) << 16))+0.5)
          --DBG(rr)
          local strip = tracks[track_select].strip
          local pop = strips[strip][page].pop

          if mouse.ctrl or mouse.alt or lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0 and pop and #pop > 0) then

            local posidx = lvar.stripdim.extposidx
            local swdata = lvar.stripdim.swdata
            local extid = swdata.extid
            if extid then

              local close
              local swid = posidx[extid][cc]
              local strip = tracks[track_select].strip
              if (lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0)) and lb then
                close = false
              elseif (lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0)) and rb then
                close = true
              elseif lvar.showpop and strips[strip][page].popidx and strips[strip][page].popidx[swid] then
                close = true
              end

              if mouse.alt or lvar.dm_singlepopup then
                PopOut_DeleteAll(true)
              elseif close then
                PopOut_Delete(swid)
              end

              if not close then
                local x, y
                if swid and swdata[swid] then
                  local w = swdata[swid].r - swdata[swid].l
                  local h = swdata[swid].b - swdata[swid].t
                  x = math.floor(obj.sections[10].w/2 - w/2) -- obj.sections[10].x
                  y = math.floor(obj.sections[10].h/2 - h/2) -- obj.sections[10].y
                  if lvar.mmov_show then
                    x = x + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                  end
                  if not mouse.alt and not lvar.dm_singlepopup and switchers[swid].popx and switchers[swid].popy then
                    x = switchers[swid].popx or x
                    y = switchers[swid].popy or y
                  end
                end
                PopOut(swid,x,y)
                ShowPop(true)
                
                if lvar.popout_autoarrange and swdata[swid] then
                  local rn = swdata[swid].rownum
                  if rn then
                    MixMode_Swipe_Pop(0,nil,rn-1)
                    TouchFX_Switcher(swid)
                  end
                end
              end
              --[[if not strips[strip][page].pop or #strips[strip][page].pop == 0 then
                ShowPop(false)
              end]]
            end
          else
            MixMode_Swipe(lvar.centrepos,cc)
          end
        end
      --end
    else
      local mpad = lvar.mmov_pad
      --if mouse.my < obj.sections[10].y+lvar.mmov_vsize+mpad*2 then
        gfx.dest = 950
        local zz = mouse.mx -lvar.mmov_offset - obj.sections[10].x - mpad + lvar.mmov_pos
        local zzz = zz
        local rr = -1
        local rrr = 0
        for r = 0, #lvar.mmov_rows do
          rrr = rrr + lvar.mmov_rows[r]
          if zz > lvar.mmov_rows[r] then
            zz = zz - lvar.mmov_rows[r]
          else
            if zzz < rrr then
              rr = r
            end
            break
          end
        end

        if rr ~= -1 then
          gfx.x = zz
          gfx.y = lvar.mmov_vsize + math.floor(lvar.mmov_vsize/2) + (rr*lvar.mmov_vsize*2)
          local r,g,b = gfx.getpixel()
          gfx.dest = 1
          local cc = math.floor(((r*255) + ((g*255) << 8) + ((b*255) << 16))+0.5)

          local strip = tracks[track_select].strip
          local pop = strips[strip][page].pop

          if mouse.ctrl or mouse.alt or lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0 and pop and #pop > 0) then

            local posidx = lvar.stripdim.extposidx
            local swdata = lvar.stripdim.swdata
            local extid = swdata.extid

            if extid then

              local close
              local swid = posidx[extid][cc]
              local strip = tracks[track_select].strip
              if (lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0)) and lb then
                close = false
              elseif (lvar.showpoponly or (lvar.showpop and lvar.mm_fadepop == 0)) and rb then
                close = true
              elseif lvar.showpop and strips[strip][page].popidx and strips[strip][page].popidx[swid] then
                close = true
              end

              if mouse.alt or lvar.dm_singlepopup then
                PopOut_DeleteAll(true)
              elseif close then
                PopOut_Delete(swid)
              end

              if not close then
                local x, y
                if swid and swdata[swid] then
                  local w = swdata[swid].r - swdata[swid].l
                  local h = swdata[swid].b - swdata[swid].t
                  x = math.floor(obj.sections[10].w/2 - w/2) -- obj.sections[10].x
                  y = math.floor(obj.sections[10].h/2 - h/2) -- obj.sections[10].y
                  if lvar.mmov_show then
                    y = y + math.floor((lvar.mmov_vsize + 2*lvar.mmov_pad)/2)
                  end
                  if not mouse.alt and not lvar.dm_singlepopup and switchers[swid].popx and switchers[swid].popy then
                    x = switchers[swid].popx or x
                    y = switchers[swid].popy or y
                  end
                end
                PopOut(swid,x,y)
                ShowPop(true)

                if lvar.popout_autoarrange and swdata[swid] then
                  local rn = swdata[swid].rownum
                  if rn then
                    MixMode_Swipe_Pop(0,nil,rn-1)
                    TouchFX_Switcher(swid)
                  end
                end
              end
              --[[if not strips[strip][page].pop or #strips[strip][page].pop == 0 then
                ShowPop(false)
              end]]

            end
          else
            MixMode_Swipe(lvar.centrepos,cc)
          end
        end
      --end
    end
  end

  function Process_EB(context)

    if context == nil then
      if not lvar.delayfunction.ebopen then
        if gfx.mouse_cap&1 == 1 then
          if not mouse.down then
            OnMouseDown()
            if mouse.uptime and os.clock()-mouse.uptime < 0.25 then
              OnMouseDoubleClick()
            end
          elseif gfx.mouse_x ~= mouse.lx or gfx.mouse_y ~= mouse.ly then
            OnMouseMove()
          end
        elseif mouse.down then
          OnMouseUp()
        end
      end
      if mouse.LB == true and not lvar.editbox_mouseLB and MOUSE_over(obj.sections[6]) or EB_Enter then
        --OK
        EB_Enter = false
        if EB_Open == 1 then
          SaveStrip3(editbox.text)
        elseif EB_Open == 2 then
          Undo_Set({'ctlname_override'})
          EditCtlName2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 3 then
          Undo_Set({'dvaloffset'})
          EditDValOffset2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 4 then
          Undo_Set({'minov'})
          EditMinDVal2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 16 then
          Undo_Set({'maxov'})
          EditMaxDVal2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 5 then
          EditValue2(editbox.text)
          --lupd.update_ctls = true
        elseif EB_Open == 6 then
          InsertLabel2(editbox.text)
        elseif EB_Open == 7 then
          Undo_Set({'text'})
          EditLabel2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 8 then
          Undo_Set({'font'})
          EditFont2(editbox.text)
          lupd.update_gfx = true
        elseif EB_Open == 10 then
          EditCycleDV(editbox.text)
        elseif EB_Open == 11 then
          EditSSName2(editbox.text)
          lupd.update_snaps = true
          lupd.update_gfx = true

        elseif EB_Open == 111 then
          EditSSName3(editbox.text)
          lupd.update_snaps = true
          lupd.update_gfx = true
        --elseif EB_Open == 12 then
          --[[trackfxparam_select = ctl_select[1].ctl
          retval, comid = reaper.GetUserInputs('Action Button', 1, 'Please enter action command ID: ,extrawidth=196', '')
          if retval == true and comid then
            local actnm = AssAction_GetNameFromID(comid)
            AssActionByID(comid,actnm)
            lupd.update_gfx = true
          end]]
          --OpenEB(13,'Please enter action command ID:')
        --[[elseif EB_Open == 13 then
          trackfxparam_select = ctl_select[1].ctl
          retval, comid = reaper.GetUserInputs('Action Button', 1, 'Please enter action command ID: ,extrawidth=196', '')
          if retval == true and comid then
            local actnm = AssAction_GetNameFromID(comid)
            AssActionByID(comid,actnm)
            lupd.update_gfx = true
          end]]
          --AssActionByID(editbox.text)
          --lupd.update_gfx = true
        elseif EB_Open == 14 then
          action_tblF = ActionListFilter(editbox.text)
          al_offset = 0
          lupd.update_gfx = true
        elseif EB_Open == 15 then
          EditSubName(editbox.text)
          lupd.update_snaps = true
        elseif EB_Open == 17 then
          local sc = tonumber(editbox.text)
          if sc then
            cycle_select.statecnt = F_limit(sc,0,max_cycle)
            Cycle_InitData()
          end
          lupd.update_surface = true
        elseif EB_Open == 18 then
          SavePath(editbox.text)
        elseif EB_Open == 20 then
          SaveSet2(editbox.text)
        elseif EB_Open == 30 then
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandname = editbox.text
          lupd.update_gfx = true
        elseif EB_Open == 31 then
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandtype = editbox.text
          local path = paths.eqbands_path
          reaper.RecursiveCreateDirectory(path..string.upper(editbox.text),1)

          lupd.update_gfx = true
        elseif EB_Open == 32 then
          EQC_SaveEQ(editbox.text)

        elseif EB_Open == 50 then

          save_subfolder = editbox.text
          if save_subfolder == '' then
            save_subfolder = nil
          end
          lupd.update_gfx = true

        elseif EB_Open == 51 then

          local ctls = strips[tracks[track_select].strip][page].controls
          local ctl = ctls[switcher_select]
          local switchid = ctl.switcherid
          local newname = editbox.text
          local grpid
          for g = 1, #switchers[switchid].grpids do
            if switchers[switchid].grpids[g].id == switchers[switchid].current then
              switchers[switchid].grpids[g].name = newname
              ctl.param_info.paramname = string.format('%i',g)..': '..switchers[switchid].grpids[g].name
              lupd.update_gfx = true
              grpid = switchers[switchid].grpids[g].id
              break
            end
          end
          if grpid then
            for i = 1, #ctls do
              local ctl = ctls[i]
              if ctl.ctlcat == ctlcats.switcher_pagesel then
                if ctl.switcherid == switchid and ctl.param == grpid then
                  ctl.param_info.paramname = newname
                  SetCtlDirty(i)
                  lupd.update_ctls = true
                end
              end
            end
          end

        elseif EB_Open == 60 then
          local txt = editbox.text
          local mo = tonumber(txt)
          if mo then
            local nval, dval = GetValFromDVal(ctl_select[1].ctl,txt)
            if nval then

              local gtab = gauge_select
              local gcnt = #gtab.vals+1
              gtab.vals[gcnt] = {val = nval, dval = dval, dover = nil}
              local nonly
              if gtab.numonly then
                nonly = ''
              end
              if gtab.val_dp > -1 then
                gtab.vals[gcnt].dover = roundX(dval, gtab.val_dp, nonly)
              end
              Gauge_SortVals()
              for i = 1, #gtab.vals do
                if gtab.vals[i].val == gtab.val then
                  gauge_ticksel = i
                end
              end
              gtab.ticks = gtab.ticks+1
              lupd.update_surface = true

            end
          end

        elseif EB_Open == 130 then

          local txt = editbox.text
          local gtab = gauge_select
          local gcnt = #gtab.vals+1
          local nval = gauge_select.val
          gtab.vals[gcnt] = {val = nval, dval = txt, dover = txt}
          Gauge_SortVals()
          for i = 1, #gtab.vals do
            if gtab.vals[i].val == gtab.val then
              gauge_ticksel = i
            end
          end
          gtab.ticks = gtab.ticks+1
          lupd.update_surface = true

        elseif EB_Open == 833 then

          local txt = editbox.text
          if (txt or '') ~= '' then
            Gauge_EditLabel(txt)
          end
          
        elseif EB_Open == 61 then
          local f = CheckFont(editbox.text)
          if f then
            gauge_select.font = f
            lupd.update_gfx = true
          end
        elseif EB_Open == 62 then
          local f = CheckFont(editbox.text)
          if f then
            ctlfont_select = f
            for i = 1, #ctl_select do
              strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].font = ctlfont_select
            end
          end
          lupd.update_gfx = true
        elseif EB_Open == 100 then
          autosnap_rowheight = F_limit(nz(tonumber(editbox.text),autosnap_rowheight),50,lvar.maxdim)
          lupd.update_gfx = true
        elseif EB_Open == 101 then
          autosnap_itemgap = F_limit(nz(tonumber(editbox.text),autosnap_itemgap),0,1000)
          lupd.update_gfx = true
        elseif EB_Open == 102 then
          autosnap_itemgapmax = F_limit(nz(tonumber(editbox.text),autosnap_itemgapmax),0,1000)
          lupd.update_gfx = true
        elseif EB_Open == 103 then
          gallery_itemgap = F_limit(nz(tonumber(editbox.text),gallery_itemgap),0,1000)
          lupd.update_gfx = true

        elseif EB_Open == 104 then
          local mcnt = nz(tonumber(editbox.text),modulator_cnt)
          if mcnt ~= modulator_cnt then
            Mod_ChangeCount(mcnt)
          end
          lupd.update_gfx = true

        elseif EB_Open == 120 then
          local fn = editbox.text
          if fn and fn ~= '' then

            local file
            local ffn = paths.mod_path..fn..'.lbxmod'
            file=io.open(ffn,"w")
            if file then
              SaveMod(file,'',modulators[mod_select],true)
              file:close()
            else
              OpenMsgBox(1,'Error opening file for saving.  Possibly invalid filename.',1)
            end
          end

        elseif EB_Open == 121 then
          local fn = editbox.text
          if fn and fn ~= '' then
            reaper.RecursiveCreateDirectory(paths.strips_path..fn,1)
            PopulateStripFolders(lvar.sortcontrols)
            PopulateStrips(lvar.sortcontrols)
          end

        elseif EB_Open == 122 then
          local fn = editbox.text
          if fn and fn ~= '' then
            reaper.RecursiveCreateDirectory(paths.graphics_path..fn,1)
            PopulateGFX(nil, lvar.sortcontrols)
            lupd.update_sidebar = true
          end

        elseif EB_Open == 200 then
          --X range
          local x = tonumber(editbox.text)
          if x and x >= 0 and x <= 100 then
            x = x / 100
            local p = randomopts_select.param
            local lg = randomopts_select.ctls[p].linkgrp
            if randomopts_select.linkgrps[lg] then
              randomopts_select.linkgrps[lg].X = x
              lupd.update_randomopts = true
            end

          end

        elseif EB_Open == 201 then
          --X min
          local x = tonumber(editbox.text)
          if x and x >= 0 and x <= 1 then
            local p = randomopts_select.param
            randomopts_select.ctls[p].min = x
            lupd.update_randomopts = true
          end

        elseif EB_Open == 202 then
          --X max
          local x = tonumber(editbox.text)
          if x and x >= 0 and x <= 1 then
            local p = randomopts_select.param
            randomopts_select.ctls[p].max = x
            lupd.update_randomopts = true
          end

        elseif EB_Open == 203 then
          --X range (ctl)
          local x = tonumber(editbox.text)
          if x and x >= 0 and x <= 100 then
            x = x / 100
            local p = randomopts_select.param
            randomopts_select.ctls[p].amount = x
            lupd.update_randomopts = true
          end

        elseif EB_Open == 250 then
          --pixel width
          local x = tonumber(editbox.text)
          if x then
            Undo_Set({'limittext'})
            limittext_select = x
            EditLimitText2(x)
            lupd.update_gfx = true
          end

        elseif EB_Open == 251 then
          --flags
          local x = tonumber(editbox.text)
          if x then
            Undo_Set({'textflags'})
            flags_select = x
            EditFlagText2(x)
            lupd.update_gfx = true
          end

        elseif EB_Open == 252 then
          --pixel width
          local x = tonumber(editbox.text)
          if x then
            Undo_Set({'wwtext'})
            wwtext_select = x
            EditWWText2(x)
            lupd.update_gfx = true
          end

        elseif EB_Open == 253 then
          --animate time
          local x = tonumber(editbox.text)
          if x then
            x = math.max(x, 0)
            Undo_Set({'animatetime'})
            animatetime_select = x
            EditAnimateText2(x)
            lupd.update_gfx = true
          end
          
        elseif EB_Open == 300 then
          --ctlbrowserfavs
          local sel = lvar.ctlbrowserfav_select
          local favs = lvar.ctlbrowserfavs
          if not favs[sel] then
            favs[sel] = {}
          end
          local txt = tostring(editbox.text)
          if txt == '' then
            txt = nil
          end
          favs[sel].name = txt
          CB_SaveFavs()
          lupd.update_surface = true

        elseif EB_Open == 499 then

          local ctl = strips[tracks[track_select].strip][page].controls[lvar.statestr_edit]
          if ctl then
            ctl.param_info.paramstr = editbox.text

            local extname = ctl.stateinfo.extname
            local key = ctl.stateinfo.key
            if extname and key and extname ~= '[NoState]' and extname ~= '' then
              reaper.SetExtState(extname,key,ctl.param_info.paramstr or '', true)
            end
            SetCtlDirty(lvar.statestr_edit)
            lupd.update_ctls = true
          end

        elseif EB_Open == 731 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            lvar.ctlupdate_rr = math.floor(tonumber(editbox.text))
            lvar.ctlupdate_pos = 1
          else
            lvar.ctlupdate_rr = nil
            lvar.ctlupdate_pos = 1
          end

        elseif EB_Open == 740 then
          if tonumber(editbox.text) then
            undo.max = F_limit(math.floor(tonumber(editbox.text)),0,999)
          end
          lupd.update_gfx = true

        elseif EB_Open == 999 then
          if editbox.text then
            Strip_SetPlugDef2X(editbox.text)
          end

        elseif EB_Open == 1500 then
          if tonumber(editbox.text) then
            lvar.dm_padx = tonumber(editbox.text)

            local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
            if ctl then
              local switchid = ctl.switcherid
              local extid = switchers[switchid].extendid
              Switcher_SetPadX(switchid, tonumber(editbox.text))
              if extid then
                Strip_ReposSwitcher_Ext(extid, 1)
              end
              GUI_DrawCtlBitmap()
            end
          end
          lupd.update_gfx = true

        elseif EB_Open == 1501 then
          if tonumber(editbox.text) then
            lvar.dm_pady = tonumber(editbox.text)

            local ctl = strips[tracks[track_select].strip][page].controls[switcher_select]
            if ctl then
              local switchid = ctl.switcherid
              local extid = switchers[switchid].extendid
              Switcher_SetPadY(switchid, tonumber(editbox.text))
              if extid then
                Strip_ReposSwitcher_Ext(extid, 1)
              end
              GUI_DrawCtlBitmap()
            end
          end
          lupd.update_gfx = true

        elseif EB_Open == 3003 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            local x = math.floor(tonumber(editbox.text))
            CtlSelect_SetX(x)
          end

        elseif EB_Open == 3004 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            local y = math.floor(tonumber(editbox.text))
            CtlSelect_SetY(y)
          end

        elseif EB_Open == 3005 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            local w = math.floor(tonumber(editbox.text))
            CtlSelect_SetW(w)
          end

        elseif EB_Open == 3006 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            local h = math.floor(tonumber(editbox.text))
            CtlSelect_SetH(h)
          end

        elseif EB_Open == 3002 then
          if tonumber(editbox.text) and tonumber(editbox.text) > 0 then
            local s = tonumber(editbox.text)
            CtlSelect_SetScale(s)
          end

        elseif EB_Open == 5020 then
          local stripfn = TrimStr(editbox.text)
          if stripfn ~= '' then
            local sfn, fol, fol2, ffn

            if lvar.dm_editmode_data.sfn then
              sfn = lvar.dm_editmode_data.sfn
              fol = string.match(sfn, '.+[\\/](.-)[\\/].*')
              fol2 = string.match(sfn, '(.+[\\/]).*')
              ffn = fol2..stripfn..'.strip'
            else
              fol = strip_folders[stripfol_select].fn
              ffn = paths.strips_path..fol..'/'..stripfn..'.strip'
            end
            DM_EM_AddDummyFX(stripfn, lvar.dm_editmode_data.edit_trn)

            SaveStrip3(stripfn, nil, ffn)
            lvar.ss3_bmp.pause = true

            if not plugdefstrips then
              plugdefstrips = {}
              plugdefstrips_idx = {}
            end
            local idx = #plugdefstrips+1
            --get plug name
            local track = GetTrackByName('__LBXEDIT')
            if track and reaper.TrackFX_GetCount(track) == 1 then

              local plugid = lvar.dm_save_plug
              if not plugid then
                plugid = stripfn
              end

              --[[if plugdefstrips_idx[plugid] then
                idx = plugdefstrips_idx[plugid]
              end
              plugdefstrips[idx] = {plug = plugid, stripfile = stripfn..'.strip', stripfol = fol}
              plugdefstrips_idx[plugid] = idx]]
              --local p1 = PlugDef_Add(plugid, stripfn, fol, false, nil)
              --local p3 = PlugDef_Add(stripfn, stripfn, fol, false, nil)

              local _, plug = reaper.TrackFX_GetFXName(track, 0, '')
              local p2 = PlugDef_Add(plug, stripfn, fol, false, nil)

              --[[local p1 = plugid
              local p2 = ''

              if plug then
                plug = TrimStr(CropFXName(plug))
                if plug ~= plugid then
                  if plugdefstrips_idx[plug] then
                    idx = plugdefstrips_idx[plug]
                  else
                    idx = idx + 1
                  end
                  plugdefstrips[idx] = {plug = plug, stripfile = stripfn..'.strip', stripfol = fol}
                  plugdefstrips_idx[plug] = idx
                  p2 = plug
                end
              end]]


              local _, plug = reaper.BR_TrackFX_GetFXModuleName(track,0,'',64)
              --[[if plug then
                if plug ~= plugid then
                  local ii = plugdefstrips_idx[plug]
                  if not ii or plugdefstrips[ii].stripfile ~= stripfn..'.strip' or plugdefstrips[ii].stripfol ~= fol then
                    if reaper.MB('This strip has been associated with strip/plugin names: \n\n'..p1..'\n'..p2..'\n\nAlso associate this strip with plugin filename: '..plug..'?','DM Strip Save',4) == 6 then
                      if plugdefstrips_idx[plug] then
                        idx = plugdefstrips_idx[plug]
                      else
                        idx = idx + 1
                      end
                      plugdefstrips[idx] = {plug = plug, stripfile = stripfn..'.strip', stripfol = fol}
                      plugdefstrips_idx[plug] = idx
                    end
                  end
                end
              end]]
              local asslist = (p3 or '') ..'\n'.. (p1 or '') ..'\n'.. (p2 or '')
              PlugDef_Add(plug, stripfn, fol, true, asslist)


              Save_PlugDefs()
            else
              --multi plugin


            end

            lvar.dm_save_plug = nil

            if reaper.JS_LICE_WritePNG then
              lvar.dm_return_set = true
              lvar.ss3_bmp.delay = reaper.time_precise()+0.5
              lvar.ss3_bmp.pause = nil
            else
              local ret_page = lvar.dm_editmode_data.ret_page
              local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
              navigate = true

              if lvar.dm_editmode_data.plist_w == 0 then
                plist_w = lvar.dm_editmode_data.plist_w
                show_editbar = false
                resize_display = true
              end
              lvar.dm_editmode_data = nil

              setmode(1)
              ChangeTrack2(ret_trn, ret_page, true)
              obj = PosTrBtns(obj)
            end
          end

        elseif EB_Open == 5021 then

          local fxident = TrimStr(editbox.text)
          if fxident ~= '' then
            local ffn = paths.strips_path..'/'..paths.dmstrip_folder..'/'..fxident..'.strip'
            --DBG(ffn..'  '..fxident)
            SaveStrip3(fxident, nil, ffn)
            lvar.ss3_bmp.pause = true

            local sfn = lvar.dm_editmode_data.sfn
            if not plugdefstrips then
              plugdefstrips = {}
              plugdefstrips_idx = {}
            end

            local idx = #plugdefstrips+1
            --get plug name
            local track = GetTrackByName('__LBXEDIT')
            if track and reaper.TrackFX_GetCount(track) == 1 then

              --[[local plugid = lvar.dm_save_plug
              if not plugid then
                plugid = fxident
              end

              if plugdefstrips_idx[plugid] then
                idx = plugdefstrips_idx[plugid]
              end
              plugdefstrips[idx] = {plug = plugid, stripfile = fxident..'.strip', stripfol = paths.dmstrip_folder}
              plugdefstrips_idx[plugid] = idx]]

              local _, plug = reaper.TrackFX_GetFXName(track, 0, '')
              local p2 = PlugDef_Add(plug, fxident, paths.dmstrip_folder, false, nil)

              --[[local p1 = plugid
              local p2 = ''

              if plug then
                plug = TrimStr(CropFXName(plug))
                if plug ~= plugid then
                  if plugdefstrips_idx[plug] then
                    idx = plugdefstrips_idx[plug]
                  else
                    idx = idx + 1
                  end
                  plugdefstrips[idx] = {plug = plug, stripfile = fxident..'.strip', stripfol = paths.dmstrip_folder}
                  plugdefstrips_idx[plug] = idx
                  p2 = plug
                end
              end  ]]

              local _, plug = reaper.BR_TrackFX_GetFXModuleName(track,0,'',64)
              local asslist = --[[(p1 or '') ..'\n'.. ]](p2 or '')
              PlugDef_Add(plug, fxident, paths.dmstrip_folder, true, asslist)

              --[[if plug then
                if plug ~= plugid then
                  local ii = plugdefstrips_idx[plug]
                  if not ii or plugdefstrips[ii].stripfile ~= stripfn..'.strip' or plugdefstrips[ii].stripfol ~= paths.dmstrip_folder then
                    if reaper.MB('This strip has been associated with strip/plugin names: \n\n'..p1..'\n'..p2..'\n\nAlso associate this strip with plugin filename: '..plug..'?','DM Strip Save',4) == 6 then
                      if plugdefstrips_idx[plug] then
                        idx = plugdefstrips_idx[plug]
                      else
                        idx = idx + 1
                      end
                      plugdefstrips[idx] = {plug = plug, stripfile = fxident..'.strip', stripfol = paths.dmstrip_folder}
                      plugdefstrips_idx[plug] = idx
                    end
                  end
                end
              end]]

              Save_PlugDefs()
            end

            lvar.dm_save_plug = nil

            if reaper.JS_LICE_WritePNG then
              lvar.dm_return_set = true
              lvar.ss3_bmp.delay = reaper.time_precise()+0.5
              lvar.ss3_bmp.pause = nil
            else
              local ret_page = lvar.dm_editmode_data.ret_page
              local ret_trn = tracks[lvar.dm_editmode_data.ret_trn].tracknum
              navigate = true

              if lvar.dm_editmode_data.plist_w == 0 then
                plist_w = lvar.dm_editmode_data.plist_w
                show_editbar = false
                resize_display = true
              end
              lvar.dm_editmode_data = nil

              setmode(1)
              ChangeTrack2(ret_trn, ret_page, true)
              obj = PosTrBtns(obj)
            end
          end

        elseif EB_Open == 4507 then

          if lvar.sapd then
            local fxident = string.lower(TrimStr(editbox.text))
            if lvar.sapd.stripdata and #lvar.sapd.stripdata.fx == 1 and lvar.sapd.selected then
              if fxident and fxident ~= '' then
                PlugDef_AddX(fxident, lvar.sapd[lvar.sapd.selected].fil, lvar.sapd[lvar.sapd.selected].fol, true)
                StripAssoc_RefreshAssData()
                lupd.update_stripass = true
              end
            end
          end

        elseif EB_Open == 1010 then
          local bars = tonumber(editbox.text)
          if bars then
            --calculate time in secs
            local bt = CalcBarTime()
            snapshots[tracks[track_select].strip][page][sstype_select].morph_time = bars*bt /100
            lupd.update_snaps = true
          end

        elseif EB_Open == 5040 then

          local t = editbox.text
          if t ~= '' then
            lvar.btnpnl_obj.ndesc = t
            lupd.update_trbtns = true
          end

        elseif EB_Open == 7000 then
          --search strip
          local t = editbox.text
          if t ~= '' then
            StripSearch2(t,true)
          else
            lvar.stripbrowser.search = nil
            lvar.reloadsbimages = true
            lupd.update_stripbrowser = true
          end

        end

        editbox = nil
        EB_Open = 0
        mouse.release = true

      elseif mouse.LB == true and not lvar.editbox_mouseLB and MOUSE_over(obj.sections[7]) then
        if editbox.cancelfunc then
          editbox.cancelfunc()
        end
        editbox = nil
        EB_Open = 0
        mouse.release = true
        lvar.dm_save_plug = nil

      elseif mouse.LB == true and not lvar.editbox_mouseLB and MOUSE_over(obj.sections[8]) and not MOUSE_over(obj.sections[9]) --[[,mouse.mx-obj.sections[8].x,mouse.my-obj.sections[8].y)]] then
        context = contexts.move_eb
        ebpos = {dx = mouse.mx-obj.sections[8].x, dy = mouse.my-obj.sections[8].y}
      end

    elseif context and context == contexts.move_eb then

      local sizex, sizey = 350, 100
      local bsizex, bsizey = 60, 20
      --[[local x, y = F_limit(mouse.mx - ebpos.dx,obj.sections[10].x,obj.sections[10].x+obj.sections[10].w-sizex),
                   F_limit(mouse.my - ebpos.dy,obj.sections[10].y,obj.sections[10].y+obj.sections[10].h-sizey)]]
      local x, y = F_limit(mouse.mx - ebpos.dx,0,gfx1.main_w-sizex),
                         F_limit(mouse.my - ebpos.dy,0,gfx1.main_h-sizey)
      obj.sections[8].x = x
      obj.sections[8].y = y
      obj = PosEBCtls(obj)

      lupd.update_surface = true
    end

    local c=gfx.getchar()
    if editbox and editbox.hasfocus and c > 0 then editbox_onchar(editbox, c) end
    lupd.update_surface = true

    return context

  end

  function PlugDef_GetFromFXGUID(track, guid)
    local fxn = GetFXNFromGUID(track, guid)
    if fxn then

      local _, fxname = reaper.TrackFX_GetFXName(track, fxn, '')
      fxname = TrimStr(CropFXName(fxname))
      local _, fxmod = reaper.BR_TrackFX_GetFXModuleName(track,fxn,'',64)

      local idx = plugdefstrips_idx[string.lower(fxname)]
      if not idx then
        idx = plugdefstrips_idx[string.lower(fxmod)]
      end

      if idx then
        return plugdefstrips[idx].stripfol..'/'..plugdefstrips[idx].stripfile
      end

    end
  end

  function PlugDef_SetDefaultX(plug, fil, fol)

    local tab = {}
    local tabidx = {}
    local cnt = 1
    plug = string.lower(plug)
    for p = 1, #plugdefstrips do
      if plugdefstrips[p].plug == plug and plugdefstrips[p].stripfile == fil and plugdefstrips[p].stripfol == fol then
      else
        tab[cnt] = {plug = plugdefstrips[p].plug, stripfile = plugdefstrips[p].stripfile, stripfol = plugdefstrips[p].stripfol}
        tabidx[plugdefstrips[p].plug] = cnt
        cnt=cnt+1
      end

    end
    tab[cnt] = {plug = plug, stripfile = fil, stripfol = fol}
    tabidx[plug] = cnt

    plugdefstrips = tab
    plugdefstrips_idx = tabidx

  end

  function PlugDef_RemoveX(plug, fil, fol)

    local tab = {}
    local tabidx = {}
    local cnt = 1
    plug = string.lower(plug)
    
    for p = 1, #plugdefstrips do
      if plugdefstrips[p].plug == plug and plugdefstrips[p].stripfile == fil and plugdefstrips[p].stripfol == fol then
      else
        tab[cnt] = {plug = plugdefstrips[p].plug, stripfile = plugdefstrips[p].stripfile, stripfol = plugdefstrips[p].stripfol}
        tabidx[plugdefstrips[p].plug] = cnt
        cnt=cnt+1
      end

    end

    plugdefstrips = tab
    plugdefstrips_idx = tabidx

  end

  function PlugDef_AddX(plug, fil, fol, replace)

    local tab = {}
    local tabidx = {}
    local insert
    plug = string.lower(plug)
    
    if replace then
      if plugdefstrips_idx[plug] then
        local idx = plugdefstrips_idx[plug]
        plugdefstrips[idx] = {plug = plug, stripfile = fil, stripfol = fol}
        --DBG(plug..'  '..fil..'  '..fol)
      else
        insert = true
      end
    else
      insert = true
    end

    if insert then
      tab[1] = {plug = plug, stripfile = fil, stripfol = fol}
      tabidx[plug] = 1
      for p = 1, #plugdefstrips do
        tab[p+1] = plugdefstrips[p]
        tabidx[plugdefstrips[p].plug] = p+1
      end

      plugdefstrips = tab
      plugdefstrips_idx = tabidx
    end

  end

  function PlugDef_Add(plug, stripfn, fol, ask, asslist)

    if plug then
      plug = string.lower(plug)
      
      local fnd
      for p = 1, #plugdefstrips do
        if plugdefstrips[p].plug == plug and plugdefstrips[p].stripfile == stripfn..'.strip' and plugdefstrips[p].stripfol == fol then
          fnd = p
          break
        end
      end

      if not fnd then
        local msg = ''
        if asslist then
          msg = 'This strip has been associated with strip/plugin names: \n\n'..asslist..'\n\n'
        end
        if not ask or reaper.MB(msg..'Associate this strip with plugin filename: '..plug..'?','DM Strip Save',4) == 6 then
          local idx
          if not ask and plugdefstrips_idx[plug] then
            idx = plugdefstrips_idx[plug]
          else
            idx = #plugdefstrips + 1
          end
          if idx then
            plugdefstrips[idx] = {plug = plug, stripfile = stripfn..'.strip', stripfol = fol}
            plugdefstrips_idx[plug] = idx
          end

          return plug
        end
      end
    end
  end

  function TrimStr(s)
    return string.match(s,"^%s*(.-)%s*$")
  end

--[[  function VAL2DB(x)
    local xx = DenormalizeValue(-60,0,x)
    return xx
  end

  function DB2VAL(x)
   return math.exp((x)*0.11512925464970228420089957273422 )
  end]]

  function Process_MB()

    local c=gfx.getchar()
    mb_onchar(c)

    if MOUSE_click(obj.sections[62]) or MB_Enter then
      --OK
      if MS_Open == 1 then
        msgbox = nil
        MS_Open = 0
      elseif MS_Open == 2 then
        -- savedefaultgraph
        msgbox = nil
        strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph = EQC_SetMain(eqcontrolband_select)
        lupd.update_gfx = true
      elseif MS_Open == 3 then
        msgbox = nil
        --MS_Open = 0
        local sscnt = #snapshots[tracks[track_select].strip][page]
        if sscnt > 1 then
          for s = sscnt, 2, -1 do
            Snapshot_DeleteSubset(tracks[track_select].strip, page, s)
          end
          SetCtlBitmapRedraw()
          OpenMsgBox(1,sscnt..' subsets deleted.',1)
        end
        lupd.update_gfx = true
      end
      MB_Enter = false
      lupd.update_surface = true
      mouse.LB = false
      mouse.release = true
    elseif MOUSE_click(obj.sections[64]) then
      --No
      msgbox = nil
      MS_Open = 0
      MB_Enter = false
      lupd.update_surface = true
      mouse.LB = false
      mouse.release = true
    end

  end

  function FollowTrack(ct)
    if mouse.context ~= nil then return end
    if track_select ~= nil or ct > 0 then
      if ct > 0 then
        if track_select == nil then track_select = -1 end
        local st = reaper.GetSelectedTrack(0,0)
        if st == nil then
          st = GetTrack(-1)
        end
        local tr = GetTrack(track_select)
        if st ~= nil and tr ~= nil then
          if GetTrackGUID(st) ~= GetTrackGUID(tr) then
            PopulateTracks()
            for i = -1, reaper.CountTracks(0) do
              tr = GetTrack(i)
              if tr ~= nil then
                tracks[i].name = reaper.GetTrackState(tr)
                if GetTrackGUID(st) == GetTrackGUID(tr) then
                  if strips[tracks[track_select].strip] then
                    strips[tracks[track_select].strip].page = page
                  end

                  local strip = tracks[i].strip
                  if strips and strips[strip] then
                    page = strips[strip].page
                    surface_offset.x = strips[strip][page].surface_x
                    surface_offset.y = strips[strip][page].surface_y
                  else
                    page = 1
                    surface_offset.x = 0
                    surface_offset.y = 0
                  end

                  ChangeTrack(i)
                  trctlslist_offset = 0

                  break
                end
              end
            end

            --TRK CHANGED
            CheckStripControls()
            CheckStripSends()
            PopulateTrackSendsInfo()
            PopulateTrackFX()
            PopulateSpecial()
            ctl_select = nil
            gfx2_select = nil
            gfx3_select = nil
            gfx4_select = nil
            gfx4_selectidx = nil
            CloseActChooser()
            showctlbrowser(false)

            ss_select = nil
            sstype_select = 1
            ssoffset = 0
            lupd.update_gfx = true
          end
        end
      end
    end
  end

  function Process_Settings()

    if mouse.LB and not mouse.last_LB and not MOUSE_click(obj.sections[70]) then
      show_settings = false
      SaveSettings()
      lupd.update_surface = true
      RedrawGUIBitmap()
    elseif gfx.mouse_wheel ~= 0 then
      local v = mousewheel_val()
      settingswin_off = F_limit(settingswin_off + (v*25),(-settingswin_maxh)+settingswin_h,0)
      obj = PosSetWinCtls(obj)
      lupd.update_surface = true
      gfx.mouse_wheel = 0

    elseif MC() --[[mouse.LB or mouse.RB]] then

      local mx, my = mouse.mx, mouse.my

      if MOUSE_click(obj.sections[732]) then

        local i = math.floor((mouse.mx - obj.sections[732].x) / math.floor(obj.sections[732].w/#lvar.settingspages))+1
        if lvar.settingspages[i] then

          lvar.settingspage = i
          settingswin_off = 0
          obj = PosSetWinCtls(obj)
          lupd.update_surface = true
          lupd.update_settings = true

        end

      elseif mouse.context == nil and mouse.my > obj.sections[70].y + lvar.settingsy then

        mouse.mx = mx - obj.sections[70].x
        mouse.my = my - obj.sections[70].y

        if lvar.settingspage == 1 then

          if MOUSE_click(obj.sections[71]) then
            if lvar.livemode ~= 2 or not lvar.dm_trackslocked then
              settings_followselectedtrack = not settings_followselectedtrack
              lupd.update_settings = true
            end
          elseif MOUSE_click(obj.sections[735]) then
            lvar.sliderxy = not lvar.sliderxy
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[81]) then
            settings_mousewheelknob = not settings_mousewheelknob
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[82]) then
            settings_swapctrlclick = not settings_swapctrlclick
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[83]) then
            settings_insertdefaultoneverytrack = not settings_insertdefaultoneverytrack
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[84]) then
            settings_insertdefaultoneverypage = not settings_insertdefaultoneverypage
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[75]) then
            lockx = not lockx
            obj = GetObjects()
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[76]) then
            locky = not locky
            obj = GetObjects()
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[77]) then
            mouse.context = contexts.lockw
            ctlpos = lockw
          elseif MOUSE_click(obj.sections[78]) then
            mouse.context = contexts.lockh
            ctlpos = lockh
          elseif MOUSE_click(obj.sections[80]) then
            settings_showgrid = not settings_showgrid
            osg = settings_showgrid
            if settings_gridsize < 4 then
              settings_showgrid = false
            end
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[79]) then
            mouse.context = contexts.gridslider
            ctlpos = ogrid or settings_gridsize
          elseif MOUSE_click(obj.sections[733]) then
            local retval, c = reaper.GR_SelectColor(_,ConvertColorString(lvar.gridcolor))
            if retval ~= 0 then
              if lvar.Mac_revcol then c = MacRevC(c) end
              lvar.gridcolor = ConvertColor(c)
              settings_gridsize = ogrid
              DrawGrid(settings_gridsize, lvar.gridstyle)
              lupd.update_bg = true
              lupd.update_gfx = true
            end

          elseif MOUSE_click(obj.sections[97]) then
            settings_locksurfaceonnewproject = not settings_locksurfaceonnewproject
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[719]) then
            settings_pagescrolldir = 1-settings_pagescrolldir
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[705]) then
            settings_trackchangemidi = not settings_trackchangemidi
            lupd.update_settings = true
          
          elseif MOUSE_click(obj.sections[707]) then
            lvar.sliderzoom = not lvar.sliderzoom
            lupd.update_settings = true
            
          elseif MOUSE_click(obj.sections[708]) then
            lvar.limitmw = not lvar.limitmw
            lupd.update_settings = true
            
          --[[elseif MOUSE_click(obj.sections[707]) then
            settings_stripautosnap = not settings_stripautosnap
            lupd.update_settings = true]]
            
          elseif MOUSE_click(obj.sections[713]) then
            settings_deletefxwithstrip = not settings_deletefxwithstrip
            lupd.update_settings = true
            
          elseif MOUSE_click(obj.sections[752]) then
            lvar.forcestrippluginguisclosed = not lvar.forcestrippluginguisclosed
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[718]) then
            settings_groupsel = not settings_groupsel
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[727]) then

            if lvar.updateravailable == true then

              RunUpdater()

            end

          elseif MOUSE_click_RB(obj.sections[727]) then

            RollbackMenu(mx, my)

          elseif MOUSE_click(obj.sections[716]) then

            OpenEB(104, 'Number of modulators:', modulator_cnt)
            lupd.update_settings = true
            lupd.update_sidebar = true

          --[[elseif MOUSE_click(obj.sections[708]) then

            OpenEB(100, 'Please choose new row height:', autosnap_rowheight)
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[709]) then

            OpenEB(101, 'Please choose min gap size between strip items:', autosnap_itemgap)
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[710]) then

            OpenEB(102, 'Please choose max gap size between strip items:', autosnap_itemgapmax)
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[711]) then

            OpenEB(103, 'Please choose gap size between strip items in gallery view:', gallery_itemgap)
            lupd.update_gfx = true]]

          elseif MOUSE_click(obj.sections[700]) then
            local abs, _ = GetMOFaders()
            local f = {targettype = 3, mode = 0}
            local fadabs = SetAutomationFader(f ,abs, true, mx, my)
            if fadabs == -2 then
              DeleteFader(abs)
            elseif fadabs ~= -1 then
              AssignFader(fadabs, f)
            end
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[701]) then
            lvar.showtakeover = not lvar.showtakeover
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[734]) then
            lvar.mousefadermode = 1-lvar.mousefadermode
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[70]) then
            --drag offset
            mouse.context = contexts.settingswin_dragoff
            dragsetoff = {dy = mouse.my-obj.sections[70].y, offs = settingswin_off}

          end

        elseif lvar.settingspage == 2 then

          if MOUSE_click(obj.sections[74]) then
            mouse.context = contexts.updatefreq
            oval = settings_updatefreq
          elseif MOUSE_click(obj.sections[731]) then
            OpenEB(731, 'Round robin size:', lvar.ctlupdate_rr)
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[88]) then
            local changeval = true
            if settings_usectlbitmap then
              if reaper.MB("Please do NOT disable this option - it will prevent many things from working properly!\n\nAre you sure you wish to disable this option?"
                        , 'Bitmap Mask Detection', 4) ~= 6 then
                changeval = false
              else
                reaper.MB("On your head be it! :)", 'Bitmap Mask Detection', 0)
              end
            end
            if changeval then
              settings_usectlbitmap = not settings_usectlbitmap
              if settings_usectlbitmap then
                GUI_DrawCtlBitmap()
              else
                Img_SetDim(ctl_bitmap,-1,-1)
              end
            end
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[715]) then
            settings_alwaysrunmods = not settings_alwaysrunmods
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[726]) then
            settings_dragmode = not settings_dragmode
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[72]) then
            settings_disablesendchecks = not settings_disablesendchecks
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[738]) then
            settings_enablednu = not settings_enablednu
            ctls_dnu, ctls_upd, ctls_orr = CtlDNU()
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[740]) then
            OpenEB(740, 'Enter number of undo states (0 = off):', undo.max)
            lupd.update_settings = true
          end

        elseif lvar.settingspage == 3 then

          if MOUSE_click(obj.sections[73]) then
            settings_saveallfxinststrip = not settings_saveallfxinststrip
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[87]) then
            settings_savedatainprojectfolder = not settings_savedatainprojectfolder
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[95]) then

            OpenEB(50, 'Please choose a save subfolder name:', nz(save_subfolder,''))
          elseif MOUSE_click(obj.sections[98]) then
            settings_createbackuponmanualsave = not settings_createbackuponmanualsave
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[728]) then
            settings_backupduringsave = not settings_backupduringsave
            lupd.update_settings = true
          end

        elseif lvar.settingspage == 4 then

          if MOUSE_click(obj.sections[85]) then
            settings_showbars = not settings_showbars
            obj = GetObjects()
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[86]) then
            local retval, c = reaper.GR_SelectColor(_,ConvertColorString(settings_snaplistbgcol))
            if retval ~= 0 then
              if lvar.Mac_revcol then c = MacRevC(c) end
              settings_snaplistbgcol = ConvertColor(c)
              lupd.update_gfx = true
            end
          elseif MOUSE_click(obj.sections[96]) then
            settings_hideeditbaronnewproject = not settings_hideeditbaronnewproject
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[739]) then
            lvar.stripbrowser.showlabel = not lvar.stripbrowser.showlabel
            lupd.update_gfx = true
            
          elseif MOUSE_click(obj.sections[753]) then
            lvar.Mac_revcol = not lvar.Mac_revcol
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[754]) then
            lvar.sortcontrols = not lvar.sortcontrols
            lupd.update_settings = true
            
          elseif MOUSE_click(obj.sections[89]) then
            settings_showminimaltopbar = not settings_showminimaltopbar
            obj = GetObjects()
            lupd.update_surface = true
          elseif MOUSE_click(obj.sections[720]) then
            MenuSkins(mx, my)
            lupd.update_gfx = true
          elseif MOUSE_click(obj.sections[721]) then
            mouse.context = contexts.sbpanszslider
            lvar.panelscaled = true
            lvar.panelscaled_box = {x = obj.sections[721].x,
                                    y = obj.sections[721].y,
                                    w = obj.sections[721].w,
                                    h = obj.sections[721].h,
                                    my = obj.sections[70].y}
            ctlpos = tb_butt_h
          elseif MOUSE_click(obj.sections[722]) then
            mouse.context = contexts.panszslider
            lvar.panelscaled = true
            lvar.panelscaled_box = {x = obj.sections[722].x,
                                    y = obj.sections[722].y,
                                    w = obj.sections[722].w,
                                    h = obj.sections[722].h,
                                    my = obj.sections[70].y}
            ctlpos = pnl_scale
          elseif MOUSE_click(obj.sections[723]) then
            mouse.context = contexts.panfontszslider
            ctlpos = fontscale
          elseif MOUSE_click(obj.sections[724]) then
            mouse.context = contexts.sbfontszslider
            ctlpos = tb_fontscale
          elseif MOUSE_click(obj.sections[725]) then
            mouse.context = contexts.lstfontszslider
            ctlpos = lst_fontscale
          elseif MOUSE_click(obj.sections[702]) then
            local retval, c = reaper.GR_SelectColor(_,ConvertColorString(backcol))
            if retval ~= 0 then
              if lvar.Mac_revcol then c = MacRevC(c) end
              backcol = ConvertColor(c)
              lupd.update_bg = true
              lupd.update_gfx = true
            end
          elseif MOUSE_click_RB(obj.sections[702]) then
            backcol = '16 16 16'
            lupd.update_bg = true
            lupd.update_gfx = true

          --[[elseif MOUSE_click(obj.sections[701]) then
            local _, rel = GetMOFaders()
            local fadrel = SetAutomationFader({targettype = 3, mode = 1},rel)
            lupd.update_gfx = true]]

          elseif MOUSE_click(obj.sections[741]) then
            lvar.bgmatchestrackcolour = lvar.bgmatchestrackcolour + 1
            if lvar.bgmatchestrackcolour > 5 then
              lvar.bgmatchestrackcolour = 0
            end
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[742]) then

            lvar.enablegfxshadows = not lvar.enablegfxshadows
            if lvar.enablegfxshadows then
              lvar.shadowmax = lvar.shadowmax_p
            else
              lvar.shadowmax = 0
            end
            lupd.update_bg = true
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[743]) then
            mouse.context = contexts.shadsz_slider
            ctlpos = lvar.shadow_offsx/lvar.shadowmax

          elseif MOUSE_click(obj.sections[744]) then
            mouse.context = contexts.shadalpha_slider
            ctlpos = lvar.shadow_alpha

          elseif MOUSE_click(obj.sections[745]) then
            mouse.context = contexts.shadfeather_slider
            ctlpos = lvar.shadow_feather

          elseif MOUSE_click(obj.sections[706]) then
            settings_showfaderassignments = not settings_showfaderassignments
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[717]) then
            settings_showmorphpop = not settings_showmorphpop
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[737]) then
            settings_hideplugnotfound = not settings_hideplugnotfound
            lupd.update_gfx = true

          elseif MOUSE_click(obj.sections[751]) then
            lvar.enablelargegui = not lvar.enablelargegui
            reaper.SetExtState(lvar.SCRIPT,'enablelargegui',tostring(lvar.enablelargegui), true)
            OpenMsgBox(1,'Please restart LBX Stripper for change to take effect',1)
            lupd.update_settings = true
          end

        elseif lvar.settingspage == 5 then

          if MOUSE_click(obj.sections[703]) then

            local retval, fn = reaper.GetUserFileNameForRead('~scanboot.xml', 'Locate Nebula Scanboot', '*.XML')
            if retval == true then

              nebscanboot_file = fn
              LoadScanBoot(nebscanboot_file)
              lupd.update_gfx = true

            end

          elseif MOUSE_click(obj.sections[748]) then
            if reaper.JS_Mouse_SetPosition then
              lvar.hidecursordrag = not (lvar.hidecursordrag or false)
              if lvar.hidecursordrag then
                settings_touchmode = false
                lvar.TSM_active = false
              end
            else
              reaper.MB("Please note - mouse pointer hiding requires Julian Sader's API\n\n","Hide mouse pointer",0)
              lvar.hidecursordrag = false
            end
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[749]) then
            if reaper.JS_Mouse_SetPosition then
              settings_touchmode = not settings_touchmode
              lvar.TSM_active = settings_touchmode
              if settings_touchmode == true then
                lvar.hidecursordrag = false
              end
            else
              reaper.MB("Please note - touch mode requires Julian Sader's API\n\n","Touch mode",0)
              settings_touchmode = false
            end
            lupd.update_settings = true

          elseif MOUSE_click(obj.sections[704]) then
            settings_touchFB = not settings_touchFB
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[714]) then
            settings_morphfaderassignedctls = not settings_morphfaderassignedctls
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[730]) then
            logflag = not logflag
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[729]) then
            settings_runstartbat = not settings_runstartbat
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[712]) then
            settings_disablekeysonlockedsurface = not settings_disablekeysonlockedsurface
            lupd.update_settings = true
          elseif MOUSE_click(obj.sections[736]) then
            if not mouse.ctrl then
              local retval, fn = reaper.GetUserFileNameForRead('', 'Locate lbx data file', '*.lbxstripper')
              if retval == true then

                --SaveData()
                SaveProj(true,nil,true)

                lvar.striploadoverride = fn
                lupd.update_gfx = true

                LoadData()

                --newloc = true
                --lvar.newloc_preserveid = true

              end
            else
              lvar.striploadoverride = nil
              lupd.update_gfx = true

              lvar.striploadoverride_active = nil
              LoadData()

              --newloc = true
              --lvar.newloc_preserveid = true
            end

          elseif MOUSE_click(obj.sections[750]) then
            if not mouse.ctrl and reaper.JS_Dialog_BrowseForFolder then
              local retval, folder = reaper.JS_Dialog_BrowseForFolder('Please select resources folder:', paths.resource_path)
              if retval == 1 then
                folder = folder..'/'
                reaper.SetExtState(lvar.SCRIPT,'lbx_alternative_resources_path',tostring(folder), true)
                lvar.altrespath = folder
                lupd.update_settings = true  
                OpenMsgBox(1, 'Please restart the script before making any further changes.', 1)
              end
            elseif mouse.ctrl then
              local folder = reaper.GetResourcePath().."/Scripts/LBX/LBXCS_resources/"
              if folder ~= paths.resource_folder then
                reaper.SetExtState(lvar.SCRIPT,'lbx_alternative_resources_path',tostring(folder), true)
                lvar.altrespath = folder
                lupd.update_settings = true  
              end
              OpenMsgBox(1, 'Please restart the script before making any further changes.', 1)
            end
          elseif MOUSE_click_RB(obj.sections[736]) then

            local mstr = 'Set current setup as override data||Clear'
            gfx.x = mx
            gfx.y = my
            local res = gfx.showmenu(mstr)
            if res > 0 then
              if res == 1 then
              
                local fileName = paths.resource_path..'overridedatafile.lbxstripper'
                local status = PCALL_SaveData(false, true, false, fileName)
                lvar.striploadoverride = fileName
                lvar.striploadoverride_active = nil
                lupd.update_gfx = true
  
                LoadData()
                
              elseif res == 2 then
              
                lvar.striploadoverride = nil
                lupd.update_settings = true

                lvar.striploadoverride_active = nil
                LoadData()

                --newloc = true
                --lvar.newloc_preserveid = true
              end
            end

          end

        end

      end
    
    elseif mouse.context then
    
      local mx, my = mouse.mx, mouse.my
    
      mouse.mx = mx - obj.sections[70].x
      mouse.my = my - obj.sections[70].y
    
      if mouse.context == contexts.settingswin_dragoff then
    
        settingswin_off = dragsetoff.offs + (mouse.my - dragsetoff.dy)
        settingswin_off = F_limit(settingswin_off,(-settingswin_maxh)+settingswin_h,0)
        obj = PosSetWinCtls(obj)
        --DBG(settingswin_off)
        lupd.update_surface = true
    
      elseif mouse.context == contexts.updatefreq then
        local val = F_limit(MOUSE_sliderHBar(obj.sections[74]),0,1)
        if val ~= nil then
          settings_updatefreq = (1-val)/10
          --DBG(settings_updatefreq)
          if oval ~= settings_updatefreq then
            lupd.update_settings = true
          end
          oval = settings_updatefreq
        end
      elseif mouse.context == contexts.lockw then
        local val = F_limit(MOUSE_slider(obj.sections[77]),0,1)
        if val ~= nil then
          val = 1-val
          lockw = F_limit( math.floor((val*1000)/settings_gridsize)*settings_gridsize,64,1000)
          obj = GetObjects()
          lupd.update_gfx = true
        end
      elseif mouse.context == contexts.lockh then
        local val = F_limit(MOUSE_slider(obj.sections[78]),0,1)
        if val ~= nil then
          val = 1-val
          lockh = F_limit( math.floor((val*1000)/settings_gridsize)*settings_gridsize,64,1000)
          obj = GetObjects()
          lupd.update_gfx = true
        end
      elseif mouse.context == contexts.gridslider then
        local val = F_limit(MOUSE_slider(obj.sections[79]),0,1)
        if val ~= nil then
          val = 1-val
          settings_gridsize = F_limit(ctlpos + math.floor((val-0.5)*200),1,128)
          ogrid = settings_gridsize
          if settings_gridsize < 4 then
            settings_showgrid = false
          else
            settings_showgrid = nz(osg,true)
          end
          lupd.update_gfx = true
        end
      
      elseif mouse.context == contexts.sbpanszslider then
        mouse.my = my - lvar.panelscaled_box.my
        local val = F_limit(MOUSE_slider(lvar.panelscaled_box),0,1)
        if val ~= nil then
          val = 1-val
          tb_butt_h = F_limit(ctlpos + math.floor((val-0.5)*200),16,60)
          lupd.update_sidebar = true
          lupd.update_topbar = true
          lupd.update_cbox = true
          resize_display = true
          lupd.update_surface = true
          if mouse.shift then
            local sc = (tb_butt_h+1)/(butt_h+1)
            pnl_scale = math.min(math.floor(sc*100)/100,2)
            lupd.update_stripbrowser = true
            lupd.update_mutate = true
            lupd.update_randomopts = true
            lupd.update_gfx = true
            
          end
          obj = GetObjects()
          --lupd.update_gfx = true
        end
    
      elseif mouse.context == contexts.panszslider then
        mouse.my = my - lvar.panelscaled_box.my
        local val = F_limit(MOUSE_slider(lvar.panelscaled_box),0,1)
        if val ~= nil then
          val = 1-val
          pnl_scale = round(F_limit(ctlpos + (val-0.5)*2,0.9,2),2)
          if pnl_scale ~= ops then
            resize_display = true
            pnlscaleflag = true
            if mouse.shift then
              tb_butt_h = math.ceil((butt_h+1)*pnl_scale)-1
            end
            obj = GetObjects()
            lupd.update_gfx = true
            ops = pnl_scale
            
          end
        end
    
      elseif mouse.context == contexts.panfontszslider then
        local val = F_limit(MOUSE_slider(obj.sections[723]),0,1)
        if val ~= nil then
          val = 1-val
          fontscale = round(F_limit(ctlpos + (val-0.5)*20,0,20),0)
          if fontscale ~= ofs then
            resize_display = true
            --pnlscaleflag = true
            --obj = GetObjects()
            lupd.update_gfx = true
            ofs = fontscale
          end
        end
    
      elseif mouse.context == contexts.sbfontszslider then
        local val = F_limit(MOUSE_slider(obj.sections[724]),0,1)
        if val ~= nil then
          val = 1-val
          tb_fontscale = round(F_limit(ctlpos + (val-0.5)*20,-1,20),0)
          if tb_fontscale ~= tbofs then
            resize_display = true
            --pnlscaleflag = true
            --obj = GetObjects()
            lupd.update_gfx = true
            tbofs = tb_fontscale
          end
        end
    
      elseif mouse.context == contexts.lstfontszslider then
        local val = F_limit(MOUSE_slider(obj.sections[725]),0,1)
        if val ~= nil then
          val = 1-val
          lst_fontscale = round(F_limit(ctlpos + (val-0.5)*20,-1,20),0)
          if lst_fontscale ~= lstofs then
            resize_display = true
            --pnlscaleflag = true
            --obj = GetObjects()
            lupd.update_gfx = true
            lstofs = lst_fontscale
          end
        end
    
      elseif mouse.context == contexts.shadsz_slider then
    
        local val = F_limit(MOUSE_sliderHBar(obj.sections[743]),0,1)
        if val ~= nil then
          lvar.shadow_offsx = round(F_limit(val*lvar.shadowmax,0,lvar.shadowmax),0)
          if lvar.shadow_offsx ~= ooffs then
            lupd.update_bg = true
            lupd.update_gfx = true
            ooffs = lvar.shadow_offsx
          end
        end
    
      elseif mouse.context == contexts.shadalpha_slider then
    
        local val = F_limit(MOUSE_sliderHBar(obj.sections[744]),0,1)
        if val ~= nil then
          lvar.shadow_alpha = val --round(F_limit(val*lvar.shadowmax,0,lvar.shadowmax),0)
          if lvar.shadow_alpha ~= ooffs then
            lupd.update_bg = true
            lupd.update_gfx = true
            ooffs = lvar.shadow_alpha
          end
        end
    
      elseif mouse.context == contexts.shadfeather_slider then
    
        local val = F_limit(MOUSE_sliderHBar(obj.sections[745]),0,1)
        if val ~= nil then
          lvar.shadow_feather = val*50 --round(F_limit(val*lvar.shadowmax,0,lvar.shadowmax),0)
          if lvar.shadow_feather ~= ooffs then
            lupd.update_bg = true
            lupd.update_gfx = true
            ooffs = lvar.shadow_feather
          end
        end
    
      end

      mouse.mx, mouse.my = mx, my
    
    --end
      
    elseif mouse.context == nil then

      if lvar.panelscaled then
        obj = GetObjects()
        lupd.update_gfx = true
        lvar.panelscaled = nil
      end

      local fnd
      local top = math.min(lvar.settings_rrpos+lvar.settings_rr, #lvar.settingsinf[lvar.settingspage])
      local mx = mouse.mx - obj.sections[70].x
      local my = mouse.my - obj.sections[70].y
      for i = lvar.settings_rrpos, top do
        local idx = lvar.settingsinf[lvar.settingspage][i]
        if idx ~= lvar.settings_last and MOUSE_over(obj.sections[idx], mx, my) then
          lvar.settings_last = idx
          fnd = true
          lupd.update_settings = true
          break
        end

      end
      lvar.settings_rrpos = lvar.settings_rrpos + lvar.settings_rr+1
      if lvar.settings_rrpos > #lvar.settingsinf[lvar.settingspage] then
        lvar.settings_rrpos = 1
      end
      if not fnd and lvar.settings_last ~= -1 and not MOUSE_over(obj.sections[lvar.settings_last], mx, my) then
        lvar.settings_last = -1
        lupd.update_settings = true
      end


    end

  end

  function SettingsInfoSetup()

    lvar.settingsinf = {}
    lvar.settingsinf[1] = {71,75,76,77,78,79,80,81,82,83,84,97,719,700,705,718,707,708,--[[709,710,711,]]727,713,716,733,701,734,735,752}
    lvar.settingsinf[2] = {74,731,88,715,726,72,738,740}
    lvar.settingsinf[3] = {73,87,95,98,728}
    lvar.settingsinf[4] = {85,86,89,96,720,721,722,723,724,725,702,706,717,737,751,753,754}
    lvar.settingsinf[5] = {703,704,714,730,729,712,736,749,748,750}

    lvar.settingsinf_txt = {}

    --PAGE 1

    lvar.settingsinf_txt[71] = {'Automatically change current strip to the strip for the selected track','Setting not available when in locked dynamic mode'}
    lvar.settingsinf_txt[80] = {'Show grid in edit mode - the grid will only be displayed if set to 16 pixels or more'}
    lvar.settingsinf_txt[79] = {'Set the grid size (in pixels)'}
    lvar.settingsinf_txt[733] = {'Set the grid colour'}
    lvar.settingsinf_txt[81] = {'When set - the mousewheel alters the value of the control under the mouse','When unset - the mousewheel scrolls the strip surface'}
    lvar.settingsinf_txt[82] = {"When clicking on a strip control - ","swap the action of ctrl+click and double-click ('enter value' and 'set to default' actions)"}
    lvar.settingsinf_txt[83] = {'When first focussing on a new track within Stripper','automatically insert the default strip as defined in STRIP EDIT mode'}
    lvar.settingsinf_txt[84] = {'Like insert default strip on every track option - but also insert the default strip on every page'}
    lvar.settingsinf_txt[97] = {'When opening stripper for first time in a new project - set the surface to locked'}
    lvar.settingsinf_txt[719] = {'When middle mouse button clicked - arrows and mousewheel will scroll the surface horizontally'}
    lvar.settingsinf_txt[700] = {'EXPERIMENTAL: Set the input FADER to be used to alter a control when the mouse hovers above it',
                                 'Useful if you only have a few midi control knobs or do not want to set up controllers for each parameter',
                                 'Currently only works in absolute mode (with soft takeover)'}
    lvar.settingsinf_txt[701] = {'When using a mouseover FADER - display soft-takeover indicator'}
    lvar.settingsinf_txt[734] = {'When using a mouseover FADER - if the hardware has a suitable endless encoder','this mode removes the requirement for soft takeover',
                                 'Works well with Automap enabled devices in conjuction with Faderbox hosted in ReaJS'}
    lvar.settingsinf_txt[705] = {'Ensures midi feedback data is sent for all strip controls when the track is changed'}
    lvar.settingsinf_txt[707] = {'When strip surface zoomed - alter mouse drag sensitivity to compensate when adjusting control values'}
    lvar.settingsinf_txt[708] = {'Limit maximum multiplier value per click of mouse wheel to 1'}
    --[[lvar.settingsinf_txt[707] = {'Automatically positions an inserted strip to the right of the last inserted strip','Useful when using Strip Gallery mode',
                                 'Strips are inserted in rows - each rows height is determined by the Autosnap Row Height setting'}
    lvar.settingsinf_txt[708] = {'Row height (in pixels) of each row when using the autosnap feature for aligning new strips'}
    lvar.settingsinf_txt[709] = {'Minimum gap (in pixels) to allow between inserted strips when using autosnap mode'}
    lvar.settingsinf_txt[710] = {'Maximum gap (in pixels) to allow between inserted strips when using autosnap mode'}
    lvar.settingsinf_txt[711] = {'Gap between strips when displayed in Strip Gallery mode'}]]
    if lvar.updateravailable then
      lvar.settingsinf_txt[727] = {'Click to automatically download the latest stripper files from Github',
                                   'Right-click to open the rollback menu to revert to an older saved backup version of the script'}
    end
    lvar.settingsinf_txt[716] = {'Sets the number of available modulators.  Too many will tax your CPU more - default is 32'}
    lvar.settingsinf_txt[713] = {'When deleting an inserted strip - setting this option will also cause all associated fx plugins to be removed'}
    lvar.settingsinf_txt[752] = {"When inserting a strip - prevent the strip's plugin GUIs from displaying"}

    lvar.settingsinf_txt[75] = {'Restrict the visible size of the strip surface horizontally (in pixels) and prevent horizontal scrolling'}
    lvar.settingsinf_txt[76] = {'Restrict the visible size of the strip surface vertically (in pixels) and prevent vertical scrolling',
                                'You can still scroll the surface using the up/down arrows on the top bar'}
    lvar.settingsinf_txt[77] = {'Set visible width of surface in pixels'}
    lvar.settingsinf_txt[78] = {'Set visible height of surface in pixels'}
    lvar.settingsinf_txt[718] = {'When set - in FX EDIT mode - clicking on a control that is grouped with other controls will select the group'}
    lvar.settingsinf_txt[735] = {'When dragging a control to change its value - both X and Y axis of mouse movement are used.',
                                 'This option means the horiz option in CTL OPTIONS 2 screen will be ignored.'}

    --PAGE 2

    lvar.settingsinf_txt[88] = {'HIGHLY RECOMMENDED THAT THIS OPTION IS SET',
                                'Uses a special bitmap of the strip surface to identify mouse interaction with controls and other objects',
                                'Some Stripper features are not available if this option is switched off'}
    lvar.settingsinf_txt[74] = {'Sets the frequency at which controls values are refreshed',
                                'The bigger the bar - the more accurate and smoother the response will be'}
    lvar.settingsinf_txt[731] = {'Sets the number of controls to be updated each round the update function is called.  Useful to set this value when',
                                 'there are so many controls on a strip that the performance of the script suffers.  Best to start where you notice',
                                 'the performance is sub-optimal - and then lower gradually until performance is acceptable'}
    lvar.settingsinf_txt[726] = {'Set this option to use a quicker alternative way to select and drag controls in FX edit mode',
                                 'Subtle changes to the way controls are displayed/redrawn will occur when using the alternative algorithm'}
    lvar.settingsinf_txt[72] = {'Disable constant monitoring of track sends',
                                'Although monitoring of track sends is useful to try to keep track of any changes - it can also',
                                'cause small but noticeable delays under certain conditions - so can be disabled'}
    lvar.settingsinf_txt[715] = {'Setting this option will cause modulators to continue running even when transport has been paused or stopped'}
    lvar.settingsinf_txt[738] = {"EXPERIMENTAL: Allow the disabling of constant monitoring of a control's value",'This option works in conjunction with the "auto monitor value" option in CTL OPTIONS page 3',
                                 'This option can be useful to save CPU when you do not require a control to keep track of its current value'}
    lvar.settingsinf_txt[740] = {"EXPERIMENTAL: Set maximum number of undo states (edit mode)",'Larger number of undo states will mean more RAM usage',
                                 ''}

    --PAGE 3

    lvar.settingsinf_txt[73] = {'When set - if you save a strip - all plugins loaded on the track will be saved and recalled with the strip',
                                'When unset - only those plugins with controls added to the strip will be saved and recalled with the strip'}
    lvar.settingsinf_txt[87] = {'If set - the script will save the strip data in the same folder as the project'}
    lvar.settingsinf_txt[95] = {'Enter a subfolder to save the script data in.','Use the # symbol to use a folder named after the project'}
    lvar.settingsinf_txt[98] = {'Create a backup data file (lbxbak) when saving manually using the SAVE button on the top bar or Ctrl+S'}
    lvar.settingsinf_txt[728] = {'Create a temporary backup of the old data file when saving','This file will be deleted when the save completes successfully'}

    --PAGE 4

    lvar.settingsinf_txt[85] = {'Show scroll bars around the strip surface to identify the current position'}
    lvar.settingsinf_txt[86] = {'Set the background colour for the snapshot controls dropdown list'}
    lvar.settingsinf_txt[89] = {'When the top bar is hidden - show only the sidebar show/hide button and main menu button'}
    lvar.settingsinf_txt[96] = {'Hide the edit bar when opening stripper in a new project'}
    lvar.settingsinf_txt[720] = {'Select the Stripper skin'}
    lvar.settingsinf_txt[724] = {'Change the font size for the top and side bar buttons','This is an offset amount from the default value'}
    lvar.settingsinf_txt[725] = {'Change the font size for the side bar lists','This is an offset amount from the default value'}
    lvar.settingsinf_txt[722] = {'Set the scale amount for the main script panels to make them larger or smaller'}
    lvar.settingsinf_txt[723] = {'Change the font size for the main script panels','This value is relative to the panel size scale value'}
    lvar.settingsinf_txt[721] = {'Set the height in pixels for the top and side bar buttons'}
    lvar.settingsinf_txt[702] = {'Set the main surface background colour'}
    lvar.settingsinf_txt[706] = {'Draw coloured boxes around controls that have fader and modulator assignments'}
    lvar.settingsinf_txt[717] = {'When morphing - draw a pop-up control on the top left of the strip surface','Use this pop-up to stop/pause/change direction of and crossfade the morph'}
    lvar.settingsinf_txt[737] = {'Removes "plugin not found" text when a plugin is not found - makes it look offline'}
    lvar.settingsinf_txt[751] = {'Allow GUI size > 2048 pixels (with surface size of 4096x4096 pixels)','Note: takes slightly longer to initialize script'}
    lvar.settingsinf_txt[753] = {'Mac colour picker returns values with red and blue swapped','Select this option to correct the colour value returned by the picker'}
    lvar.settingsinf_txt[754] = {'If files do not appear sorted in file lists','Select this option to sort them into alphabetical order','Restart script to activate changes to this option'}

    --PAGE 5

    lvar.settingsinf_txt[703] = {'When using Nebula plugin from Acustica Audio - use this to set the scanboot file',
                                 'This is essential when sharing strips to ensure the different libraries on different computers load correctly'}
    lvar.settingsinf_txt[748] = {'Hides the mouse cursor when dragging a control in live mode',
                                 'Not suitable for touchscreens if you wish to touch-drag a control',
                                 'Prevents hitting top or bottom of screen with mouse pointer'}
    lvar.settingsinf_txt[749] = {'Enables pointer relocation if using stripper on a touchscreen with no mouse input',
                                 '',
                                 'Experimental!'}
    lvar.settingsinf_txt[704] = {'This option flashes a tiny square in the corner of the script window when a control is clicked or released',
                                 'This square can be monitored by an external AutoHotKey script to perform actions when a control is clicked',
                                 'Useful for example to return the mouse to a previous position when using a touch monitor'}
    lvar.settingsinf_txt[714] = {'Unset this option to disallow morphing of fader and modulator assigned controls',
                                 'If a snapshot set has controls being controlled by faders or modulators - you often do not want them',
                                 'being morphed as they can become jumpy and glitchy while the morph is in progress'}
    lvar.settingsinf_txt[730] = {'Create a log file when adding strips - useful for tracking errors if you have any problem strips that will not load',
                                 'The value of this setting will default to off every time you open the script'}
    lvar.settingsinf_txt[729] = {'Execute a batch file called lbxstart.bat located in the resources folder when the script loads',
                                 'You decide what the batch file does - but possible uses are to run an AutoHotKey script to alter the','window properties of the script'}
    lvar.settingsinf_txt[712] = {'Disables keyboard shortcuts when the surface is locked'}
    lvar.settingsinf_txt[736] = {'EXPERIMENTAL: This option forces Stripper to load the specified data file for every project and disables saving',
                                 'Useful if you use Stripper just as a template for performing actions',
                                 'Be careful what you include in the data file as any links to fx plugins etc. will likely not work'}
    lvar.settingsinf_txt[750] = {'EXPERIMENTAL: Change resource folder path',
                                 'Useful if you want to store your Stripper data in another location',
                                 'or try out a new resources folder'}

    --lvar.settingsinf_txt[0] = {''}

    lvar.settings_rrpos = 1
    lvar.settings_rr = 5
    lvar.settings_last = -1
  end

  --returns ctls_dnu, ctls_upd
  function CtlDNU(c)
    local strip = tracks[track_select].strip

    if settings_enablednu == true then
      if strips[strip] then
        local ctls_dnu_ret, ctls_upd_ret, ctls_orr_ret = {}, {}, {}
        if c == nil then
          for i = 1, #strips[strip][page].controls do
            local ctl = strips[strip][page].controls[i]
            ctl.ctli = i
            if ctl.dnu == true then
              ctls_dnu_ret[#ctls_dnu_ret+1] = ctl
            else
              ctls_upd_ret[#ctls_upd_ret+1] = ctl
              if ctl.orr == true then
                ctls_orr_ret[#ctls_orr_ret+1] = ctl
              end
            end
          end
        else
          ctls_dnu_ret = ctls_dnu or {}
          ctls_upd_ret = ctls_upd or {}
          ctls_orr_ret = ctls_orr or {}
          local ctl = strips[strip][page].controls[c]
          if ctl then
            ctl.ctli = c
            if ctl.dnu == true then
              --ctls_dnu[#ctls_dnu+1] = ctl
              ctls_dnu_ret[#ctls_dnu_ret+1] = ctl
            else
              --ctls_upd[#ctls_upd+1] = ctl
              ctls_upd_ret[#ctls_upd_ret+1] = ctl
              if ctl.orr == true then
                ctls_orr_ret[#ctls_orr_ret+1] = ctl
              end
            end
          end
        end
        return ctls_dnu_ret, ctls_upd_ret, ctls_orr_ret
      else
        return {}, {}, {}
      end
    else
      if strips[strip] then
        return {}, strips[strip][page].controls, {}
      else
        return {}, {}, {}
      end
    end
  end

  local function UCV_grmeter(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid then

      local ret, v = reaper.TrackFX_GetNamedConfigParm(tr, ctl.fxnum, 'GainReduction_dB')
      local min = ctl.grmin or -20
      local max = ctl.grmax or 0
      if tonumber(v) then
        v2 = normalize(min, max, v)
      
        local diff
        if tostring(ctl.dval) ~= tostring(v) then
          diff = true
        end
  
        if v ~= '' then
          ctl.val = v2
          ctl.dval = v
          if diff == true then
            ctl.dirty = true
            --lupd.update_ctls = true

            --[[if ctl.midiout then
              SendMIDIMsg(ctl.midiout, ctl.val)
            end]]
          end
        elseif ctl.val ~= v2 then
          ctl.val = v2
          ctl.dval = v
          ctl.dirty = true
          --lupd.update_ctls = true

          --[[if ctl.midiout then
            SendMIDIMsg(ctl.midiout, ctl.val)
          end]]

        --[[else
          ctl.val = 0
          ctl.dval = '0']]
        end

      else
        ctl.val = 0
        ctl.dval = '0'
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end

  end
  
  local function UCV_macro(tr, ctl, strip, rt, c)
  
    local macro = ctl.macroctl
    if macro then
      local m = ctl.macromon
      if m and macro[m] then
        local tgt_c = macro[m].ctl
        if tgt_c then
          
          local tv = GetParamValue_Ctl(tgt_c)
          if tv then
            --local mv = ctls[ctl].val
            local ma = macro[m].A_val
            local mb = macro[m].B_val
            local mv
            if macro[m].inv then
              --v = F_limit(ma - macScale(macro[m].shape,(mv-0.5)*2) * mb,F_limit(ma-mb,0,1),F_limit(ma+mb,0,1))
              mv = -(macScaleInv(macro[m].shape,(tv+ma)/mb*2)/2)
              if mv ~= ctl.val and mv == mv then
                ctl.val = mv
                ctl.dirty = true
              end        
            else
              mv = (macScaleInv(macro[m].shape,(tv-ma)/mb*2)/2)
              if mv ~= ctl.val and mv == mv then
                ctl.val = mv
                ctl.dirty = true
              end
            end
          end
        end
      end
    end
  end
  
  function Cycle_SwitcherPage(ctl)
    local v3 = ctl.val
    local cd = ctl.cycledata
    for i = 1, #cd do
      if cd[i].startval then
        if v3 >= cd[i].startval and v3 < cd[i].nextval-0.001 then
          --selected
          if cd[i].tsp then
            --DBG(cd[i].tsp.swid..'  '..cd[i].tsp.grpid)
            Switcher_Set_GrpID(cd[i].tsp.swid, cd[i].tsp.grpid)
          end
          break
        end
      else
        v3 = round(v3,5)
        if tostring(v3) == tostring(round(cd[i].val,5)) then
          --selected
          if cd[i].tsp then
            --DBG('A '..cd[i].tsp.swid..'  '..cd[i].tsp.grpid)
            Switcher_Set_GrpID(cd[i].tsp.swid, cd[i].tsp.grpid)
          end
          break
        end
      end
    end
  end

  local function UCV_fxname(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid then
      local _, v = reaper.TrackFX_GetFXName(tr, ctl.fxnum, "")
      local diff
      v = CropFXName(v)
      if tostring(ctl.dval) ~= tostring(v) then
        diff = true
      end
      if diff then
        ctl.val = 0
        ctl.dval = v
        ctl.dirty = true
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end
  
  end
  
  local function UCV_fxparam(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid then

      local pn = reaper.TrackFX_GetNumParams(tr,ctl.fxnum)
      if pn ~= lvar.offline_paramcnt then
        if ctl.offline ~= nil then
          ctl.dirty = true
        end
        ctl.offline = nil
      else
        if ctl.offline == nil then
          ctl.dirty = true
        end
        ctl.offline = true
      end

      local _, v = reaper.TrackFX_GetFormattedParamValue(tr, ctl.fxnum, ctl.param, "")
      local v2, min, max = reaper.TrackFX_GetParam(tr, ctl.fxnum, ctl.param)
      --[[if ctl.param == 11 then
        DBG(v2..'  '..ctl.val)
      end]]
      min = ctl.minov or min
      max = ctl.maxov or max
      v2 = normalize(min, max, v2)

      local diff
      if tostring(ctl.dval) ~= tostring(v) or v2 ~= ctl.val then
        diff = true
      end

      if ctl.ctltype == 4 then
        if diff then

          ctl.val = v2
          ctl.dval = v

          --if diff == true then
            ctl.dirty = true
            ctl.cycledata.posdirty = true
            if ctl.midiout then
              SendMIDIMsg(ctl.midiout, ctl.val)
            end
            
            if ctl.cycledata.tspactive then
              Cycle_SwitcherPage(ctl)
            end
          --end
        end
      else
        if v ~= '' then
          ctl.val = v2
          ctl.dval = v
          if diff == true then
            ctl.dirty = true
            if ctl.param_info.paramname == 'Bypass' then
              SetCtlEnabled(ctl.fxnum)
            end
            if ctl.midiout then
              SendMIDIMsg(ctl.midiout, ctl.val)
            end
          end
        elseif ctl.val ~= v2 then
          ctl.val = v2
          ctl.dval = v
          ctl.dirty = true
          if ctl.param_info.paramname == 'Bypass' then
            SetCtlEnabled(ctl.fxnum)
          end
          --lupd.update_ctls = true

          if ctl.midiout then
            SendMIDIMsg(ctl.midiout, ctl.val)
          end

        end
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end

  end

  local function UCV_trackparam(tr, ctl, strip, rt, i)

    local v = GetParamValue2(ctl.ctlcat,
                             tr,
                             nil,
                             ctl.param, i)
    if ctl.ctltype == 4 then
      if tostring(ctl.val) ~= tostring(v) then
        ctl.val = v
        ctl.dirty = true
        ctl.cycledata.posdirty = true
        --lupd.update_ctls = true

        if ctl.midiout then
          SendMIDIMsg(ctl.midiout, ctl.val)
        end
        
        if ctl.cycledata.tspactive then
          Cycle_SwitcherPage(ctl)
        end
      end
    else
      if ctl.val ~= v then
        ctl.val = v
        ctl.dirty = true
        --lupd.update_ctls = true

        if ctl.midiout then
          SendMIDIMsg(ctl.midiout, ctl.val)
        end
      end
    end
  end

  local function UCV_tracksend(tr, ctl, strip, rt, i)

    if settings_disablesendchecks == false and checksends == true then
      local tt = ctl.tracknum
      if tt == nil then
        tt = strips[strip].track.tracknum
      end
      local chk
      local chktbl = lvar.chktbl

      chk, chktbl[tt] = CheckSendGUID(tt,nil,ctl.param_info.paramnum,
                                            ctl.param_info.paramdestguid,
                                            ctl.param_info.paramdestchan,
                                            ctl.param_info.paramsrcchan,
                                            chktbl[tt])
      if chk == false then
        chktbl = CheckStripSends(chktbl)
      end
    end

    local v = GetParamValue2(ctl.ctlcat,
                             tr,
                             nil,
                             ctl.param, i)
    if ctl.ctltype == 4 then
      if tostring(ctl.val) ~= tostring(v) then
        ctl.val = v
        ctl.dirty = true
        ctl.cycledata.posdirty = true
        --lupd.update_ctls = true

        if ctl.midiout then
          SendMIDIMsg(ctl.midiout, ctl.val)
        end
        
        if ctl.cycledata.tspactive then
          Cycle_SwitcherPage(ctl)
        end
      end
    else
      if ctl.val ~= v then
        ctl.val = v
        ctl.dirty = true
        --lupd.update_ctls = true

        if ctl.midiout then
          SendMIDIMsg(ctl.midiout, ctl.val)
        end
      end
    end
  end

  local function UCV_pkmeter(tr, ctl, strip, rt)
    if rt >= time_nextupdate_pkmeter then
      lvar.pkmts = true
      local chd = 0
      local trn = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        trn = ctl.tracknum
        if trn == -3 then
          trn = reaper.GetMediaTrackInfo_Value(tr, 'IP_TRACKNUMBER')-1
        end
      end
      local p = ctl.param
      if peak_info[trn] and peak_info[trn][p % 64] then
        chd = peak_info[trn][p % 64].ch_d
      else
        chd = -150
      end
      if tostring(ctl.val) ~= tostring(chd) then
        ctl.val = chd
        ctl.dirty = true
        --lupd.update_ctls = true

        if ctl.midiout then
          SendMIDIMsg(ctl.midiout, ctl.val)
        end
        --lupd.update_mtrs = true
      end
    end
  end

  local function UCV_action(tr, ctl, strip, rt)

    if not ctl.monext then

      local pi = ctl.param_info
      if pi.paramstr then
        local commid = pi.paramnum
        if pi.paramidx then
          commid = reaper.NamedCommandLookup(pi.paramidx)
        end
        local v = reaper.GetToggleCommandStateEx(pi.paramstr, commid)
        if v ~= -1 and ctl.val ~= v then
          ctl.val = v
          ctl.dirty = true
        end
      end

    else
      if reaper.HasExtState(ctl.monext.section, ctl.monext.key) then
        local rs = ctl.monext.range_start
        local re = ctl.monext.range_end

        local v = tonumber(reaper.GetExtState(ctl.monext.section, ctl.monext.key))
        if v and rs and re then
          local v2 = F_limit((v-rs)/(re-rs),0,1)
          --local v2 = v-rs
          if v2 ~= ctl.val then
            ctl.val = v2
            ctl.dirty = true
          end
        end
      end
    end

  end

  local function UCV_rs5k(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid and ctl.rsdata.samplesidx then
      local lvar = lvar
      local retval, fn = reaper.TrackFX_GetNamedConfigParm(tr, ctl.fxnum, 'FILE')
      local ffn = string.match(fn, '.*[\\/](.*)')
      local si = ctl.rsdata.samplesidx[fn]
      if si and si ~= math.min(math.floor(ctl.val * lvar.maxsamples)+1,#ctl.rsdata.samples) then
        ctl.val = ((si-1) / lvar.maxsamples)
        ctl.dirty = true
        --lupd.update_ctls = true
      end

      --Check keyboard controls - params
      if show_samplemanager == true and rs5k_select == i then
        local pkey = 72 + lvar.rs.pitch
        local kstart = lvar.kb.kstart or -1
        local kend = lvar.kb.kend or -1
        local pstart = 3
        local pend = 4

        local s = reaper.TrackFX_GetParam(tr,ctl.fxnum,pstart)
        local e = reaper.TrackFX_GetParam(tr,ctl.fxnum,pend)
        local pit = reaper.TrackFX_GetParam(tr,ctl.fxnum,15)

        local single = 1/160
        local diff = 0.5-pit

        if s*128 ~= lvar.kb.kstart or
           e*128 ~= lvar.kb.kend or
           round(diff/single) ~= lvar.rs.pitch then
          lvar.rs.pitch = round(diff/single)
          lvar.kb.kstart = s*128
          lvar.kb.kend = e*128
          GUI_DrawKeyboardOverlay(obj, gui)
          lupd.update_samplemanager = true
        end
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end
  end

  local function UCV_takeswitcher(tr, ctl, strip, rt)

    if ctl.iteminfo then
      local item = GetMediaItemByGUID(ctl.iteminfo.guid)
      if item then
        local tkidx = reaper.GetMediaItemInfo_Value(item,'I_CURTAKE')
        if tkidx and tkidx >= 0 then
          tkidx2 = tkidx/takeswitch_max
          if tkidx2 ~= ctl.val then
            ctl.val = tkidx2
            --ctl.tkidx = tkidx
            local take = reaper.GetTake(item, tkidx)
            if take then
              _, ctl.iteminfo.curtake = reaper.GetSetMediaItemTakeInfo_String(take, 'P_NAME', '', false)
            else
              ctl.iteminfo.curtake = 'empty'
            end
            ctl.dirty = true
            --lupd.update_ctls = true
          end
        end
      end
    end
  end

  local function UCV_fxoffline(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid then

      local pn = reaper.TrackFX_GetNumParams(tr,ctl.fxnum)
      if pn ~= lvar.offline_paramcnt then
        if ctl.offline ~= nil then
          ctl.dirty = true
          --lupd.update_ctls = true

          if ctl.midiout then
            SendMIDIMsg(ctl.midiout, ctl.val)
          end
        end
        ctl.offline = nil
        ctl.val = 0
      else
        if ctl.offline == nil then
          ctl.dirty = true
          --lupd.update_ctls = true

          if ctl.midiout then
            SendMIDIMsg(ctl.midiout, ctl.val)
          end
        end
        ctl.offline = true
        ctl.val = 1
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end
  end

  local function UCV_fxmulti(tr, ctl, strip, rt)

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
    if ctl.fxguid == fxguid then
      local state = FXMulti_GetState(tr, ctl)

      local v = (state-1)/(#lvar.fxmulti_table-1)
      if ctl.val ~= v then
        ctl.val = v
        ctl.dirty = true
      end
    else
      if ctl.fxfound then
        CheckStripControls()
      end
    end
  end

  local function UCV_fxgui(tr, ctl, strip, rt)

    if not ctl.fxnum then return end

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)

    if ctl.fxguid and ctl.fxguid ~= fxguid then

      if ctl.fxfound then
        CheckStripControls()
      end
    end
    
    if ctl.fxguid and ctl.fxguid == fxguid then
      local v = 0
      if reaper.TrackFX_GetOpen(tr, ctl.fxnum) then
        v = 1
      end
      --DBG(ctl.val)
      if ctl.val ~= v then
        ctl.val = v
        ctl.dirty = true
      end
    end
    
  end

  local function UCV_rcm(tr, ctl, strip, rt)

    if not ctl.fxnum then return end

    local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)

    if ctl.fxguid and ctl.fxguid ~= fxguid then

      if ctl.fxfound then
        CheckStripControls()
      end
    end
    
  end

  local function UCV_midieditor_pageswitch(tr, ctl, strip, rt)

    if mode == 0 then
      local hwnd = reaper.MIDIEditor_GetActive()
      if hwnd then
        if page ~= tonumber(ctl.param_info.paramidx) then
          setpage_wait = tonumber(ctl.param_info.paramidx)
          SetPage(setpage_wait)
          return true
        end
      else
        if page ~= ctl.param then
          setpage_wait = tonumber(ctl.param)
          SetPage(setpage_wait)
          return true
        end
      end
    end
  end

  local function UCV_paramvalue(tr, ctl, strip, rt)

    --get control under mouse
    if mouse.context == nil then
      local strip = tracks[track_select].strip
      local tctls = strips[strip][page].controls
      local c, stripidx, stripid = GetControlAtXY(strip, page, mouse.mx, mouse.my)
      if c and tctls[c] and (ctl.ctlcat == ctlcats.paramvalue_glob or tctls[c].id == ctl.id) then
        local tctl = tctls[c]
        ctl.pvc_ctl = c
        local v
        if tonumber(ctl.param_info.paramidx or 0) == 0 then
          v = tctl.display_value
        elseif tonumber(ctl.param_info.paramidx) == 1 then
          if (tctl.ctlname_override or '') ~= '' then
            v = tctl.ctlname_override
          else
            if ctl.ctlcat == ctlcats.fxparam then
              _, v = reaper.TrackFX_GetParamName(tr, tctl.fxnum, tctl.param, '')
            else
              v = tctl.param_info.paramname
            end
          end
        end
        if v ~= ctl.pvc_val then
          ctl.pvc_val = v
          ctl.dirty = true
        end
      elseif ctl.pvc_val ~= nil then
        ctl.pvc_val = nil
        ctl.pvc_ctl = nil
        ctl.dirty = true
        --lupd.update_ctls = true
      end
    
    elseif ctl.pvc_ctl then
      local c = ctl.pvc_ctl
      local strip = tracks[track_select].strip
      local tctl = strips[strip][page].controls[c]
      if tctl then
        --local v = tctl.display_value
        local v
        if tonumber(ctl.param_info.paramidx or 0) == 0 then
          v = tctl.display_value
        elseif tonumber(ctl.param_info.paramidx) == 1 then
          if (tctl.ctlname_override or '') ~= '' then
            v = tctl.ctlname_override
          else
            if ctl.ctlcat == ctlcats.fxparam then
              _, v = reaper.TrackFX_GetParamName(tr, tctl.fxnum, tctl.param, '')
            else
              v = tctl.param_info.paramname
            end
          end
        end
        if v ~= ctl.pvc_val then
          ctl.pvc_val = v
          ctl.dirty = true
        end
      end
    end
  end

  local function UCV_sk2ctl(tr, ctl, strip, rt, c)

    --check lmode
    --if ctl.param == 4 then
      if tonumber(reaper.GetExtState('SK2DATA_ASSIGN', 'UPDATING')) == 1 then return end
      
      reaper.gmem_attach('LBX_SK2_SharedMem')
      local i = tonumber(ctl.param_info.paramidx)
      if i then
        if lvar.sk2data_slots and lvar.sk2data_slots[i] and lvar.sk2data_assign and lvar.sk2data_assign[i] then
          --local name = reaper.GetExtState('SK2DATA_SLOTS', string.format('%i',i)..'_NAME')
          local fxslot
          --if reaper.HasExtState('SK2DATA_ASSIGN', string.format('%i',i)..'_FXSLOT') then
            fxslot = reaper.GetExtState('SK2DATA_ASSIGN', string.format('%i',i)..'_FXSLOT')
            if fxslot == '' then
              fxslot = nil
            end
            if fxslot ~= ctl.ofxslot_name then
              ctl.ofxslot_name = fxslot
              ctl.fxslot_name = CropFXName3(fxslot)
              ctl.dirty = true
              SetCtlDirty(c)
              lupd.update_ctls = true
            end
          --else
          --  fxslot = ''
          --end
          if lvar.show_slotnameoninactivesk2ctls == 2 and not ctl.slot_name then
            ctl.slot_name = lvar.sk2data_slots[i].name
          end
          
          local dval = reaper.GetExtState('SK2DATA_ASSIGN', string.format('%i',i)..'_DVAL')
          local sscolor = reaper.GetExtState('SK2DATA_ASSIGN', string.format('%i',i)..'_SSCOLOR')
          --DBG(i..'  '..tostring(lvar.sk2data_slots[i].active))
          if lvar.sk2data_assign[i].active == 1 then
            if lvar.sk2data_slots[i].lmode == 4 then
              
              if sscolor == '' then sscolor = nil end
              
              local val = reaper.gmem_read(lvar.gm_fb.bstate + i)
              
              if ctl.val ~= val or dval ~= ctl.dval or (tonumber(sscolor) and tonumber(sscolor) ~= lvar.sk2data_assign[i].sscolor) then

                if tonumber(sscolor) then
                  lvar.sk2data_assign[i].sscolor = tonumber(sscolor)
                end
                ctl.val = val
                ctl.dval = dval
                ctl.fxslot_name = CropFXName3(fxslot)
                ctl.dirty = true
                --DBG(i..'  '..tostring(fxslot))
              end
            else
              local val = reaper.gmem_read(lvar.gm_fb.fader_val + i)/16383
              if ctl.val ~= val or ctl.dval ~= dval then
              --DBG(val..'  '..tostring(ctl.val))
                if lvar.sk2lock ~= i then
                  ctl.dval = dval
                  ctl.val = val
                  ctl.dirty = true
                end
              end
            
            end
            if dval and ctl.dval ~= dval then
              ctl.dval = dval
              ctl.dirty = true
            end
          else
            if lvar.show_slotnameoninactivesk2ctls == 1 and not ctl.slot_name then
              ctl.slot_name = lvar.sk2data_slots[i].name
            end
            ctl.dval = '' ---- ''
            if ctl.val ~= 0 then
              ctl.val = 0
              ctl.dirty = true
            end
          end
        end
      end
    --else
    
    --end
    
  end
  
  local function UCV_infoctl(tr, ctl, strip, rt)

    if ctl.param == 1 then
      local iv = reaper.GetTrackState(tr)
      if ctl.info_val ~= iv then
        ctl.info_val = iv
        ctl.dirty = true
      end
    elseif ctl.param == 2 then
      if ctl.tracknum == -3 and lvar.slotoffset[ctl.tracknum] then
        local t = reaper.GetSelectedTrack2(0,0,true)
        if lvar.slotoldtrack and lvar.slotoldtrack ~= t then
          lvar.slotoffset[ctl.tracknum] = 0
        end
        lvar.slotoldtrack = t
      end
      local slot = tonumber(ctl.param_info.paramidx or 0) + (lvar.slotoffset[ctl.tracknum or tracks[track_select].tracknum] or 0)
      local _, fxname = reaper.TrackFX_GetFXName(tr,slot,'')
      if fxname and fxname ~= '' then
        local en = GetFXEnabled(ctl.tracknum or tracks[track_select].tracknum, slot)
        local iv = CropFXName2(fxname)
        if ctl.info_val ~= iv or en ~= ctl.info_en then
          ctl.info_val = iv
          ctl.info_col = nil
          if not en then
            ctl.info_col = '160 0 0'
          end
          ctl.info_en = en
          ctl.dirty = true
        end
        local vis = reaper.TrackFX_GetOpen(tr, slot)
        v = 0
        if vis then v = 1 end

        if v ~= ctl.val then
          ctl.val = v
          ctl.dirty = true
        end

      else
        local iv = '[Slot Empty]' --'[FX '..string.format('%i',slot+1)..': Empty]'
        if ctl.info_val ~= iv then
          ctl.info_val = iv
          ctl.info_col = '64 64 64'
          ctl.val = 0
          ctl.dirty = true
        end
      end
    end
  end

  local function UCV_switcher_pagesel(tr, ctl, strip, rt)

    local sw = switchers[ctl.switcherid]
    if sw and (sw.switchmode or 0) == 0 then
      local v = 0
      if sw.current == ctl.param then
        v = 1
      end

      if ctl.val ~= v then
        ctl.val = v
        ctl.dirty = true
      end
    end

  end

  local function UCV_switcher(tr, ctl, strip, rt)

    if switchers[ctl.switcherid] and (switchers[ctl.switcherid].switchmode or 0) == 1 then
      if ctl.fxnum then
        local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
        if ctl.fxguid ~= fxguid then
          if ctl.fxfound then
            CheckStripControls()
          end
        end
      end
    end
  end

  local function UCV_statectl(tr, ctl, strip, rt)

    if ctl.ctli ~= trackfxparam_select or mouse.context == nil then
      local extname = ctl.stateinfo.extname
      local key = ctl.stateinfo.key
      if extname and key then
        local v = tonumber(reaper.GetExtState(extname, key))
        if v then
          local v2 = (v-ctl.stateinfo.min)/(ctl.stateinfo.max-ctl.stateinfo.min)
          if v2 ~= ctl.val then
            --DBG(extname..'  '..key..'  '..v2)
            ctl.val = v2
            ctl.dirty = true
          end
        end
      end
    end
  end

  local function UCV_statectl_str(tr, ctl, strip, rt)
    --if ctl.ctli ~= trackfxparam_select or mouse.context == nil then
      local extname = ctl.stateinfo.extname
      local key = ctl.stateinfo.key
      if extname and key then
        local v = reaper.GetExtState(extname, key)
        if v then
          if v ~= ctl.param_info.paramstr then
            --DBG(extname..'  '..key..'  '..v2)
            ctl.param_info.paramstr = v
            ctl.dirty = true
          end
        end
      end
    --end
  end

  --local function UCV_(ctl, rt)
  --end

  local function UpdateORR(rt, ctls_upd)
    if tracks[track_select] then
      --check track
      local strip = tracks[track_select].strip

      if not strips or strip == nil or not strips[strip] then return end

      if CheckTrack(strips[strip].track, strip) then
        if tracks[track_select] and strips[tracks[track_select].strip] then
          local strip = tracks[track_select].strip

          local tr2
          if lvar.livemode == 2 then
            tr2 = GetTrack(lvar.dynamicmode_trn)
          else
            tr2 = GetTrack(strips[strip].track.tracknum)
          end
          if tr2 ~= nil then
            if strips and strips[strip] then
              lvar.chktbl = {}
              lvar.pkmts = false

              for updi = 1, #ctls_upd do
                --check fx
                local ctl = ctls_upd[updi]

                if ctl then

                  local i = updi
                  if settings_enablednu then
                    i = ctl.ctli
                  end

                  if not ctl.trackmissing or ctl.tracknum == -3 then

                    tr = tr2
                    local tr_found = true
                    if ctl.tracknum ~= nil then
                      if ctl.tracknum ~= -3 then
                        tr_found = CheckTrack(tracks[ctl.tracknum], strip, page, i)
                        if tr_found then
                          tr = GetTrack(ctl.tracknum)
                        end
                      else
                        tr = GetTrack(ctl.tracknum)

                        if not tr then
                          tr_found = false
                        end
                      end
                    end

                    if tr_found and tr then

                      local UCVf = lvar.ctlcats_ucv_funcs[ctl.ctlcat]
                      if UCVf then
                        if UCVf(tr, ctl, strip, rt, i) then
                          break
                        end
                      end
                      if ctl.dirty == true or (ctl.tracknum == -3 and seltrack ~= lvar.oseltrack) --[[fuc]] then

                        SetCtlDirty(i)
                        lupd.update_ctls = true
                      end

                    else
                      --track not found
                      if ctl.tracknum ~= -3 then
                        ctl.fxfound = false
                        ctl.trackmissing = true
                      elseif ctl.val ~= 0 or ctl.info_val ~= nil then
                        ctl.val = 0
                        ctl.info_val = nil
                        SetCtlDirty(i)
                        lupd.update_ctls = true
                      end
                    end
                  end
                else
                  --ctl not found -- hmm - what to do here...

                end
              end

              lvar.chktbl = nil
              if lvar.pkmts then
                time_nextupdate_pkmeter = rt + settings_updatefreq_pkmeter
              end
              if lvar.ctlupdate_rr then
                lvar.ctlupdate_pos = lvar.ctlupdate_pos+lvar.ctlupdate_rr+1
              end
            end
          end
        end
      end
    end
    lvar.oseltrack = reaper.GetSelectedTrack2(0,0,true)

  end

  function UpdateControlValues3(rt, ctls_upd, ctls_orr, force)

    --if reaper.Audio_IsRunning() ~= 1 then DBG('F') return end
    --local ttt = reaper.time_precise()
    if rt == nil then rt = time_nextupdate end

    if rt >= time_nextupdate then
      --local suf = settings_updatefreq
      --if mode == 1 then suf = 0.2 end
      local seltrack = reaper.GetSelectedTrack2(0,0,true)

      time_nextupdate = rt + settings_updatefreq
      if ctls_upd and #ctls_upd > 0 and tracks[track_select] then
        --check track
        local strip = tracks[track_select].strip

        if not strips or strip == nil or not strips[strip] then return end

        if CheckTrack(strips[strip].track, strip) then
          if tracks[track_select] and strips[tracks[track_select].strip] then
            local strip = tracks[track_select].strip

            local tr2
            if lvar.livemode == 2 then
              tr2 = GetTrack(lvar.dynamicmode_trn)
            else
              tr2 = GetTrack(strips[strip].track.tracknum)
            end
            if tr2 ~= nil then

              if strips and strips[strip] then
                lvar.chktbl = {}
                lvar.pkmts = false

                --rr

                local rrend
                if lvar.ctlupdate_rr and not force then
                  if not ctls_upd[lvar.ctlupdate_pos] then
                    lvar.ctlupdate_pos = 1
                  end
                  rrend = math.min(lvar.ctlupdate_pos+(lvar.ctlupdate_rr or 0),#ctls_upd)
                end

                --local t = reaper.time_precise()
                for updi = lvar.ctlupdate_pos, (rrend or #ctls_upd) do
                  --check fx
                  local ctl = ctls_upd[updi]

                  if ctl then

                    local i = updi
                    if settings_enablednu then
                      i = ctl.ctli
                    end

                    if not ctl.trackmissing or ctl.tracknum == -3 then

                      --[[local fuc
                      if ctl.tracknum == -3 and seltrack ~= lvar.oseltrack then
                        fuc = true
                      end]]

                      tr = tr2
                      local tr_found = true

                      if ctl.tracknum ~= nil then
                        if ctl.tracknum ~= -3 then
                          tr_found = CheckTrack(tracks[ctl.tracknum], strip, page, i)
                          if tr_found then
                            tr = GetTrack(ctl.tracknum)
                          end
                        else
                          tr = GetTrack(ctl.tracknum)

                          if not tr then
                            tr_found = false
                          end
                        end
                      end

                      if tr_found and tr then

                        local UCVf = lvar.ctlcats_ucv_funcs[ctl.ctlcat]
                        local odval = ctl.dval
                        if UCVf then
                          
                          if UCVf(tr, ctl, strip, rt, i) then
                            break
                          end
                        end

                        if ctl.dirty == true then
                          if ctl.animatetime --[[and not ctl.animate_et]] and lvar.ctltype_buttons[ctl.ctltype] and ctl.oval then
                            SetAnimate_Ctl(ctl)
                          end
                          if xPnl.HUD.visible == true and ctl.ctltype ~= 5 and odval ~= ctl.dval then
                            SetHUD(ctl)
                          end
                        end
                        
                        if ctl.animate_et then
                          local animframe
                          local frames = ctl.ctl_info.frames-1 --ctl_files[knob_select].frames-1 
                        
                          local t = macScale(ctl.animateshape or 1, math.min(((reaper.time_precise() - ctl.animate_st) / (ctl.animate_et - ctl.animate_st))*1000 ,1))
                          local framediff = math.floor((ctl.animate_ef - ctl.animate_sf) * frames)
                          if framediff > 0 then                            
                            animframe = math.floor(ctl.animate_sf*frames) + math.floor(t*math.abs(framediff))
                          else
                            animframe = math.floor(ctl.animate_sf*frames) - math.floor(t*math.abs(framediff))
                          end
                          if animframe ~= ctl.animate_frame then
                            ctl.animate_frame = animframe
                            ctl.dirty = true
                          end
                          if t >= 1 then
                            ctl.animate_et = nil
                            ctl.animate_frame = nil
                          end
                        
                        end

                        if ctl.dirty == true or (ctl.tracknum == -3 and seltrack ~= lvar.oseltrack) --[[fuc]] then

                          SetCtlDirty(i)
                          lupd.update_ctls = true
                          ctl.oval = ctl.val
                        end

                      else
                        --track not found
                        if ctl.tracknum ~= -3 then
                          ctl.fxfound = false
                          ctl.trackmissing = true
                        elseif ctl.val ~= 0 or ctl.info_val ~= nil then
                          ctl.val = 0
                          ctl.info_val = nil
                          SetCtlDirty(i)
                          lupd.update_ctls = true
                        end
                      end
                    end
                  else
                    --ctl not found -- hmm - what to do here...

                  end
                end

                --DBG((reaper.time_precise()-t)*100000000)
                lvar.chktbl = nil
                if lvar.pkmts then
                  time_nextupdate_pkmeter = rt + settings_updatefreq_pkmeter
                end
                if lvar.ctlupdate_rr then
                  lvar.ctlupdate_pos = lvar.ctlupdate_pos+lvar.ctlupdate_rr+1
                end
              end
            end
          end
        end
      end
      lvar.oseltrack = reaper.GetSelectedTrack2(0,0,true)

    elseif ctls_orr and #ctls_orr > 0 then
      UpdateORR(rt, ctls_orr)
    end

    --DBG(reaper.time_precise() - ttt)

  end

  function SetUp_UCV_Functions()
    local tmp = {}

    tmp[ctlcats.macro] = UCV_macro
    tmp[ctlcats.gr_meter] = UCV_grmeter
    tmp[ctlcats.fxparam] = UCV_fxparam
    tmp[ctlcats.trackparam] = UCV_trackparam
    tmp[ctlcats.tracksend] = UCV_tracksend
    tmp[ctlcats.action] = UCV_action
    tmp[ctlcats.pkmeter] = UCV_pkmeter
    tmp[ctlcats.fxoffline] = UCV_fxoffline
    tmp[ctlcats.rs5k] = UCV_rs5k
    tmp[ctlcats.takeswitcher] = UCV_takeswitcher
    tmp[ctlcats.fxmulti] = UCV_fxmulti
    tmp[ctlcats.fxgui] = UCV_fxgui
    tmp[ctlcats.rcm_switch] = UCV_rcm
    tmp[ctlcats.midieditor_pageswitch] = UCV_midieditor_pageswitch
    tmp[ctlcats.paramvalue_glob] = UCV_paramvalue
    tmp[ctlcats.paramvalue_strip] = UCV_paramvalue
    tmp[ctlcats.infoctl] = UCV_infoctl
    tmp[ctlcats.switcher] = UCV_switcher
    tmp[ctlcats.statectl] = UCV_statectl
    tmp[ctlcats.statectl_str] = UCV_statectl_str
    tmp[ctlcats.switcher_pagesel] = UCV_switcher_pagesel
    tmp[ctlcats.sk2ctl] = UCV_sk2ctl
    tmp[ctlcats.fxname] = UCV_fxname
    --tmp[ctlcats.] = UCV_

    lvar.ctlcats_ucv_funcs = tmp
  end


  function FXMulti_GetState2(v)
    --local v = (state-1)/(#lvar.fxmulti_table-1)
    return round(v * (#lvar.fxmulti_table-1)) + 1
  end

  function FXMulti_GetState(tr, ctl)
    local state = 1

    local pn = reaper.TrackFX_GetNumParams(tr,ctl.fxnum)
    if pn == lvar.offline_paramcnt then
      state = 4
    else
      local byp = reaper.TrackFX_GetParam(tr,ctl.fxnum,pn-lvar.pn_byp) --lvar.pn_byp
      if byp == 1 then
        state = 3
      else
        local wet = reaper.TrackFX_GetParam(tr,ctl.fxnum,pn-lvar.pn_wet) --lvar.pn_wet
        if wet == 0 then
          state = 2
        end
      end

    end
    return state
  end

  function FXMulti_AddFXFindFX(guid)
    local trcnt = reaper.GetNumTracks()
    for t = -1, trcnt-1 do

      local tr = GetTrack(t)
      if tr then
        local fxcnt = reaper.TrackFX_GetCount(tr)
        local fnd
        for f = 0, fxcnt-1 do

          if guid == reaper.TrackFX_GetFXGUID(tr, f) then

            local ntrguid = GetTrackGUID(tr)
            return {fxnum = f, guid = guid, trn = t, trguid = ntrguid}

          end

        end
      end
    end

    --not found

  end

  function FXMulti_SetMainFX(ctl, state)

    local trn = ctl.tracknum or tracks[track_select].tracknum
    local fxnum = ctl.fxnum
    if state == 1 then
      SetFXOffline3(trn, fxnum, 0, 0)
      SetFXWet(trn, fxnum, 1)

    elseif state == 2 then
      SetFXOffline3(trn, fxnum, 0, 0)
      SetFXWet(trn, fxnum, 0)

    elseif state == 3 then
      SetFXOffline3(trn, fxnum, 0, 1)

    elseif state == 4 then
      SetFXOffline3(trn, fxnum, 1, nil)

    end

    SetCtlEnabled(fxnum)
    lupd.update_ctls = true
  end

  function FXMulti_SetAddFX(ctl, state)

    local addfx = ctl.addfx
    --won, woff, byp, off
    local trchunk = {}
    local hitrn = -2
    local notfnd

    local afxcnt = 0
    if addfx then
      afxcnt = #addfx
    end

    if afxcnt == 0 then return end

    local fxnums = {}
    --state = round(state)
    for a = 1, afxcnt do

      local tr = GetTrack(addfx[a].trn)
      if tr then
        if addfx[a].guid ~= reaper.TrackFX_GetFXGUID(tr, addfx[a].fxnum) then
          addfx[a] = FXMulti_AddFXFindFX(addfx[a].guid)
        end
      else
        addfx[a] = FXMulti_AddFXFindFX(addfx[a].guid)
      end


      if addfx[a] then
        local trn = addfx[a].trn
        local fxnum = addfx[a].fxnum
        local trguid = addfx[a].trguid
        local guid = addfx[a].guid

        fxnums[#fxnums+1] = fxnum

        hitrn = math.max(hitrn,trn)
        if state == 1 then
          trchunk[trn] = SetFXOffline3(trn, fxnum, 0, 0, true, trchunk[trn])

        elseif state == 2 then
          trchunk[trn] = SetFXOffline3(trn, fxnum, 0, 0, true, trchunk[trn])

        elseif state == 3 then
          trchunk[trn] = SetFXOffline3(trn, fxnum, 0, 1, true, trchunk[trn])

        elseif state == 4 then
          trchunk[trn] = SetFXOffline3(trn, fxnum, 1, nil, true, trchunk[trn])

        end
      else
        notfnd = true
      end
    end

    if notfnd == true then
      ctl.addfx = Table_RemoveNils(addfx, afxcnt)
      addfx = ctl.addfx
    end

    for t = -1, hitrn do
      if trchunk[t] then
        local tr = GetTrack(t)
        SetTrackChunk(tr, trchunk[t])
      end
    end

    for a = 1, #addfx do

      local trn = addfx[a].trn
      local fxnum = addfx[a].fxnum
      local trguid = addfx[a].trguid
      local guid = addfx[a].guid

      if state == 1 then
        SetFXWet(trn, fxnum, 1)

      elseif state == 2 then
        SetFXWet(trn, fxnum, 0)

      end
    end

    if #fxnums > 0 then
      SetCtlsEnabled(fxnums, state)
      lupd.update_ctls = true
    end

  end

  function UpdateControlValues2(rt)

    if rt >= time_nextupdate then
      --local suf = settings_updatefreq
      --if mode == 1 then suf = 0.2 end

      time_nextupdate = rt + settings_updatefreq
      if strips and tracks[track_select] and strips[tracks[track_select].strip] and #strips[tracks[track_select].strip][page].controls > 0 then
        --check track
        local strip = tracks[track_select].strip

        if CheckTrack(strips[strip].track, strip) then
          if tracks[track_select] and strips[tracks[track_select].strip] then
            local strip = tracks[track_select].strip

            local tr2 = GetTrack(strips[strip].track.tracknum)
            if tr2 ~= nil then
              if strips and strips[strip] then
                local chktbl = {}
                local pkmts = false

                --rr

                local rrend
                if lvar.ctlupdate_rr then
                  if not strips[strip][page].controls[lvar.ctlupdate_pos] then
                    lvar.ctlupdate_pos = 1
                  end
                  rrend = math.min(lvar.ctlupdate_pos+(lvar.ctlupdate_rr or 0),#strips[strip][page].controls)
                end

                for i = lvar.ctlupdate_pos, (rrend or #strips[strip][page].controls) do
                  --check fx
                  local ctl = strips[strip][page].controls[i]

                  if not ctl.trackmissing then

                    tr = tr2
                    local tr_found = true
                    if ctl.tracknum ~= nil then
                      tr_found = CheckTrack(tracks[ctl.tracknum], strip, page, i)
                      if tr_found then
                        tr = GetTrack(ctl.tracknum)
                      end
                    end

                    if tr_found then
                      if ctl.ctlcat == ctlcats.fxparam then
                        local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
                        if ctl.fxguid == fxguid then

                          local pn = reaper.TrackFX_GetNumParams(tr,ctl.fxnum)
                          if pn ~= lvar.offline_paramcnt then
                            if ctl.offline ~= nil then
                              ctl.dirty = true
                            end
                            ctl.offline = nil
                          else
                            if ctl.offline == nil then
                              ctl.dirty = true
                            end
                            ctl.offline = true
                          end

                          local _, v = reaper.TrackFX_GetFormattedParamValue(tr, ctl.fxnum, ctl.param, "")
                          local v2, min, max = reaper.TrackFX_GetParam(tr, ctl.fxnum, ctl.param)
                          min = ctl.minov or min
                          max = ctl.maxov or max
                          v2 = normalize(min, max, v2)

                          --[[local v2 = GetParamValue2(ctl.ctlcat,
                                                   tr,
                                                   ctl.fxnum,
                                                   ctl.param, i)]]

                          if ctl.ctltype == 4 then
                            if tostring(ctl.dval) ~= tostring(v) then

                              ctl.val = v2
                              ctl.dval = v
                              ctl.dirty = true
                              ctl.cycledata.posdirty = true
                              lupd.update_ctls = true

                              if ctl.midiout then
                                SendMIDIMsg(ctl.midiout, ctl.val)
                              end
                            end
                          else
                            if v ~= '' then
                              if ctl.dval ~= v then
                                ctl.val = v2
                                ctl.dval = v
                                ctl.dirty = true
                                if ctl.param_info.paramname == 'Bypass' then
                                  SetCtlEnabled(ctl.fxnum)
                                end
                                lupd.update_ctls = true

                                if ctl.midiout then
                                  SendMIDIMsg(ctl.midiout, ctl.val)
                                end
                              end
                            elseif ctl.val ~= v2 then
                              ctl.val = v2
                              ctl.dval = v
                              ctl.dirty = true
                              if ctl.param_info.paramname == 'Bypass' then
                                SetCtlEnabled(ctl.fxnum)
                              end
                              lupd.update_ctls = true

                              if ctl.midiout then
                                SendMIDIMsg(ctl.midiout, ctl.val)
                              end

                            end
                          end
                        else
                          if ctl.fxfound then
                            CheckStripControls()
                          end
                        end
                      elseif ctl.ctlcat == ctlcats.trackparam then
                        local v = GetParamValue2(ctl.ctlcat,
                                                 tr,
                                                 nil,
                                                 ctl.param, i)
                        if ctl.ctltype == 4 then
                          if tostring(ctl.val) ~= tostring(v) then
                            ctl.val = v
                            ctl.dirty = true
                            ctl.cycledata.posdirty = true
                            lupd.update_ctls = true

                            if ctl.midiout then
                              SendMIDIMsg(ctl.midiout, ctl.val)
                            end
                          end
                        else
                          if ctl.val ~= v then
                            ctl.val = v
                            ctl.dirty = true
                            lupd.update_ctls = true

                            if ctl.midiout then
                              SendMIDIMsg(ctl.midiout, ctl.val)
                            end
                          end
                        end

                      elseif ctl.ctlcat == ctlcats.tracksend then

                        if settings_disablesendchecks == false and checksends == true then
                          local tt = ctl.tracknum
                          if tt == nil then
                            tt = strips[strip].track.tracknum
                          end
                          local chk

                          chk, chktbl[tt] = CheckSendGUID(tt,nil,ctl.param_info.paramnum,
                                                                ctl.param_info.paramdestguid,
                                                                ctl.param_info.paramdestchan,
                                                                ctl.param_info.paramsrcchan,
                                                                chktbl[tt])
                          if chk == false then
                            chktbl = CheckStripSends(chktbl)
                          end
                        end

                        local v = GetParamValue2(ctl.ctlcat,
                                                 tr,
                                                 nil,
                                                 ctl.param, i)

                        if ctl.ctltype == 4 then
                          if tostring(ctl.val) ~= tostring(v) then
                            ctl.val = v
                            ctl.dirty = true
                            ctl.cycledata.posdirty = true
                            lupd.update_ctls = true

                            if ctl.midiout then
                              SendMIDIMsg(ctl.midiout, ctl.val)
                            end
                          end
                        else
                          if ctl.val ~= v then
                            ctl.val = v
                            ctl.dirty = true
                            lupd.update_ctls = true

                            if ctl.midiout then
                              SendMIDIMsg(ctl.midiout, ctl.val)
                            end
                          end
                        end
                      elseif ctl.ctlcat == ctlcats.pkmeter then
                        if rt >= time_nextupdate_pkmeter then
                          pkmts = true
                          local chd = 0
                          local trn = strips[strip].track.tracknum
                          if ctl.tracknum ~= nil then
                            trn = ctl.tracknum
                          end
                          local p = ctl.param
                          local v = GetParamValue2(ctl.ctlcat,
                                                   tr,
                                                   nil,
                                                   p, i)
                          if peak_info[trn] and peak_info[trn][p % 64] then
                            chd = peak_info[trn][p % 64].ch_d
                          else
                            chd = -150
                          end
                          if tostring(ctl.val) ~= tostring(chd) then
                            ctl.val = chd
                            ctl.dirty = true
                            lupd.update_ctls = true

                            if ctl.midiout then
                              SendMIDIMsg(ctl.midiout, ctl.val)
                            end
                            --lupd.update_mtrs = true
                          end
                        end

                      elseif ctl.ctlcat == ctlcats.rs5k then

                        local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
                        if ctl.fxguid == fxguid and ctl.rsdata.samplesidx then
                          local lvar = lvar
                          local retval, fn = reaper.TrackFX_GetNamedConfigParm(tr, ctl.fxnum, 'FILE')
                          local ffn = string.match(fn, '.*[\\/](.*)')
                          local si = ctl.rsdata.samplesidx[fn]
                          if si and si ~= math.min(math.floor(ctl.val * lvar.maxsamples)+1,#ctl.rsdata.samples) then
                            ctl.val = ((si-1) / lvar.maxsamples)
                            ctl.dirty = true
                            lupd.update_ctls = true
                          end

                          --Check keyboard controls - params
                          if show_samplemanager == true and rs5k_select == i then
                            local pkey = 72 + lvar.rs.pitch
                            local kstart = lvar.kb.kstart or -1
                            local kend = lvar.kb.kend or -1
                            local pstart = 3
                            local pend = 4

                            local s = reaper.TrackFX_GetParam(tr,ctl.fxnum,pstart)
                            local e = reaper.TrackFX_GetParam(tr,ctl.fxnum,pend)
                            local pit = reaper.TrackFX_GetParam(tr,ctl.fxnum,15)

                            local single = 1/160
                            local diff = 0.5-pit

                            if s*128 ~= lvar.kb.kstart or
                               e*128 ~= lvar.kb.kend or
                               round(diff/single) ~= lvar.rs.pitch then
                              lvar.rs.pitch = round(diff/single)
                              lvar.kb.kstart = s*128
                              lvar.kb.kend = e*128
                              GUI_DrawKeyboardOverlay(obj, gui)
                              lupd.update_samplemanager = true
                            end
                          end
                        else
                          if ctl.fxfound then
                            CheckStripControls()
                          end
                        end

                      elseif ctl.ctlcat == ctlcats.takeswitcher then

                        if ctl.iteminfo then
                          local item = GetMediaItemByGUID(ctl.iteminfo.guid)
                          if item then
                            local tkidx = reaper.GetMediaItemInfo_Value(item,'I_CURTAKE')
                            if tkidx and tkidx >= 0 then
                              tkidx2 = tkidx/takeswitch_max
                              if tkidx2 ~= ctl.val then
                                ctl.val = tkidx2
                                --ctl.tkidx = tkidx
                                local take = reaper.GetTake(item, tkidx)
                                if take then
                                  _, ctl.iteminfo.curtake = reaper.GetSetMediaItemTakeInfo_String(take, 'P_NAME', '', false)
                                else
                                  ctl.iteminfo.curtake = 'empty'
                                end
                                ctl.dirty = true
                                lupd.update_ctls = true
                              end
                            end
                          end
                        end

                      elseif ctl.ctlcat == ctlcats.fxoffline then
                        local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
                        if ctl.fxguid == fxguid then

                          local pn = reaper.TrackFX_GetNumParams(tr,ctl.fxnum)
                          if pn ~= lvar.offline_paramcnt then
                            if ctl.offline ~= nil then
                              ctl.dirty = true
                              lupd.update_ctls = true

                              if ctl.midiout then
                                SendMIDIMsg(ctl.midiout, ctl.val)
                              end
                            end
                            ctl.offline = nil
                            ctl.val = 0
                          else
                            if ctl.offline == nil then
                              ctl.dirty = true
                              lupd.update_ctls = true

                              if ctl.midiout then
                                SendMIDIMsg(ctl.midiout, ctl.val)
                              end
                            end
                            ctl.offline = true
                            ctl.val = 1
                          end
                        else
                          if ctl.fxfound then
                            CheckStripControls()
                          end
                        end
                      elseif ctl.ctlcat == ctlcats.fxgui or (ctl.ctlcat == ctlcats.rcm_switch and ctl.fxnum) then
                        local fxguid = reaper.TrackFX_GetFXGUID(tr, ctl.fxnum)
                        if ctl.fxguid and ctl.fxguid ~= fxguid then
                          if ctl.fxfound then
                            CheckStripControls()
                          end
                        end


                      elseif ctl.ctlcat == ctlcats.midieditor_pageswitch then

                        if mode == 0 then
                          local hwnd = reaper.MIDIEditor_GetActive()
                          if hwnd then
                            if page ~= tonumber(ctl.param_info.paramidx) then
                              setpage_wait = tonumber(ctl.param_info.paramidx)
                              SetPage(setpage_wait)
                              break
                            end
                          else
                            if page ~= ctl.param then
                              setpage_wait = tonumber(ctl.param)
                              SetPage(setpage_wait)
                              break
                            end
                          end
                        end
                      end

                      --if ctl.macrofader then
                        --SetFader(ctl.macrofader, ctl.val)
                      --end

                      if ctl.dirty == true then
                        SetCtlDirty(i)
                      end

                    else
                      --track not found
                      ctl.fxfound = false
                      ctl.trackmissing = true
                    end
                  end
                end
                chktbl = nil
                if pkmts then
                  time_nextupdate_pkmeter = rt + settings_updatefreq_pkmeter
                end
                if lvar.ctlupdate_rr then
                  lvar.ctlupdate_pos = lvar.ctlupdate_pos+lvar.ctlupdate_rr+1
                end
              end
            end
          end
        end
      end
    end

  end

  function GetMediaItemByGUID(guid)
    if reaper.APIExists('BR_GetMediaItemByGUID') == true then
      return reaper.BR_GetMediaItemByGUID(0, guid)
    end
  end

  function SetCtlDirty(c)
    if not ctls_dirty.idx[c] then
      ctls_dirty.idx[c] = true
      ctls_dirty.update[#ctls_dirty.update+1] = c
    end
  end

  function DropCtls()
    --if ctl_select == nil then return end
    local updallowed = true
    --if ctl_select then
    local ctls = strips[tracks[track_select].strip][page].controls
    if newgrp and ctl_select then
      for i = 1, #ctl_select do --might need to do nested checks
        if strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].switcherid == strips[tracks[track_select].strip][page].controls[newgrp.switchid].switcherid then
          updallowed = false
          break
        end
      end
      if updallowed == true then
        if newgrp.grpid == nil or newgrp.grpid == -1 then
          newgrp.grpid = Switcher_AddPage(newgrp.switchid)
        end
      end
    end
    if ctl_select then
      for i = 1, #ctl_select do
        local ctl = ctls[ctl_select[i].ctl]
        if newgrp then
          if updallowed == true then
            --is parent switcher in selection?
            local par = IsParentSwitchInSel(ctl_select, ctl, i)
            if par == false then
              ctl.grpid = newgrp.grpid
              ctl.switcher = ctls[newgrp.switchid].switcherid
              if ctl.ctlcat == ctlcats.switcher then
                local swid = ctl.switcherid
                switchers[swid].parent = {}
                switchers[swid].parent.grpid = newgrp.grpid
                switchers[swid].parent.switcherid = ctls[newgrp.switchid].switcherid
              end
            end
          end
        end
        ctl.hide = nil
      end
    end
    if gfx3_select and #gfx3_select > 0 then
      local gfxx = strips[tracks[track_select].strip][page].graphics
      for i = 1, #gfx3_select do
        local gfxc = strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl]
        if newgrp then
          if updallowed == true then
            --is parent switcher in selection?
            local par = IsParentSwitchInSel(ctl_select, gfxc, i)
            if par == false then
              gfxc.grpid = newgrp.grpid
              gfxc.switcher = ctls[newgrp.switchid].switcherid
            end
          end
        end
        gfxc.hide = nil
      end
    end
    --end
    newgrp = nil
    lupd.update_gfx = true
  end

  function IsParentSwitchInSel(ctlselect, ctl, i)
    if not ctlselect then return false end

    local par = false
    local ctls = strips[tracks[track_select].strip][page].controls
    if ctl.switcher then
      local ctab = {}
      for j = 1, #ctlselect do
        if j ~= i then
          ctab[#ctab+1] = ctlselect[j]
        end
      end
      for j = 1, #ctlselect do
        if ctls[ctlselect[j].ctl].ctlcat == ctlcats.switcher and ctls[ctlselect[j].ctl].switcherid == ctl.switcher then
          par = true
          break
        elseif ctls[ctlselect[j].ctl].ctlcat == ctlcats.switcher then
          par = IsParentSwitchInSel(ctab, ctls[ctlselect[j].ctl], j)
          if par == true then
            break
          end
        end
      end
    end
    return par
  end

  function GetReassCtl()
    local reass_param
    local ctls = strips[tracks[track_select].strip][page].controls
    local reass_param = GetControlAtXY(tracks[track_select].strip, page, mouse.mx, mouse.my)

    --[[if settings_usectlbitmap then

      gfx.dest = ctl_bitmap
      gfx.x = mouse.mx + surface_offset.x -obj.sections[10].x
      gfx.y = mouse.my + surface_offset.y -obj.sections[10].y
      local r,g,b = gfx.getpixel()
      gfx.dest = 1
      local cc = r*255 + ((g*255) << 8) + ((b*255) << 16)
      if cc > 0 and ctls[cc] then
        reass_param = cc
      end
    else
      for i = 1, #ctls do
        local ctl = strips[tracks[track_select].strip][page].controls[i]
        local hidden = Switcher_CtlsHidden(ctl.switcher,ctl.grpid)

        if hidden == false then
          local xywh
          xywh = {x = ctl.x - surface_offset.x +obj.sections[10].x,
                  y = ctl.y - surface_offset.y +obj.sections[10].y,
                  w = ctl.w,
                  h = ctl.ctl_info.cellh}
          if MOUSE_over(xywh) then
            reass_param = i
            break
          end
        end
      end
    end]]
    return reass_param
  end


  function EQC_LoadGraph(band)

    local fn = paths.eqbands_path..'default.eqgraph'
    if reaper.file_exists(fn) then

      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      local defgraph = unpickle(content)

      return defgraph
    end

  end

  function EQC_SetMain(band)


    local m = {}
    m.lookmap = {}
    m.gmap = {}
    local lm = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].lookmap
    for i = 1, #lm do
      m.lookmap[i] = {pix = lm[i].pix,
                      hz = lm[i].hz}
    end
    local gm = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].gmap
    for i = 1, #gm do
      m.gmap[i] = {pix = gm[i].pix,
                   db = gm[i].db}
    end
    m.gmin = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].gmin
    m.gmax = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].gmax
    m.posmin = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].posmin
    m.posmax = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].posmax

    local save_path=paths.eqbands_path
    local fn=save_path.."default.eqgraph"

    local DELETE=true
    local file

    if reaper.file_exists(fn) then

    end

    if DELETE then
      file=io.open(fn,"w")
      local pickled_table=pickle(m)
      file:write(pickled_table)
      file:close()
    end

    OpenMsgBox(1,'Default EQ graph saved.',1)
    def_graph = m
    return m

  end

  function EQC_GetParam(track, fx, param)
    if param then
      --local track = GetTrack(tr)
      local v = reaper.TrackFX_GetParamNormalized(track, fx, param)
      return v
    end
  end

  function EQC_SetDefault(b)

    local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
    if bands and bands[b] then
      if bands[b].freq_def then
        EQC_SetParam(b, bands[b].freq_param, bands[b].freq_def)
      end
      if bands[b].gain_def then
        EQC_SetParam(b, bands[b].gain_param, bands[b].gain_def)
      end
      if bands[b].q_def then
        EQC_SetParam(b, bands[b].q_param, bands[b].q_def)
      end
      if bands[b].c1_def then
        EQC_SetParam(b, bands[b].c1_param, bands[b].c1_def)
      end
      if bands[b].c2_def then
        EQC_SetParam(b, bands[b].c2_param, bands[b].c2_def)
      end
      if bands[b].c3_def then
        EQC_SetParam(b, bands[b].c3_param, bands[b].c3_def)
      end
      if bands[b].c4_def then
        EQC_SetParam(b, bands[b].c4_param, bands[b].c4_def)
      end
      if bands[b].c5_def then
        EQC_SetParam(b, bands[b].c5_param, bands[b].c5_def)
      end
    end

  end

  function EQC_SetParam(band, param, val)
    if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].fxnum then
      local fxnum = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].fxnum
      local track = GetTrack(tracks[track_select].tracknum)
      reaper.TrackFX_SetParamNormalized(track, fxnum, param, val)
    end
  end

  function EQC_SelectParam()
    if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].fxnum then
      local fxnum = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].fxnum
      local track = GetTrack(tracks[track_select].tracknum)
      local pcnt = reaper.TrackFX_GetNumParams(track, fxnum)
      local mstr = '[ CLEAR ]|'
      for pn = 1, pcnt do
        local _, pname = reaper.TrackFX_GetParamName(track, fxnum, pn-1, '')
        mstr = mstr..pn..': '..pname
        if pn < pcnt then
          mstr = mstr..'|'
        end
      end
      gfx.x, gfx.y = mouse.mx, mouse.my
      res = OpenMenu(mstr)-1
      if res == 0 then res = -1 end
      return res
    else
      return 0
    end
  end

  function EQC_AlignGraph(src, aligntype)

    if aligntype == nil then aligntype = 1 end

    local strip = tracks[track_select].strip
    local eqgraph = strips[strip][page].controls[eqcontrol_select].eqgraph
    if eqgraph then
      local lookmap_src = strips[strip][page].controls[eqcontrol_select].eqbands[src].lookmap
      local lookmap_tgt = eqgraph.lookmap

      if lookmap_src and #lookmap_src > 1 then

        local src_pts = {}
        for i = 1, #lookmap_src do

          if 10^math.floor(math.log(lookmap_src[i].hz,10)) == lookmap_src[i].hz then
            src_pts[#src_pts+1] = i
          end

        end

        if #src_pts < 2 then

          if #src_pts == 1 then
            --if #lookmap_src - src_pts[1] > #lookmap_src / 2 and lookmap_src[#lookmap_src].hz <= lookmap_tgt[#lookmap_tgt].hz then
            if #lookmap_src > src_pts[1] and lookmap_src[#lookmap_src].hz <= lookmap_tgt[#lookmap_tgt].hz and (aligntype == 1 or src_pts[1] == 1) then
              src_pts[2] = #lookmap_src

            else
              src_pts[2] = 1

            end
            if src_pts[1] > src_pts[2] then
              local sp = src_pts[1]
              src_pts[1] = src_pts[2]
              src_pts[2] = sp
            end
          else
            src_pts[1] = 1
            src_pts[2] = #lookmap_src
          end
        end
        local tgt_pts = {}
        for i = 1, #lookmap_tgt do
          if lookmap_tgt[i].hz == lookmap_src[src_pts[1]].hz then
            tgt_pts[1] = i
          elseif lookmap_tgt[i].hz == lookmap_src[src_pts[2]].hz then
            tgt_pts[2] = i
          end
        end
        if #tgt_pts == 2 then
          local tgt_pix = (lookmap_tgt[tgt_pts[2]].pix/2000) - (lookmap_tgt[tgt_pts[1]].pix/2000)
          local tgt_mult = eqgraph.posmax-eqgraph.posmin
          local tp = (lookmap_tgt[tgt_pts[1]].pix/2000)*tgt_mult
          local src_pix = (lookmap_src[src_pts[2]].pix/2000) - (lookmap_src[src_pts[1]].pix/2000)
          local src_mult = (tgt_pix*tgt_mult)/src_pix

          local srcdif = (lookmap_src[src_pts[1]].pix/2000) * src_mult
          local posmin = tp - srcdif + (eqgraph.posmin)
          local posmax = posmin + src_mult
          strips[strip][page].controls[eqcontrol_select].eqbands[src].posmin = posmin
          strips[strip][page].controls[eqcontrol_select].eqbands[src].posmax = posmax

          lupd.update_gfx = true
        end
      end

      local gmap_src = strips[strip][page].controls[eqcontrol_select].eqbands[src].gmap
      local gmap_tgt = eqgraph.gmap

      if gmap_src and #gmap_src > 1 then

        local src_pts = {}
        for i = 1, #gmap_src do

          if gmap_src[i].db == 0 then
            src_pts[#src_pts+1] = i
          end

        end

        if #src_pts == 1 then

          if #src_pts > src_pts[1]+1 then

            src_pts[2] = src_pts[1] + 2

          elseif src_pts[1] > 2 then

            src_pts[2] = src_pts[1] - 2

          end

          if #src_pts == 2 then

            local tgt_pts = {}
            for i = 1, #gmap_tgt do
              if gmap_tgt[i].db == gmap_src[src_pts[1]].db then
                tgt_pts[1] = i
              elseif gmap_tgt[i].db == gmap_src[src_pts[2]].db then
                tgt_pts[2] = i
              end
            end

            if #tgt_pts == 2 then
              local tgt_pix = (gmap_tgt[tgt_pts[2]].pix/2000) - (gmap_tgt[tgt_pts[1]].pix/2000)
              local tgt_mult = eqgraph.gmax-eqgraph.gmin
              local tp = (gmap_tgt[tgt_pts[1]].pix/2000)*tgt_mult
              local src_pix = (gmap_src[src_pts[2]].pix/2000) - (gmap_src[src_pts[1]].pix/2000)
              local src_mult = (tgt_pix*tgt_mult)/src_pix

              local srcdif = (gmap_src[src_pts[1]].pix/2000) * src_mult
              local gmin = tp - srcdif + (eqgraph.gmin)
              local gmax = gmin + src_mult
              strips[strip][page].controls[eqcontrol_select].eqbands[src].gmin = gmin
              strips[strip][page].controls[eqcontrol_select].eqbands[src].gmax = gmax

              lupd.update_gfx = true
            end

          end
        end
      end

    end

  end

  function EQC_LoadBand()

    if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands == nil or
      (strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
        and #strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands < 20) then
      local i = 0
      local mstr = '[ NEW EMPTY BAND ]|>EQs'
      local bands = {}
      local eqs = {}

      local eq = reaper.EnumerateFiles(paths.eq_path,i)
      if eq ~= nil then
        while eq ~= nil do
          local str = string.match(eq,'(.*)%.lbxeq')
          i=i+1
          eq = reaper.EnumerateFiles(paths.eq_path,i)
          if eq ~= nil then
            mstr = mstr..'|'..str
            eqs[#eqs+1] = str
          else
            mstr = mstr..'|<'..str
            eqs[#eqs+1] = str
          end
        end
      else
        mstr = mstr..'|#<empty'
        eqs[#eqs+1] = ''
      end

      i=0
      local bt = reaper.EnumerateSubdirectories(paths.eqbands_path,i)
      while bt ~= nil do
        if mstr ~= '' then
          mstr = mstr .. '|'
        end
        mstr = mstr..'>'..bt
        local btp = paths.eqbands_path..bt
        local b = 0
        local bn = reaper.EnumerateFiles(btp,b)
        if bn ~= nil then
          while bn ~= nil do
            local str = string.match(bn,'(.*)%.eqband')
            b=b+1
            bn = reaper.EnumerateFiles(btp,b)
            if bn ~= nil then
              mstr = mstr..'|'..str
              bands[#bands+1] = bt..'/'..str
            else
              mstr = mstr..'|<'..str
              bands[#bands+1] = bt..'/'..str
            end
          end
        else
          mstr = mstr..'|#<empty'
          bands[#bands+1] = ''
        end
        i=i+1
        bt = reaper.EnumerateSubdirectories(paths.eqbands_path,i)
      end
      gfx.x, gfx.y = mouse.mx+obj.sections[300].x, mouse.my+obj.sections[300].y
      res = OpenMenu(mstr)
      if res ~= 0 then

        if res == 1 then
          --add band
          eq_edit = true
          if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands == nil then
            strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands = {}
          end
          local eqb = #strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands+1
          eqcontrolband_select = eqb
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb] = {}
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].posmin = 0
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].posmax = 1
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].gmin = 0
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].gmax = 1

          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].col = '160 160 160'
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqb].khz = false

          lupd.update_gfx = true
        elseif res-1 <= #eqs then
          res = res - 1
          local fn = paths.eq_path..eqs[res]..'.lbxeq'

          EQC_LoadEQ(fn)

        else
          res = res - (1+#eqs)
          local fn = paths.eqbands_path..bands[res]..'.eqband'
          if reaper.file_exists(fn) then

            local file
            file=io.open(fn,"r")
            local content=file:read("*a")
            file:close()

            local loaddata = unpickle(content)
            if loaddata then

              local trn = tracks[track_select].tracknum
              local fxc = loaddata.chunk
              local track = GetTrack(trn)
              local chunk = GetTrackChunk(track, settings_usetrackchunkfix)
              local nchunk, nfxguid, ofxguid = Chunk_InsertFXChunkAtEndOfFXChain(trn, chunk, fxc)
              if nchunk then
                SetTrackChunk(track,nchunk, false)
                loaddata.eqband.fxguid = nfxguid
                loaddata.eqband.fxnum = reaper.TrackFX_GetCount(track)-1
                if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands == nil then
                  strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands = {}
                end
                local newband = #strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands+1
                --loaddata.eqband.col = lvar.eqcontrol_colours[newband]
                strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband] = loaddata.eqband
                eqcontrolband_select = newband
                --compatibility
                if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband].khz == nil then
                  strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband].khz = false
                end
                if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband].gmin == nil then
                  strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband].gmin = 0
                  strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[newband].gmax = 1
                end
              end
            end

            lupd.update_gfx = true

          else
            OpenMsgBox(1,'File not found.',1)
          end
        end
      end
    end
  end

  function EQC_SelectBandType()

    local i = 0
    local bt = reaper.EnumerateSubdirectories(paths.eqbands_path,i)
    local mstr = '[ NEW FOLDER ]'
    local bandtypes = {'NEW FOLDER'}
    while bt ~= nil do
      bandtypes[#bandtypes+1] = bt
      if mstr ~= '' then
        mstr = mstr .. '|'
      end
      mstr = mstr..bt
      i=i+1
      bt = reaper.EnumerateSubdirectories(paths.eqbands_path,i)
    end
    gfx.x, gfx.y = mouse.mx+obj.sections[300].x, mouse.my+obj.sections[300].y
    res = OpenMenu(mstr)
    if res ~= 0 then
      if res == 1 then
        OpenEB(31,'Please enter new EQ band folder:')
      else
        strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandtype = bandtypes[res]
      end
      lupd.update_gfx = true
    end

  end

  function EQC_CopyBandData(strip, page, c,b)

    local bb = strips[strip][page].controls[c].eqbands

    local bd = {posmin = bb[b].posmin,
                posmax = bb[b].posmax,
                gmin = bb[b].gmin,
                gmax = bb[b].gmax,
                fxnum = bb[b].fxnum,
                fxguid = bb[b].fxguid,
                fxname = bb[b].fxname,
                col = bb[b].col,
                freq_param = bb[b].freq_param,
                freq_param_name = bb[b].freq_param_name,
                gain_param = bb[b].gain_param,
                gain_param_name = bb[b].gain_param_name,
                q_param = bb[b].q_param,
                q_param_name = bb[b].q_param_name,
                bypass_param = bb[b].bypass_param,
                bypass_param_name = bb[b].bypass_param_name,
                c1_param = bb[b].c1_param,
                c1_param_name = bb[b].c1_param_name,
                c2_param = bb[b].c2_param,
                c2_param_name = bb[b].c2_param_name,
                c3_param = bb[b].c3_param,
                c3_param_name = bb[b].c3_param_name,
                c4_param = bb[b].c4_param,
                c4_param_name = bb[b].c4_param_name,
                c5_param = bb[b].c5_param,
                c5_param_name = bb[b].c5_param_name,
                freq_min = bb[b].freq_min,
                freq_max = bb[b].freq_max,
                bandtype = bb[b].bandtype,
                bandname = bb[b].bandname,
                lookmap = {},
                gmap = {},
                gain_inv = bb[b].gain_inv,
                q_inv = bb[b].q_inv,
                khz = khz,
                freq_def = bb[b].freq_def,
                gain_def = bb[b].gain_def,
                q_def = bb[b].q_def,
                c1_def = bb[b].c1_def,
                c2_def = bb[b].c2_def,
                c3_def = bb[b].c3_def,
                c4_def = bb[b].c4_def,
                c5_def = bb[b].c5_def
                }
    if bb[b].lookmap then
      for lc = 1, #bb[b].lookmap do
        bd.lookmap[lc] = {pix = bb[b].lookmap[lc].pix,
                          hz = bb[b].lookmap[lc].hz
                          }
      end
    end
    if bb[b].gmap then
      for lc = 1, #bb[b].gmap do
        bd.gmap[lc] = {pix = bb[b].gmap[lc].pix,
                        db = bb[b].gmap[lc].db
                        }
      end
    end

    return bd
  end

  function EQC_DelBand()

    local strip = tracks[track_select].strip
    if strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select] then
      local fxnum = strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].fxnum
      local unique = true
      if fxnum then
        for b = 1, #strips[strip][page].controls[eqcontrol_select].eqbands do
          if b ~= eqcontrolband_select and fxnum == strips[strip][page].controls[eqcontrol_select].eqbands[b].fxnum then
            unique = false
          end
        end
      else
        --no fx
        unique = false
      end

      local cnt = #strips[strip][page].controls[eqcontrol_select].eqbands
      strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select] = nil
      strips[strip][page].controls[eqcontrol_select].eqbands = Table_RemoveNils(strips[strip][page].controls[eqcontrol_select].eqbands, cnt)

      if eqcontrolband_select > #strips[strip][page].controls[eqcontrol_select].eqbands then
        eqcontrolband_select = #strips[strip][page].controls[eqcontrol_select].eqbands
        if eqcontrolband_select == 0 then
          eqcontrolband_select = nil
        end
      end
      lupd.update_gfx = true

      if unique and fxnum then
        --can delete
        local tr = GetTrack(tracks[track_select].tracknum)
        local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
        local _, nchunk = RemoveFXChunkFromTrackChunk(chunk, fxnum+1)
        if nchunk then
          SetTrackChunk(tr,nchunk, false)

          --Reorganise FXNUM
          for i = 1, #strips[strip][page].controls[eqcontrol_select].eqbands do
            if strips[strip][page].controls[eqcontrol_select].eqbands[i].fxnum and strips[strip][page].controls[eqcontrol_select].eqbands[i].fxnum > fxnum then
              strips[strip][page].controls[eqcontrol_select].eqbands[i].fxnum = strips[strip][page].controls[eqcontrol_select].eqbands[i].fxnum-1
            end
          end
        end
      end

    end
  end

  function EQC_SaveBand()

    local strip = tracks[track_select].strip
    if eqcontrolband_select then
      local fxnum = strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].fxnum
      if fxnum == -1 then OpenMsgBox(1,'Plugin not found.',1) return end

      if strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandtype == nil then
        OpenMsgBox(1,'Select a folder first.',1)
        return
      end
      if strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandname == nil then
        OpenMsgBox(1,'Select a band name first.',1)
        return
      end

      local bandtype = strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandtype
      local bandname = strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandname

      local savedata = {}
      local track = GetTrack(tracks[track_select].tracknum)
      local chunk = GetTrackChunk(track, settings_usetrackchunkfix)
      local fnd, fxc, s, e = GetFXChunkFromTrackChunk(chunk,fxnum+1)

      if fnd then
        savedata.eqband = EQC_CopyBandData(strip, page, eqcontrol_select, eqcontrolband_select)
        savedata.chunk = fxc

        local fn = bandtype..'/'..bandname

        if fn and string.len(fn)>0 then

          local save_path=paths.eqbands_path
          local fn=save_path..fn..".eqband"

          local DELETE=true
          local file

          if reaper.file_exists(fn) then

          end

          if DELETE then
            file=io.open(fn,"w")
            local pickled_table=pickle(savedata)
            file:write(pickled_table)
            file:close()
          end

          OpenMsgBox(1,'EQ band saved.',1)

        end

      else
        --error
        DBG('Failed to get fx chunk')
      end

    end

  end

  function EQC_LoadEQ(fn)

    if reaper.file_exists(fn) then

      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      local loaddata = unpickle(content)
      if loaddata then

        local fxcnt = #loaddata.chunks

        GUI_DrawMsgX(obj, gui, 'Loading EQ Data...', ck, fxcnt)

        local trn = tracks[track_select].tracknum
        local track = GetTrack(trn)
        local chunk = GetTrackChunk(track, settings_usetrackchunkfix)

        local nguids = {}
        local oguids = {}
        local fxcnt = reaper.TrackFX_GetCount(track)
        for ck = 1, #loaddata.chunks do

          local fxc = loaddata.chunks[ck]
          local nchunk, nfxguid, ofxguid = Chunk_InsertFXChunkAtEndOfFXChain(trn, chunk, fxc)
          chunk = nchunk
          nguids[ofxguid] = nfxguid
          oguids[fxcnt+ck] = ofxguid
        end
        SetTrackChunk(track,chunk, false)

        if settings_usetrackchunkfix then
          for i = fxcnt+1, reaper.TrackFX_GetCount(track) do
            nguids[oguids[i]] = reaper.TrackFX_GetFXGUID(track,i)
          end
        end

        local bandcnt = eqcontrolband_select
        if loaddata.bands and #loaddata.bands > 0 then
          if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands == nil then
            strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands = {}
          end
          local bands = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
          bandcnt = #bands+1
          for b = 1, #loaddata.bands do
            loaddata.bands[b].fxguid = nguids[loaddata.bands[b].fxguid]
            loaddata.bands[b].fxnum = -1

            if #bands < 20 then
              bands[#bands+1] = loaddata.bands[b]
            end
          end
        end
        if loaddata.eqgraph then
          strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqgraph = loaddata.eqgraph
        end

        eqcontrolband_select = bandcnt
        lupd.update_gfx = true

      end
    end
  end

  function EQC_SaveEQ(fn)

    local strip = tracks[track_select].strip
    --if eqcontrolband_select then

      --[[if strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandtype == nil then
        OpenMsgBox(1,'Select a folder first.',1)
        return
      end
      if strips[strip][page].controls[eqcontrol_select].eqbands[eqcontrolband_select].bandname == nil then
        OpenMsgBox(1,'Select a band name first.',1)
        return
      end]]

      local eqc = strips[strip][page].controls[eqcontrol_select].eqbands
      local savedata = {bands = {}, chunks = {}, eqgraph = {}}
      local track = GetTrack(tracks[track_select].tracknum)
      local fx = {}

      local chunk = GetTrackChunk(track, settings_usetrackchunkfix)

      savedata.eqgraph = strips[strip][page].controls[eqcontrol_select].eqgraph
      for b = 1, #eqc do

        --local fxnum = eqc[b].fxnum
        local fxnum = GetEQC_FXNum(b)
        if fxnum == -1 then OpenMsgBox(1,'Save failed.  Plugin not found.',1) return end

        fx[fxnum] = true
        savedata.bands[b] = EQC_CopyBandData(strip, page, eqcontrol_select, b)

      end

      local fnd = false
      for f = 0, reaper.TrackFX_GetCount(track)-1 do

        if fx[f] == true then
          fnd = false
          local fxc, s, e
          fnd, fxc, s, e = GetFXChunkFromTrackChunk(chunk,f+1)
          if fnd then
            savedata.chunks[#savedata.chunks+1] = fxc
          end
        end

      end

      if fnd then

        if fn and string.len(fn)>0 then

          local save_path=paths.eq_path
          local fn=save_path..fn..".lbxeq"

          local DELETE=true
          local file

          if reaper.file_exists(fn) then

          end

          if DELETE then
            file=io.open(fn,"w")
            local pickled_table=pickle(savedata)
            file:write(pickled_table)
            file:close()
          end

          OpenMsgBox(1,'EQ saved.',1)

        end
      end
    --end

  end

  function EQC_OpenEQs(b, open)

    local eqc = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
    if eqc then
      local track = GetTrack(tracks[track_select].tracknum)
      for i = 1, #eqc do
        local fxnum = GetEQC_FXNum(i)
        if fxnum and fxnum >= 0 and (b == nil or i == b) then

          reaper.TrackFX_SetOpen(track, fxnum, open)

        end

      end
    end

  end

  function EQC_UpdateVals()

    if strips[tracks[track_select].strip] and strips[tracks[track_select].strip][page].controls[eqcontrol_select] then
      local eqc = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands
      if eqc then
        local track = GetTrack(tracks[track_select].tracknum)
        for i = 1, #eqc do

          local fxnum = GetEQC_FXNum(i)
          if fxnum ~= -1 then

            if eqc[i].freq_param then

              local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].freq_param)
              --local v2 = reaper.TrackFX_GetParam(track, fxnum, eqc[i].freq_param)

              if v ~= eqc[i].freq_val then
                --eqc[i].freq_val = v

                lupd.update_eqcontrol = true
                break
              end
            end
            if eqc[i].gain_param then
              local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].gain_param)
              if v ~= eqc[i].gain_val then
                --eqc[i].gain_val = v
                lupd.update_eqcontrol = true
                break
              end
            end

            if i == eqcontrolband_select then
              if eqc[i].q_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].q_param)
                if v ~= eqc[i].q_val then
                  --eqc[i].q_val = v
                  lupd.update_eqcontrol = true
                  break
                end
              end
              if eqc[i].c1_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].c1_param)
                if v ~= eqc[i].c1_val then
                  lupd.update_eqcontrol = true
                  break
                end
              end
              if eqc[i].c2_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].c2_param)
                if v ~= eqc[i].c2_val then
                  lupd.update_eqcontrol = true
                  break
                end
              end
              if eqc[i].c3_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].c3_param)
                if v ~= eqc[i].c3_val then
                  lupd.update_eqcontrol = true
                  break
                end
              end
              if eqc[i].c4_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].c4_param)
                if v ~= eqc[i].c4_val then
                  lupd.update_eqcontrol = true
                  break
                end
              end
              if eqc[i].c5_param then
                local v = reaper.TrackFX_GetParamNormalized(track, fxnum, eqc[i].c5_param)
                if v ~= eqc[i].c5_val then
                  lupd.update_eqcontrol = true
                  break
                end
              end
            end
          end
        end
      end
    end
  end

  function GetEQC_FXNum(band)
    if strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands then
      local fxnum = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].fxnum
      local track = GetTrack(tracks[track_select].tracknum)
      if track and fxnum then
        if reaper.TrackFX_GetFXGUID(track, fxnum) == strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].fxguid then
          return fxnum
        else
          local fxcnt = reaper.TrackFX_GetCount(track)
          local guids = {}
          for i = 0, fxcnt-1 do
            local guid = reaper.TrackFX_GetFXGUID(track, i)
            guids[guid] = i
          end
          for i = 1, #strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands do
            local guid = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[i].fxguid
            if guids[guid] then
              strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[i].fxnum = guids[guid]
            else
              strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[i].fxnum = -1
            end
          end

          fxnum = strips[tracks[track_select].strip][page].controls[eqcontrol_select].eqbands[band].fxnum
          return fxnum
        end
      end
    else
      return -1
    end
  end

  function SetCtlBitmapRedraw(forcenow)

    if settings_usectlbitmap and forcenow then
      GUI_DrawCtlBitmap()
    elseif settings_usectlbitmap then
      lvar.delayfunction.redraw_ctlbitmap = reaper.time_precise() + 0.5
    else
      lvar.delayfunction.redraw_ctlbitmap = nil
    end
  end

  function SetCtlBitmapRedraw_Mix(forcenow)
    if settings_usectlbitmap and forcenow then
      GUI_DrawCtlBitmap_Mix()
    elseif settings_usectlbitmap then
      lvar.delayfunction.redraw_ctlbitmapmix = reaper.time_precise() + 0.2
    else
      lvar.delayfunction.redraw_ctlbitmapmix = nil
    end
  end

  function XXYRecord_Set(val)

    if LBX_CTL_TRACK and tracks[LBX_CTL_TRACK] then
      xxyrecord = val
      if xxyrecord then
        --set automode to touch
        local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
        reaper.SetTrackAutomationMode(track, 4)
      else
        --set automode to trim/read
        local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
        reaper.SetTrackAutomationMode(track, 0)
      end
    else
      xxyrecord = false
    end
  end

  function XXYPath_SetPos(strip, page, sst, pos, fader)

    if xxy and xxy[strip] and xxy[strip][page][sst] then
      local xxypath_sel = xxy[strip][page][sst].pathidx
      if xxypath_sel and xxypath[xxypath_sel] and xxypath[xxypath_sel].points and xxypath[xxypath_sel].points[1] and xxypath[xxypath_sel].points[1].t then
        if xxyrecord and xxymode == 1 then
          local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
          local pf = xxy[strip][page][sst].pathfader
          if pf and faders[pf] then
            local fxnum = math.floor((pf-1)/lvar.LBX_FB_CNT)
            local param = ((pf-1) % lvar.LBX_FB_CNT)
            reaper.TrackFX_SetParam(track, fxnum, param, pos)
            faders[pf].val = pos
          end
        end

        local xxypath_indexcnt = #xxypath[xxypath_sel].pathidxpt
        local posidx = F_limit(math.floor(pos*xxypath_indexcnt),0,xxypath_indexcnt)
        local pt = math.max(xxypath[xxypath_sel].pathidxpt[posidx],1)
        while xxypath[xxypath_sel].points[pt].posend < pos do
          pt = pt + 1
        end

        local secpos = F_limit((pos-xxypath[xxypath_sel].points[pt].posstart)/(xxypath[xxypath_sel].points[pt].posend-xxypath[xxypath_sel].points[pt].posstart),0,1)
        local sp2 = xxypath[xxypath_sel].points[pt].t[math.floor(secpos*#xxypath[xxypath_sel].points[pt].t)]
        local x,y = curve_getxy(xxypath[xxypath_sel].points[pt].x, xxypath[xxypath_sel].points[pt].y, sp2)
        local ox, oy = xxy[strip][page][sst].x, xxy[strip][page][sst].y

        xxy[strip][page][sst].x = F_limit(x,0,1)
        xxy[strip][page][sst].y = F_limit(y,0,1)
        if xxy[strip][page][sst].x ~= ox or xxy[strip][page][sst].y ~= oy then
          XXY_Set(strip, page, sst)
        end
      elseif fader and (xxypath_sel == nil or xxypath[xxypath_sel] == nil) then
        DeleteFader(fader)
      end
    elseif fader then
      DeleteFader(fader)
    end
  end

  function XXYPath_SetPos2(strip, page, sst, pos)

    local xxypath_sel = xxy[strip][page][sst].pathidx
    if xxypath_sel and xxypath[xxypath_sel] then

      local xxypath_indexcnt = #xxypath[xxypath_sel].pathidxpt
      local posidx = F_limit(math.floor(pos*xxypath_indexcnt),0,xxypath_indexcnt)
      local pt = math.max(xxypath[xxypath_sel].pathidxpt[posidx],1)
      while xxypath[xxypath_sel].points[pt].posend < pos do
        pt = pt + 1
      end

      local secpos = F_limit((pos-xxypath[xxypath_sel].points[pt].posstart)/(xxypath[xxypath_sel].points[pt].posend-xxypath[xxypath_sel].points[pt].posstart),0,1)
      local x,y = curve_getxy(xxypath[xxypath_sel].points[pt].x, xxypath[xxypath_sel].points[pt].y, secpos)
      local ox, oy = xxy[strip][page][sst].x, xxy[strip][page][sst].y

      xxy[strip][page][sst].x = F_limit(x,0,1)
      xxy[strip][page][sst].y = F_limit(y,0,1)

      if xxy[strip][page][sst].x ~= ox or xxy[strip][page][sst].y ~= oy then
        XXY_Set(strip, page, sst)
      end
    end
  end

  function LoadPath()

    if xxy and xxy[tracks[track_select].strip] and xxy[tracks[track_select].strip][page][sstype_select] then

      local retval, fn = reaper.GetUserFileNameForRead(paths.paths_path..'*', 'Load Meta Path', '.path')
      if retval then

        if reaper.file_exists(fn) then

          local file
          file=io.open(fn,"r")
          local content=file:read("*a")
          file:close()

          local loaddata = unpickle(content)
          if loaddata then

            if xxypath_select == nil then
              xxypath_select = #xxypath+1
              xxy[tracks[track_select].strip][page][sstype_select].pathidx = xxypath_select
            end
            xxypath[xxypath_select] = {}
            xxypath[xxypath_select] = loaddata
          end

          lupd.update_gfx = true

        else
          OpenMsgBox(1,'File not found.',1)
        end

      end

    end

  end

  function SavePath(fn)

    if fn and string.len(fn)>0 then

      local save_path=paths.paths_path
      local fn=save_path..fn..".path"

      local DELETE=true
      local file

      if reaper.file_exists(fn) then

      end

      if DELETE then
        file=io.open(fn,"w")
        local pickled_table=pickle(xxypath[xxypath_select])
        file:write(pickled_table)
        file:close()
      end

      OpenMsgBox(1,'Path saved.',1)

    end

  end

  function XXYPATH_movept(pt, x, y)

    if #xxypath[xxypath_select].points > 1 then
      if pt.sp == 1 then

        if pt.p == 1 then

          xxypath[xxypath_select].points[pt.p].x[pt.sp] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p].y[pt.sp] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p].x[2] = F_limit(x+pt.dx2,0,1)
          xxypath[xxypath_select].points[pt.p].y[2] = F_limit(y+pt.dy2,0,1)

          xxypath[xxypath_select].points[pt.p].len = XXYPath_CalcPathSectionLength(pt.p)

        else

          xxypath[xxypath_select].points[pt.p].x[pt.sp] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p].y[pt.sp] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p-1].x[4] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p-1].y[4] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p].x[2] = F_limit(x+pt.dx2,0,1)
          xxypath[xxypath_select].points[pt.p].y[2] = F_limit(y+pt.dy2,0,1)
          xxypath[xxypath_select].points[pt.p-1].x[3] = F_limit(x-pt.dx3,0,1)
          xxypath[xxypath_select].points[pt.p-1].y[3] = F_limit(y-pt.dy3,0,1)

          xxypath[xxypath_select].points[pt.p].len = XXYPath_CalcPathSectionLength(pt.p)
          xxypath[xxypath_select].points[pt.p-1].len = XXYPath_CalcPathSectionLength(pt.p-1)

        end

      else

        if pt.p >= #xxypath[xxypath_select].points-1  then

          xxypath[xxypath_select].points[pt.p].x[pt.sp] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p].y[pt.sp] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p].x[3] = F_limit(x-pt.dx3,0,1)
          xxypath[xxypath_select].points[pt.p].y[3] = F_limit(y-pt.dy3,0,1)
          if pt.p == #xxypath[xxypath_select].points-1 then
            xxypath[xxypath_select].points[pt.p+1].x[1] = F_limit(x,0,1)
            xxypath[xxypath_select].points[pt.p+1].y[1] = F_limit(y,0,1)
          end

        else

          xxypath[xxypath_select].points[pt.p].x[pt.sp] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p].y[pt.sp] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p+1].x[1] = F_limit(x,0,1)
          xxypath[xxypath_select].points[pt.p+1].y[1] = F_limit(y,0,1)
          xxypath[xxypath_select].points[pt.p+1].x[2] = F_limit(x+pt.dx2,0,1)
          xxypath[xxypath_select].points[pt.p+1].y[2] = F_limit(y+pt.dy2,0,1)
          xxypath[xxypath_select].points[pt.p].x[3] = F_limit(x-pt.dx3,0,1)
          xxypath[xxypath_select].points[pt.p].y[3] = F_limit(y-pt.dy3,0,1)

        end

        xxypath[xxypath_select].points[pt.p].len = XXYPath_CalcPathSectionLength(pt.p)
        xxypath[xxypath_select].points[pt.p+1].len = XXYPath_CalcPathSectionLength(pt.p+1)

      end
    else
      xxypath[xxypath_select].points[pt.p].x[1] = F_limit(x,0,1)
      xxypath[xxypath_select].points[pt.p].y[1] = F_limit(y,0,1)

    end
  end

  function XXYPATH_movectlpt(ctlpt, x, y)

    if ctlpt.sp == 2 then

      if ctlpt.p == 1 then

        xxypath[xxypath_select].points[ctlpt.p].x[ctlpt.sp] = F_limit(x,0,1)
        xxypath[xxypath_select].points[ctlpt.p].y[ctlpt.sp] = F_limit(y,0,1)

        xxypath[xxypath_select].points[ctlpt.p].len = XXYPath_CalcPathSectionLength(ctlpt.p)

      else

        xxypath[xxypath_select].points[ctlpt.p].x[ctlpt.sp] = F_limit(x,0,1)
        xxypath[xxypath_select].points[ctlpt.p].y[ctlpt.sp] = F_limit(y,0,1)

        local sp2_opp = xxypath[xxypath_select].points[ctlpt.p].x[2]-xxypath[xxypath_select].points[ctlpt.p].x[1]
        local sp2_adj = xxypath[xxypath_select].points[ctlpt.p].y[2]-xxypath[xxypath_select].points[ctlpt.p].y[1]
        local sp3_theta = math.atan(sp2_opp/sp2_adj)

        local sp3_x, sp3_y
        if sp2_adj >= 0 then
          sp3_x = xxypath[xxypath_select].points[ctlpt.p-1].x[4]-math.sin(sp3_theta)*ctlpt.hyp
          sp3_y = xxypath[xxypath_select].points[ctlpt.p-1].y[4]-math.cos(sp3_theta)*ctlpt.hyp
        else
          sp3_x = xxypath[xxypath_select].points[ctlpt.p-1].x[4]+math.sin(sp3_theta)*ctlpt.hyp
          sp3_y = xxypath[xxypath_select].points[ctlpt.p-1].y[4]+math.cos(sp3_theta)*ctlpt.hyp
        end
        xxypath[xxypath_select].points[ctlpt.p-1].x[3] = F_limit(sp3_x,0,1)
        xxypath[xxypath_select].points[ctlpt.p-1].y[3] = F_limit(sp3_y,0,1)

        xxypath[xxypath_select].points[ctlpt.p].len = XXYPath_CalcPathSectionLength(ctlpt.p)
        xxypath[xxypath_select].points[ctlpt.p-1].len = XXYPath_CalcPathSectionLength(ctlpt.p-1)

      end

    else

      if ctlpt.p >= #xxypath[xxypath_select].points-1 then

        xxypath[xxypath_select].points[ctlpt.p].x[ctlpt.sp] = F_limit(x,0,1)
        xxypath[xxypath_select].points[ctlpt.p].y[ctlpt.sp] = F_limit(y,0,1)

        xxypath[xxypath_select].points[ctlpt.p].len = XXYPath_CalcPathSectionLength(ctlpt.p)
      else

        xxypath[xxypath_select].points[ctlpt.p].x[ctlpt.sp] = F_limit(x,0,1)
        xxypath[xxypath_select].points[ctlpt.p].y[ctlpt.sp] = F_limit(y,0,1)

        local sp3_opp = xxypath[xxypath_select].points[ctlpt.p].x[4]-xxypath[xxypath_select].points[ctlpt.p].x[3]
        local sp3_adj = xxypath[xxypath_select].points[ctlpt.p].y[4]-xxypath[xxypath_select].points[ctlpt.p].y[3]
        local sp2_theta = math.atan(sp3_opp/sp3_adj)

        local sp2_x, sp2_y
        if sp3_adj < 0 then
          sp2_x = xxypath[xxypath_select].points[ctlpt.p+1].x[1]-math.sin(sp2_theta)*ctlpt.hyp
          sp2_y = xxypath[xxypath_select].points[ctlpt.p+1].y[1]-math.cos(sp2_theta)*ctlpt.hyp
        else
          sp2_x = xxypath[xxypath_select].points[ctlpt.p+1].x[1]+math.sin(sp2_theta)*ctlpt.hyp
          sp2_y = xxypath[xxypath_select].points[ctlpt.p+1].y[1]+math.cos(sp2_theta)*ctlpt.hyp
        end
        xxypath[xxypath_select].points[ctlpt.p+1].x[2] = F_limit(sp2_x,0,1)
        xxypath[xxypath_select].points[ctlpt.p+1].y[2] = F_limit(sp2_y,0,1)

        xxypath[xxypath_select].points[ctlpt.p].len = XXYPath_CalcPathSectionLength(ctlpt.p)
        xxypath[xxypath_select].points[ctlpt.p+1].len = XXYPath_CalcPathSectionLength(ctlpt.p+1)

      end

    end

  end

  function XXYPATH_addpoint(x,y)

    --[[if #xxypath == 0 then
      xxypath = {points = {x = {}, y = {}}}
    end]]
    if xxypath_select == nil then
      local strip = tracks[track_select].strip
      if xxy and xxy[strip] and xxy[strip][page][sstype_select] then
        xxypath_select = #xxypath + 1
        xxy[strip][page][sstype_select].pathidx = xxypath_select
      else
        return
      end
    end

    if xxypath[xxypath_select] == nil then
      xxypath[xxypath_select] = {}
      xxypath[xxypath_select].points = {}
    end

    local p = #xxypath[xxypath_select].points
    if p == 0 then
      xxypath[xxypath_select].points[p+1] = {x={x},y={y}}
    else
      xxypath[xxypath_select].points[p+1] = {x={x},y={y}}

      xxypath[xxypath_select].points[p].x[4] = x
      xxypath[xxypath_select].points[p].y[4] = y

      if p == 1 then
        xxypath[xxypath_select].points[p].x[2] = (xxypath[xxypath_select].points[p].x[4] - xxypath[xxypath_select].points[p].x[1]) * 0.25 + xxypath[xxypath_select].points[p].x[1]
        xxypath[xxypath_select].points[p].y[2] = (xxypath[xxypath_select].points[p].y[4] - xxypath[xxypath_select].points[p].y[1]) * 0.25 + xxypath[xxypath_select].points[p].y[1]
      else
        xxypath[xxypath_select].points[p].x[2] = xxypath[xxypath_select].points[p].x[1] + (xxypath[xxypath_select].points[p-1].x[4] - xxypath[xxypath_select].points[p-1].x[3])
        xxypath[xxypath_select].points[p].y[2] = xxypath[xxypath_select].points[p].y[1] + (xxypath[xxypath_select].points[p-1].y[4] - xxypath[xxypath_select].points[p-1].y[3])
      end
      xxypath[xxypath_select].points[p].x[3] = (xxypath[xxypath_select].points[p].x[4] - xxypath[xxypath_select].points[p].x[1]) * 0.75 + xxypath[xxypath_select].points[p].x[1]
      xxypath[xxypath_select].points[p].y[3] = (xxypath[xxypath_select].points[p].y[4] - xxypath[xxypath_select].points[p].y[1]) * 0.75 + xxypath[xxypath_select].points[p].y[1]

    end

    if p > 0 then
      xxypath[xxypath_select].points[p].len = XXYPath_CalcPathSectionLength(p)
      xxypath[xxypath_select].pathlen = XXYPath_CalcPathLen(xxypath_select)
    end

  end

  function XXYPath_CalcPathLen(xxysel)

    local len = 0
    if #xxypath[xxysel].points > 1 then
      for pt = 1, #xxypath[xxysel].points do
        if xxypath[xxysel].points[pt].len then
          len = len + xxypath[xxysel].points[pt].len
        end
      end
      local ppos = 0
      for pt = 1, #xxypath[xxysel].points do
        if xxypath[xxysel].points[pt].len then
          if pt == 0 then
            xxypath[xxysel].points[pt].posstart = 0
          else
            xxypath[xxysel].points[pt].posstart = ppos / len
          end
          xxypath[xxysel].points[pt].posend = (ppos + xxypath[xxysel].points[pt].len)/ len
          ppos = ppos + xxypath[xxysel].points[pt].len
        end
      end

      xxypath[xxysel].pathidxpt = {}
      local pt = 1
      for pi = 0,xxypath_indexcnt do
        local pival = 1/xxypath_indexcnt * pi
        while xxypath[xxysel].points[pt] and xxypath[xxysel].points[pt].posstart and (xxypath[xxysel].points[pt].posstart <= pival) do
          pt = pt + 1
        end
        xxypath[xxysel].pathidxpt[pi] = pt-1
      end

    end
    return len

  end

  function XXYPath_CalcPathSectionLength(pt)
    if #xxypath[xxypath_select].points > 1 and pt < #xxypath[xxypath_select].points then
      return path_length(xxypath[xxypath_select].points[pt].x,xxypath[xxypath_select].points[pt].y,xxypath[xxypath_select].points[pt])
    end
  end

  function path_length(x_table, y_table, pt)
    order = #x_table
    ----------------------------
    ----------------------------
    function bezier_eq(n, tab_xy, dt)
      local B = 0
      for i = 0, n-1 do
        B = B +
          ( fact[n] / ( fact[i] * fact[n-i] ) )
          *  (1-dt)^(n-i)
          * dt ^ i
          * tab_xy[i+1]
      end
      return B
    end
    ----------------------------
    local ox,oy = nil, nil
    local pathl = 0
    pt.lens = {}
    local resolution = 1/1000
    for t = 0, 1, resolution do
      x_point = bezier_eq(order, x_table, t)+ t^order*x_table[order]
      y_point = bezier_eq(order, y_table, t)+ t^order*y_table[order]
      x = (x_point)
      y = (y_point)
      if ox and oy then
        local secl = math.sqrt((x_point-ox)^2+(y_point-oy)^2)
        pathl = pathl + secl
      end
      pt.lens[tonumber(string.format('%i',tostring((1/resolution)*t)))] = pathl
      ox,oy = x,y
    end
    local def = math.floor(math.max(pathl * 500,xxypath_tres))
    local p = 0
    pt.t = {}
    for d = 0, def do
      while p < #pt.lens and pt.lens[p] / pathl < d/def do
        p = p + 1
      end
      pt.t[d] = math.max(resolution * (p-1),0)
    end
    pt.lens = nil
    return pathl
  end

  function Faders_Check(strip, page)
    if LBX_CTL_TRACK --[[and faders]] then

      local ccc = trackfxparam_select

      local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
      if tracks[LBX_CTL_TRACK].guid ~= GetTrackGUID(track) then
        PopulateTracks()
      end
      for fxnum = 0, LBX_CTL_TRACK_INF.count-1 do
        for pf = 0, lvar.LBX_FB_CNT-1 do
          p = fxnum * lvar.LBX_FB_CNT + pf
          if faders[p+1] and faders[p+1].targettype then
            if faders[p+1].targettype == 2 or faders[p+1].targettype == 4 then
              --macro/fx param check
              if faders[p+1].dm_guid then
                if faders[p+1].dm_guid == lvar.dynamicmode_guid then
                  if strips[faders[p+1].strip] then
                    local ctls = strips[faders[p+1].strip][faders[p+1].page].controls
                    if ctls[faders[p+1].ctl] == nil or (ctls[faders[p+1].ctl] and faders[p+1].c_id ~= ctls[faders[p+1].ctl].c_id) then
                      local fnd = false
                      for c = 1, #ctls do
                        if ctls[c].c_id == faders[p+1].c_id then
                          fnd = true
                          faders[p+1].ctl = c
                          break
                        end
                      end
                      if fnd == false then
                        --not found - delete assignment - macro control deleted
                        faders[p+1] = {}
                      end
                    end
                  else
                    faders[p+1] = {}
                  end
                else
                  if lvar.stripstore and lvar.stripstore[faders[p+1].dm_guid] then
                    local ctls = lvar.stripstore[faders[p+1].dm_guid].controls
                    if ctls[faders[p+1].ctl] == nil or (ctls[faders[p+1].ctl] and faders[p+1].c_id ~= ctls[faders[p+1].ctl].c_id) then
                      local fnd = false
                      for c = 1, #ctls do
                        if ctls[c].c_id == faders[p+1].c_id then
                          fnd = true
                          faders[p+1].ctl = c
                          break
                        end
                      end
                      if fnd == false then
                        --not found - delete assignment - macro control deleted
                        faders[p+1] = {}
                      end
                    end
                  else
                    faders[p+1] = {}
                  end
                end
              else
                if faders[p+1].c_id then
                  if strips[faders[p+1].strip] then
                    local ctls = strips[faders[p+1].strip][faders[p+1].page].controls
                    if ctls[faders[p+1].ctl] == nil or (ctls[faders[p+1].ctl] and faders[p+1].c_id ~= ctls[faders[p+1].ctl].c_id) then
                      local fnd = false
                      for c = 1, #ctls do
                        if ctls[c].c_id == faders[p+1].c_id then
                          fnd = true
                          faders[p+1].ctl = c
                          break
                        end
                      end
                      if fnd == false then
                        --not found - delete assignment - macro control deleted
                        faders[p+1] = {}
                      end
                    end
                  else
                    faders[p+1] = {}
                  end
                end
              end
            end
          elseif faders[p+1] == nil then
            faders[p+1] = {}
          end
        end
      end
    end
  end

  function Macro_Capture(strip, page, ctl, ab)

    local macro = strips[strip][page].controls[ctl].macroctl
    if macro then
      for m = 1, #macro do

        local ctl = macro[m].ctl
        local v = strips[strip][page].controls[ctl].val

        if ab == 0 then
          macro[m].A_val = v
        else
          if macro[m].bi == false then
            macro[m].B_val = v
          end
        end

      end
    end
  end

  function Macros_Check(strip, page)

    if strips[strip] and strips[strip][page] then
      local ctls = strips[strip][page].controls
      if ctls and #ctls > 0 then

        local cids = {}
        for c = 1,#ctls do
          cids[ctls[c].c_id] = c
        end

        for c = 1,#ctls do

          if ctls[c].ctlcat == ctlcats.macro or ctls[c].ctlcat == ctlcats.macro_updateparam then

            local macro = ctls[c].macroctl

            if macro and #macro > 0 then

              local mcnt = #macro
              for m = 1, mcnt do

                if macro[m].c_id ~= ctls[macro[m].ctl] then

                  if cids[macro[m].c_id] then
                    macro[m].ctl = cids[macro[m].c_id]
                  else
                    --deleted
                    macro[m] = nil
                  end
                end
              end
              strips[strip][page].controls[c].macroctl = Table_RemoveNils(macro, mcnt)
            end
          end
        end
      end
    end
  end

  function Macro_UpdateCtls(strip, page, ctl)

    local macro = strips[strip][page].controls[ctl].macroctl
    if macro then
      local nmacro = {}
      local mcnt = #macro
      for m = 1, mcnt do

        if macro[m].delete then
          macro[m] = nil
        end

      end
      nmacro = Table_RemoveNils(macro, mcnt)
      strips[strip][page].controls[ctl].macroctl = nmacro

      lupd.update_gfx = true
    end
  end

  function SetMacro(strip, page, ctl, mon, force)
--DBG('macro'..tostring(force))
    ofxparam = trackfxparam_select
    local ctls = strips[strip][page].controls
    local macro = ctls[ctl].macroctl
    ctls[ctl].dirty = true
    if macro then
      local byp = {}
      for m = 1, #macro do

        if macro[m].mute == false or macro[m].mute == nil then
          if macro[m].relative ~= true then
            if macro[m].bi == true then

              local c = ctls[macro[m].ctl]
              local mv = ctls[ctl].val
              local ma = macro[m].A_val
              local mb = macro[m].B_val
              trackfxparam_select = macro[m].ctl

              local v
              if macro[m].inv then
                v = F_limit(ma - macScale(macro[m].shape,(mv-0.5)*2) * mb,F_limit(ma-mb,0,1),F_limit(ma+mb,0,1))
              else
                v = F_limit(ma + macScale(macro[m].shape,(mv-0.5)*2) * mb,F_limit(ma-mb,0,1),F_limit(ma+mb,0,1))
              end
              if v ~= macro[m].oval or force or c.ctlcat == ctlcats.snapshotrand then
                c.oval = c.val
                c.val = v
                A_SetParam(strip, page, trackfxparam_select, c, true)
                macro[m].oval = v
                if c.param_info.paramname == 'Bypass' then
                  byp[#byp+1] = c.fxnum
                end
              end

            else
              local c = ctls[macro[m].ctl]
              local mv = ctls[ctl].val
              local ma = macro[m].A_val
              local mb = macro[m].B_val

              trackfxparam_select = macro[m].ctl
              local v
              if macro[m].inv then
                v = (ma - mb) * macScale(macro[m].shape,mv) + mb
              else
                v = (mb - ma) * macScale(macro[m].shape,mv) + ma
              end
              if v ~= macro[m].oval or ctls[ctl].param_info.paramnum == 1 or force or c.ctlcat == ctlcats.snapshotrand then
              --DBG('ttt')
                c.oval = c.val
                c.val = v
                A_SetParam(strip, page, trackfxparam_select, c, true)
                macro[m].oval = v
                if c.param_info.paramname == 'Bypass' then
                  byp[#byp+1] = c.fxnum
                end
              end
            end

          elseif mon ~= true then

            local c = ctls[macro[m].ctl]
            local mc = ctls[ctl]
            local mva = mc.val
            local mov = mc.oval
            if not mov then mov = mva end
            local mv = -(macScale(macro[m].shape,mov)-macScale(macro[m].shape,mva))
            local ma = macro[m].A_val
            local mb = macro[m].B_val
            if mv then
              mv =  mv * mb
              trackfxparam_select = macro[m].ctl
              if macro[m].inv then
                mv = -mv
              end
              if c.mval then
                v = c.mval + mv
              else
                v = c.val + mv
              end

              if v ~= macro[m].oval or force or c.ctlcat == ctlcats.snapshotrand then
                c.oval = c.val
                c.val = F_limit(v,0,1)
                A_SetParam(strip, page, trackfxparam_select, c, true)
                c.mval = v
                macro[m].oval = v
                if c.param_info.paramname == 'Bypass' then
                  byp[#byp+1] = c.fxnum
                end
              end
            end
          end
          SetCtlDirty(macro[m].ctl)

        end
      end
      if #byp > 0 then
        SetCtlsEnabled(byp)
        lupd.update_ctls = true
      end
    end
    trackfxparam_select = ofxparam

  end

  function XXY_Set(strip, page, sst)

    if sst > 1 then

      local fsqrt = math.sqrt
      local fmin = math.min
      local fmax = math.max
      local ffloor = math.floor

      xxy_mindist = 1
      xxy_maxdist = 0
      local xxytbl = xxy[strip][page][sst]
      local d = {}
      local gtrack = GetTrack(strips[strip].track.tracknum)
      local px, py = xxytbl.x, xxytbl.y
      if xxyrecord and xxymode == 0 then
        local track = GetTrack(tracks[LBX_CTL_TRACK].tracknum)
        local xf = xxytbl.xfader
        local yf = xxytbl.yfader
        if xf and faders[xf] then
          local fxnum = ffloor((xf-1)/lvar.LBX_FB_CNT)
          local param = ((xf-1) % lvar.LBX_FB_CNT)
          reaper.TrackFX_SetParam(track, fxnum, param, px)
          faders[xf].val = px
        end
        if yf and faders[yf] then
          local fxnum = ffloor((yf-1)/lvar.LBX_FB_CNT)
          local param = (yf-1) % lvar.LBX_FB_CNT
          reaper.TrackFX_SetParam(track, fxnum, param, py)
          faders[yf].val = py
        end
      end
      for p = 1, #xxytbl.points do
        d[p] = fsqrt((px - xxytbl.points[p].x)^2 + (py - xxytbl.points[p].y)^2)
        xxytbl.points[p].d2 = d[p]
        d[p] = d[p]^xxy_gravity
        xxytbl.points[p].distance = d[p]
        xxy_mindist = fmin(xxy_mindist,d[p])
        xxy_maxdist = fmax(xxy_maxdist,d[p])
      end
      for ctl = 1, #snapshots[strip][page][sst].ctls do
        local num, den = 0, 0
        for p = 1, #d do
          if xxytbl.points[p].inactive ~= true then
            local ss = xxytbl.points[p].ss
            if snapshots[strip][page][sst].snapshot[ss].data[ctl] then
              local v = snapshots[strip][page][sst].snapshot[ss].data[ctl].dval
              if v then
                num = num + v/d[p]
                den = den + 1/d[p]
              end
            end
          end
        end
        local nv = num/den

        if xxytbl.points[1] then
          local ss = xxytbl.points[1].ss
          if snapshots[strip][page][sst].snapshot[ss].data[ctl] then
            local c = snapshots[strip][page][sst].snapshot[ss].data[ctl].ctl
            if c and nv and nv < 1/0 and nv > -1/0 then
              local ctl = strips[strip][page].controls[c]
              if ctl.ctllock ~= true then
                trackfxparam_select = c
                if ctl.tracknum then
                  track = GetTrack(ctl.tracknum)
                else
                  track = gtrack
                end
                if tostring(nv) ~= tostring(ctl.xxydval) then
                  SetParam3_Denorm2_Safe(track, nv, strip, page)
                  ctl.xxydval = nv
                end
              end
            end
          end
        end
      end
    end

  end

  function XXY_INIT(strip, page, sst)
    if xxy == nil then
      xxy = {}
    end
    if xxy[strip] == nil then
      xxy[strip] = {}
    end
    if xxy[strip][page] == nil then
      xxy[strip][page] = {}
    end
    if xxy[strip][page][sst] == nil then
      xxy[strip][page][sst] = {x = 0.5, y = 0.5, points = {}}
    end
  end

  function ReselectSelection()

    if ctl_select then
      local tbl = {}
      tbl[1] = {ctl = ctl_select[1].ctl}
      for i = 2, #ctl_select do

        tbl[i] = {}
        tbl[i].ctl = ctl_select[i].ctl
        tbl[i].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].x
        tbl[i].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].controls[ctl_select[i].ctl].y

      end

      ctl_select = tbl
    end
    if gfx3_select then
      local tbl = {}
      for i = 1, #gfx3_select do

        tbl[i] = {}
        tbl[i].ctl = gfx3_select[i].ctl
        tbl[i].relx = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].x - strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].x
        tbl[i].rely = strips[tracks[track_select].strip][page].controls[ctl_select[1].ctl].y - strips[tracks[track_select].strip][page].graphics[gfx3_select[i].ctl].y

      end

      gfx3_select = tbl
    end

  end

  function SelectAll()

    if mode == 1 and submode == 0 then
      local strip = tracks[track_select].strip
      if strips[strip] then
        ctl_select = {}
        gfx3_select = {}
        local ctls = strips[strip][page].controls
        for c = 1, #ctls do
          ctl_select[c] = {ctl = c}
          if c ~= 1 then
            ctl_select[c].relx = ctls[ctl_select[1].ctl].x - ctls[ctl_select[c].ctl].x
            ctl_select[c].rely = ctls[ctl_select[1].ctl].y - ctls[ctl_select[c].ctl].y
          end
        end
        if mouse.shift then
          local gfxx = strips[strip][page].graphics
          for c = 1, #gfxx do
            gfx3_select[c] = {ctl = c}
            gfx3_select[c].relx = ctls[ctl_select[1].ctl].x - gfxx[gfx3_select[c].ctl].x
            gfx3_select[c].rely = ctls[ctl_select[1].ctl].y - gfxx[gfx3_select[c].ctl].y
          end
        end
        lupd.update_surface = true
        lupd.update_cbox = true
      end

    elseif mode == 1 and submode == 1 then
      local strip = tracks[track_select].strip
      if strips[strip] then
        gfx4_select = {}
        gfx4_selectidx = {}
        for c = 1, #strips[strip][page].graphics do
          gfx4_select[c] = c
          gfx4_selectidx[gfx4_select[c]] = c
        end
        glob_gfxselrect = CalcGFX4SelRect()
        lupd.update_surface = true
        lupd.update_cbox = true
      end

    end

  end

  function GetLastTouchedFX(lastfx)

    local rt, tr, fx, pr = reaper.GetLastTouchedFX()
    if rt == true then
      if lastfx == nil or (lastfx ~= nil and (tr-1 ~= lastfx.tracknum or fx ~= lastfx.fxnum or pr ~= lastfx.paramnum)) then
        local track = GetTrack(tr-1)
        if track ~= nil then
          local tn = reaper.GetTrackState(track)
          local trg = GetTrackGUID(track)
          local _, fxn = reaper.TrackFX_GetFXName(track, fx, '')
          local fxg = reaper.TrackFX_GetFXGUID(track, fx)
          local _, prn = reaper.TrackFX_GetParamName(track, fx, pr, '')
          lastfx = {tracknum = tr-1,
                    trguid = trg,
                    fxnum = fx,
                    paramnum = pr,
                    trname = tn,
                    fxname = fxn,
                    fxguid = fxg,
                    prname = prn}
          lupd.update_gfx = true
        end
      end
      return lastfx
    else
      return lastfx
    end

  end

  function Cycle_InitData()

    if cycle_select.statecnt > 0 then

      trackfxparam_select = ctl_select[1].ctl
      local strip = tracks[track_select].strip
      local ctl = strips[strip][page].controls[trackfxparam_select]
      local tracknum = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        tracknum = ctl.tracknum
      end
      local cc = ctl.ctlcat
      local fxnum = ctl.fxnum
      local param = ctl.param
      local dvoff = ctl.dvaloffset
      for i = 1, cycle_select.statecnt do
        if cycle_select[i] == nil or (cycle_select[i] and cycle_select[i].dispval == nil) then
          if cc ~= ctlcats.action then
            SetParam3(strip,page,trackfxparam_select,ctl,cycle_select.val)
          end
          local dv = GetParamDisp(cc, tracknum, fxnum, param, dvoff,trackfxparam_select)
          --DBG(i..'  '..cycle_select.val)
          cycle_select[i] = {val = cycle_select.val, dispval = dv, dv = dv}
        end
      end
      cycle_select.selected = cycle_select.statecnt

      if cc ~= ctlcats.action then
        A_SetParam(strip,page,trackfxparam_select,ctl)
      end

    end

  end

  function Cycle_CopySelectIn(ctl)

    local cd = {}
    if strips[tracks[track_select].strip][page].controls[ctl].cycledata then
      cd = strips[tracks[track_select].strip][page].controls[ctl].cycledata
      local co
      if cd.statecnt > 0 then
        co = {statecnt = cd.statecnt,
                    selected = cd.selected,
                    mapptof = cd.mapptof,
                    invert = cd.invert,
                    draggable = cd.draggable,
                    spread = cd.spread,
                    val = 0,
                    {}}
      else
        co = {statecnt = cd.statecnt,
                    selected = cd.selected,
                    mapptof = mapptof_select,
                    invert = invert_select,
                    draggable = draggable_select,
                    spread = spread_select,
                    val = 0,
                    {}}
      end
      for i = 1, max_cycle do
        if cd[i] then
          co[i] = {val = cd[i].val, dispval = cd[i].dispval, dv = cd[i].dv, startval = cd[i].startval, nextval = cd[i].nextval}
          if cd[i].tsp then
            co[i].tsp = {swid = cd[i].tsp.swid, grpid = cd[i].tsp.grpid}
          end
        end
      end
      return co
    else
      return {statecnt = 0,mapptof = mapptof_select, inert = invert_select, draggable = draggable_select,spread = spread_select,val = 0,nil}
    end
  end

  function Cycle_CopySelectOut()

    local cd = {}
    if cycle_select then
      cd = cycle_select
      local co = {statecnt = cd.statecnt,
                  selected = cd.selected,
                  mapptof = cd.mapptof,
                  invert = cd.invert,
                  draggable = cd.draggable,
                  spread = cd.spread,
                  {}}
      for i = 1, max_cycle do
        if cd[i] then
          cd[i].val = cd[i].val or 0
          co[i] = {val = tonumber(cd[i].val), dispval = cd[i].dispval, dv = cd[i].dv, startval = tonumber(cd[i].startval), nextval = tonumber(cd[i].nextval)}
          if cd[i].tsp then
            co[i].tsp = {swid = cd[i].tsp.swid, grpid = cd[i].tsp.grpid}
            co.tspactive = true
          end
          --DBG(tostring(co[i].val)..'  '..tostring(cd[i].val))
        end
      end
      co = cycledata_slowsort(cd)
      return co
    else
      return {statecnt = 0, mapptof = false, invert = false, draggable = false,spread = false,pos = 1,{}}
    end
  end

  function Cycle_Norm(v, c)

    if c then

      local cc = strips[tracks[track_select].strip][page].controls[c].ctlcat
      if cc == ctlcats.fxparam then
        local min, max = GetParamMinMax_ctl(c)
        return normalize(min, max, v)
      elseif cc ~= ctlcats.action then
        local min, max = GetParamMinMax_ctl(c)
        return F_limit(v,min,max)
      end

    end

  end

  function Cycle_DeleteStep(step)

    local cd = {}
    if cycle_select then
      cd = cycle_select
      local co = {statecnt = cd.statecnt,
                  selected = nil,
                  mapptof = cd.mapptof,
                  invert = cd.invert,
                  draggable = cd.draggable,
                  spread = cd.spread,
                  val = 0,
                  {}}
      cd[step] = nil
      local ins = 0
      for i = 1, max_cycle do
        if cd[i] then
          ins = ins + 1
          co[ins] = {val = tonumber(cd[i].val), dispval = cd[i].dispval, dv = cd[i].dv, startval = tonumber(cd[i].startval), nextval = tonumber(cd[i].nextval)}
          if cd[i].tsp then
            co[ins].tsp = {swid = cd[i].tsp.swid, grpid = cd[i].tsp.grpid}
          end
          --co[ins] = {val = tonumber(cd[i].val), dispval = cd[i].dispval, dv = cd[i].dv}
        end
      end
      co.statecnt = ins
      return co
    else
      return {statecnt = 0,mapptof = false,draggable = false,spread = false,pos = 1,{}}
    end
  end

  function Cycle_CreateRadioButton(c,dx,dy)

    local ctls = strips[tracks[track_select].strip][page].controls
    local c1 = #ctls+1

    if dx == nil or dy == nil then
      dx = 0
      dy = ctls[c].ctl_info.cellh
    end

    local ocd = cycle_select
    local sel = ocd.selected

    local cc = c1
    ctls[cc]=GetControlTable(tracks[track_select].strip, page, c)

    local ctl = ctls[cc]
    ctl.poslock = false
    ctl.x = ctl.x + dx
    ctl.y = ctl.y + dy
    ctl.xsc = ctl.xsc + dx
    ctl.ysc = ctl.ysc + dy
    ctl.id = nil

    local cd = Cycle_CopySelectOut()

    cd.pos = 1

    cd[1] = {val = tonumber(ocd[sel].val), dispval = ocd[sel].dispval, dv = ocd[sel].dv,
             startval = tonumber(ocd[sel].startval), nextval = tonumber(ocd[sel].nextval)}
    for i = 2, #cd do
      cd[i] = nil
    end
    cd.statecnt = 1
    cd.mapptof = true
    cd.draggable = false
    cd.val = 0
    cd.spread = false
    cd.invert = true
    cd.selected = 1

    ctl.ctlname_override = cd[1].dispval
    ctl.show_paramval = false
    ctl.show_paramname = true

    ctl.cycledata = cd
    ctl.val = 0

    ctl.gauge = nil
    lupd.update_bg = true
    lupd.update_gfx = true
    SetCtlBitmapRedraw()

  end

  function Cycle_AutoMenu()
  end
  
  function Cycle_Auto()

    local sldiv = 400
    --local ad = auto_delay*1000000

    if cycle_select.statecnt == 0 then

      trackfxparam_select = ctl_select[1].ctl
      local strip = tracks[track_select].strip
      local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
      local v, v2 = 0.0,0.0

      local tracknum = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        tracknum = ctl.tracknum
      end
      local cc = ctl.ctlcat
      local fxnum = ctl.fxnum
      local param = ctl.param
      local dvoff = ctl.dvaloffset

      SetParam3(strip,page,trackfxparam_select,ctl,v)
      local x = 0
      os.sleep((auto_delay/sldiv)*10)
      local dval = GetParamDisp(cc, tracknum, fxnum, param, dvoff,trackfxparam_select)
      local stcnt = 1
      local ndval

      cycle_temp = {}
      --nextval must be > 1 to allow detection of final radio button in single state mode
      cycle_temp[1] = {val = v, dispval = dval, dv = dval, startval = v, nextval = 1.01}

      for v = 0.01, 1, 0.01 do

        GUI_DrawMsgX(obj, gui, 'Scanning values...', v, 1)
        SetParam3(strip,page,trackfxparam_select,ctl,v)
        local x = 0
        os.sleep((auto_delay/sldiv)*10)
        ndval = GetParamDisp(cc, tracknum, fxnum, param, dvoff,trackfxparam_select)
        if ndval ~= dval then
          dval = ndval
          local v2 = GetParamValue(cc, tracknum, fxnum, param, trackfxparam_select)
          cycle_temp[#cycle_temp].nextval = math.min(v,v2)
          cycle_temp[#cycle_temp+1] = {val = v2, dispval = dval, dv = dval, startval = math.min(v,v2), nextval = 1.01}
          stcnt = stcnt + 1
        end

      end

      if stcnt > max_cycle then
        OpenMsgBox(1, 'Too many values.', 1)
      else
        for i = 1, max_cycle do
          cycle_select[i] = cycle_temp[i]
        end
        cycle_select.statecnt = stcnt
      end
      A_SetParam(strip,page,trackfxparam_select,ctl)

    else

      local cycmode
      if mouse.ctrl then
        cycmode = 1
      end
      trackfxparam_select = ctl_select[1].ctl
      local strip = tracks[track_select].strip
      local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]

      local min, max = GetParamMinMax_ctl(trackfxparam_select, true)
      local step = (max-min)/(cycle_select.statecnt-1)
      local min2, max2 = GetParamMinMax_ctl(trackfxparam_select, false)
      local md = (max2-min2)/(max-min)
      local v, v2 = min2,0.0

      local tracknum = strips[strip].track.tracknum
      if ctl.tracknum ~= nil then
        tracknum = ctl.tracknum
      end
      local cc = ctl.ctlcat
      local fxnum = ctl.fxnum
      local param = ctl.param
      local dvoff = ctl.dvaloffset

      SetParam3(strip,page,trackfxparam_select,ctl,v)
      local x = 0
      os.sleep((auto_delay/sldiv)*10)
      local dval = GetParamDisp(cc, tracknum, fxnum, param, dvoff,trackfxparam_select)
      local stcnt = 1
      local ndval

      cycle_temp = {}
      if cycmode == 1 then
        cycle_temp[1] = {val = v, dispval = 1, dv = 1}
      else
        cycle_temp[1] = {val = v, dispval = dval, dv = dval}
      end
      
      for i = 1, cycle_select.statecnt-1 do

        GUI_DrawMsgX(obj, gui, 'Scanning values...', i, cycle_select.statecnt-1)
        v = min2+(i*step*md)
        SetParam3(strip,page,trackfxparam_select,ctl,v)
        local x = 0
        os.sleep((auto_delay/sldiv)*10)
        ndval = GetParamDisp(cc, tracknum, fxnum, param, dvoff, trackfxparam_select)
        dval = ndval
        
        local v2 = GetParamValue(cc, tracknum, fxnum, param, trackfxparam_select)
        if cycmode == 1 then
          cycle_temp[#cycle_temp+1] = {val = v, dispval = i+1, dv = i+1}
        else
          cycle_temp[#cycle_temp+1] = {val = v2, dispval = dval, dv = dval}
        end
        stcnt = stcnt + 1

      end

      for i = 1, stcnt do
        cycle_select[i] = cycle_temp[i]
      end
      if cycle_select.statecnt > stcnt then
        for i = stcnt + 1, cycle_select.statecnt do
          cycle_select[i] = {val = 0, dispval = '', dv = ''}
        end
      end
      --cycle_select.statecnt = stcnt
      A_SetParam(strip,page,trackfxparam_select,ctl)

    end

  end

  function SetCtlEnabled(fxnum, state)

    --local i
    --local enabled = reaper.TrackFX_GetEnabled(GetTrack(tracks[track_select].tracknum),fxnum)
    local strip = tracks[track_select].strip
    for i = 1, #strips[strip][page].controls do
      local ctl = strips[strip][page].controls[i]
      if ctl.fxnum == fxnum then
        --ctl.dirty = true
        if state == 4 then
          ctl.offline = true
        elseif state then
          ctl.offline = false
        end
        SetCtlDirty(i)
      end
    end

  end

  function SetCtlsEnabled(fxnum, state)

    --local i
    --local enabled = reaper.TrackFX_GetEnabled(GetTrack(tracks[track_select].tracknum),fxnum)
    local strip = tracks[track_select].strip
    for i = 1, #strips[strip][page].controls do
      local ctl = strips[strip][page].controls[i]
      for f = 1, #fxnum do
        if ctl.fxnum == fxnum[f] then
          --ctl.dirty = true
          if state == 4 then
            ctl.offline = true
          elseif state then
            ctl.offline = false
          end
          SetCtlDirty(i)
          break
        end
      end
    end

  end

  function GetGraphicsTable(strip, page, c, obj)

    if obj == nil then
      obj = strips[strip][page].graphics[c]
    end

    if obj then
      local tbl = {gfxtype = obj.gfxtype,
                   fn = obj.fn,
                   imageidx = obj.imageidx,
                   x = obj.x,
                   y = obj.y,
                   w = obj.w,
                   h = obj.h,
                   scale = obj.scale,
                   stretchw = obj.stretchw,
                   stretchh = obj.stretchh,
                   switcher = obj.switcher,
                   grpid = obj.grpid,
                   font = {idx = obj.font.idx,
                           name = obj.font.name,
                           size = obj.font.size,
                           bold = obj.font.bold,
                           italics = obj.font.italics,
                           underline = obj.font.underline,
                           vertical = obj.font.vertical,
                           shadow = obj.font.shadow,
                           shadow_x = obj.font.shadow_x,
                           shadow_y = obj.font.shadow_y,
                           shadow_a = obj.font.shadow_a
                           },
                   text = obj.text,
                   text_col = obj.text_col,
                   poslock = false,
                   bright = obj.bright,
                   contr = obj.contr,
                   rmult = obj.rmult,
                   gmult = obj.gmult,
                   bmult = obj.bmult,
                   alpha = obj.alpha,
                   stretchmode = obj.stretchmode,
                   edgesz = obj.edgesz,
                   }
      return tbl
    end

  end

  function GetSwitcherTable(switchid)

    local tbl = {grpids = {},
                 current = switchers[switchid].current,
                 parent = {}}
    if switchers[switchid].parent then
      tbl.parent.switcherid = switchers[switchid].parent.switcherid
      tbl.parent.grpid = switchers[switchid].parent.grpid
    end
    if switchers[switchid].grpids and #switchers[switchid].grpids > 0 then
      for g = 1, #switchers[switchid].grpids do
        tbl.grpids[g] = {}
        tbl.grpids[g].id = switchers[switchid].grpids[g].id
        tbl.grpids[g].name = switchers[switchid].grpids[g].name
      end
    end
    return tbl

  end

  function GetControlTable(strip, page, c)

    local ctl = strips[strip][page].controls[c]
    if ctl then
      local tbl = {ctlcat=ctl.ctlcat,
                   fxname=ctl.fxname,
                   fxguid=ctl.fxguid,
                   fxnum=ctl.fxnum,
                   fxfound = ctl.fxfound,
                   param = ctl.param,
                   param_info = {paramname = ctl.param_info.paramname,
                                 paramnum = ctl.param_info.paramnum,
                                 paramidx = ctl.param_info.paramidx,
                                 paramstr = ctl.param_info.paramstr,
                                 paramdesttrnum = ctl.param_info.paramdesttrnum,
                                 paramdestguid = ctl.param_info.paramdestguid,
                                 paramdestchan = ctl.param_info.paramdestchan,
                                 paramsrcchan = ctl.param_info.paramsrcchan},
                   ctltype = ctl.ctltype,
                   knob_select = ctl.knob_select,
                   ctl_info = {fn = ctl.ctl_info.fn,
                               frames = ctl.ctl_info.frames,
                               imageidx = ctl.ctl_info.imageidx,
                               cellh = ctl.ctl_info.cellh},
                   x = ctl.x,
                   y = ctl.y,
                   w = ctl.w,
                   scale = ctl.scale,
                   xsc = ctl.xsc,
                   ysc = ctl.ysc,
                   wsc = ctl.wsc,
                   hsc = ctl.hsc,
                   show_paramname = ctl.show_paramname,
                   show_paramval = ctl.show_paramval,
                   ctlname_override = ctl.ctlname_override,
                   textcol = ctl.textcol,
                   textoff = ctl.textoff,
                   textoffval = ctl.textoffval,
                   textoffx = ctl.textoffx,
                   textoffvalx = ctl.textoffvalx,
                   textsize = ctl.textsize,
                   textsizev = ctl.textsizev,
                   textcolv = ctl.textcolv,
                   enabledefval = ctl.enabledefval,
                   font = ctl.font,
                   val = ctl.val,
                   defval = ctl.defval,
                   maxdp = ctl.maxdp,
                   cycledata = table.deepcopy(ctl.cycledata),
                   switcherid = ctl.switcherid,
                   switcher = ctl.switcher,
                   id = ctl.id,
                   grpid = ctl.grpid,
                   tracknum = ctl.tracknum,
                   trackguid = ctl.trackguid,
                   dvaloffset = ctl.dvaloffset,
                   minov = ctl.minov,
                   maxov = ctl.maxov,
                   membtn = {state = ctl.membtn.state,
                             mem = ctl.membtn.mem},
                   xydata = {snapa = ctl.xydata.snapa,
                             snapb = ctl.xydata.snapb,
                             snapc = ctl.xydata.snapc,
                             snapd = ctl.xydata.snapd,
                             x = ctl.xydata.x,
                             y = ctl.xydata.y},
                   scalemode = ctl.scalemode,
                   framemode = ctl.framemode,
                   horiz = ctl.horiz,
                   poslock = ctl.poslock,
                   c_id = GenID(),
                   knobsens = {norm = ctl.knobsens.norm,
                               fine = ctl.knobsens.fine,
                               wheel = ctl.knobsens.wheel,
                               wheelfine = ctl.knobsens.wheelfine,
                               m_norm = ctl.knobsens.m_norm,
                               m_fine = ctl.knobsens.m_fine,
                               m_wheel = ctl.knobsens.m_wheel,
                               m_wheelfine = ctl.knobsens.m_wheelfine
                               },
                   hidden = ctl.hidden,
                   gauge = Gauge_CopySelect(ctl.gauge),
                   noss = ctl.noss,
                   bright = ctl.bright,
                   bypassbg_c = ctl.bypassbg_c,
                   bypassbg_n = ctl.bypassbg_n,
                   bypassbg_v = ctl.bypassbg_v,
                   clickthrough = ctl.clickthrough,
                   limittext = ctl.limittext,
                   wwtext = ctl.wwtext,
                   textflags = ctl.textflags,
                   animatetime = ctl.animatetime,
                   animateshape = ctl.animateshape,
                   
                   }
      if ctl.monext then
        tbl.monext = table.copy(ctl.monext)
      end
      
      if ctl.adjust_active == 1 and ctl.adjust then
        tbl.adjust_active = ctl.adjust_active
        tbl.adjust = table.copy(ctl.adjust)
      end
      
      if ctl.ctlcat == ctlcats.macro and ctl.macroctl then
        local macro = ctl.macroctl
        local mctl = {}
        for m = 1, #macro do

          mctl[m] = {c_id = macro[m].c_id,
                     ctl = macro[m].ctl,
                     A_val = macro[m].A_val,
                     B_val = macro[m].B_val,
                     shape = macro[m].shape,
                     bi = macro[m].bi,
                     inv = macro[m].inv,
                     mute = macro[m].mute
                     }

        end
        tbl.macroctl = mctl
      end
      if ctl.ctlcat == ctlcats.rcm_switch and ctl.rcmdata and #ctl.rcmdata > 0 then
        tbl.rcmdata = table.copy(ctl.rcmdata)
        tbl.rcmrefresh = table.copy(ctl.rcmrefresh)
      end
      if ctl.ctlcat == ctlcats.midictl and ctl.midiout then
        tbl.midiout = table.copy(ctl.midiout)
      end
      if ctl.ctlcat == ctlcats.takeswitcher and ctl.iteminfo then
        tbl.iteminfo = table.copy(ctl.iteminfo)
      end
      if ctl.ctlcat == ctlcats.statectl and ctl.stateinfo then
        tbl.stateinfo = table.copy(ctl.stateinfo)
      end
      if ctl.ctlcat == ctlcats.snapshotrand and ctl.random then
        tbl.random = table.deepcopy(ctl.random)
      end
      if ctl.ctlcat == ctlcats.rs5k and ctl.rsdata then
        tbl.rsdata = table.deepcopy(ctl.rsdata)
      end

      return tbl
    end
  end

  BGCOL=0xFFFFFF

  function setcolor(i)
    gfx.set(((i>>16)&0xFF)/0xFF, ((i>>8)&0xFF)/0xFF, (i&0xFF)/0xFF)
  end

  ---- editbox ----

  function editbox_draw(gui, e)

    f_Get_SSV('0 0 0')
    gfx.a = 1

    local tscale = (pnl_scale-1)*fontscale
    GUI_StrFontOnly(gui,gui.fontsz.pnltit + tscale,gui.fontnm.pnltit,gui.fontflag.pnltit)
    local titw = gfx.measurestr(e.title)
    gfx.setfont(1, gui.fontname, gui.fontsz_knob + (pnl_scale-1)*fontscale)
    local valw = gfx.measurestr(e.text)
    local nw = math.max(math.floor(350*pnl_scale),titw+20*pnl_scale,valw+50*pnl_scale)
    if nw ~= obj.sections[8].w then
      obj.sections[8].w = nw
      obj.sections[8].x = math.floor(gfx1.main_w/2 - nw/2)
      obj = PosEBCtls(obj)
    end

    GUI_DrawPanel(obj.sections[8],true,e.title)

    GUI_DrawButton(gui, 'OK', obj.sections[6], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)
    GUI_DrawButton(gui, 'Cancel', obj.sections[7], gui.color.white, gui.skol.butt1_txt, true,'',false,gui.fontsz.butt)

    e.x = obj.sections[9].x
    e.y = obj.sections[9].y
    e.w = obj.sections[9].w
    e.h = obj.sections[9].h

    setcolor(e.bgcol)
    gfx.rect(e.x,e.y,e.w,e.h,true)

    setcolor(e.hasfocus and e.fgfcol or e.fgcol)
    gfx.rect(e.x,e.y,e.w,e.h,false)
    gfx.setfont(e.font)
    setcolor(e.txtcol)
    local w,h=gfx.measurestr(e.text)
    local ox,oy=e.x+e.l,e.y+(e.h-h)/2
    gfx.x,gfx.y=ox,oy
    gfx.drawstr(e.text)
    if e.sel ~= 0 then
      local sc,ec=e.caret,e.caret+e.sel
      if sc > ec then sc,ec=ec,sc end
      local sx=gfx.measurestr(string.sub(e.text, 0, sc))
      local ex=gfx.measurestr(string.sub(e.text, 0, ec))
      setcolor(e.txtcol)
      gfx.rect(ox+sx, oy, ex-sx, h, true)
      setcolor(e.bgcol)
      gfx.x,gfx.y=ox+sx,oy
      gfx.drawstr(string.sub(e.text, sc+1, ec))
    end
    if e.hasfocus == true then
      if e.cursstate < 8 then
        w=gfx.measurestr(string.sub(e.text, 0, e.caret))
        setcolor(e.curscol)
        gfx.line(e.x+e.l+w, e.y+2, e.x+e.l+w, e.y+e.h-4)
      end
      e.cursstate=(e.cursstate+1)%16
    end
  end

  function editbox_getcaret(e)
    local len=string.len(e.text)
    for i=1,len do
      w=gfx.measurestr(string.sub(e.text,1,i))
      if gfx.mouse_x < e.x+e.l+w then return i-1 end
    end
    return len
  end

  function editbox_onmousedown(e)
    --e.hasfocus=
    --  gfx.mouse_x >= editbox.x and gfx.mouse_x < editbox.x+editbox.w and
    --  gfx.mouse_y >= editbox.y and gfx.mouse_y < editbox.y+editbox.h
    if e.hasfocus then
      e.caret=editbox_getcaret(e)
      e.cursstate=0
    end
    e.sel=0
  end

  function editbox_onmousedoubleclick(e)
    local len=string.len(e.text)
    e.caret=len ; e.sel=-len
  end

  function editbox_onmousemove(e)
    e.sel=editbox_getcaret(e)-e.caret
    lvar.editbox_mouseLB = true
  end

  function editbox_onchar(e, c)

    local oetxt = e.text
    if c == 0x6C656674 then -- left arrow
      if mouse.shift then
        if e.caret > 0 then e.caret=e.caret-1 e.sel=e.sel+1 end
      else
        if e.caret > 0 then e.caret=e.caret-1 end
        e.sel = 0
      end
    elseif c == 0x72676874 then -- right arrow
      if mouse.shift then
        if e.caret < string.len(e.text) then e.caret=e.caret+1 e.sel=e.sel-1 end
      else
        if e.caret < string.len(e.text) then e.caret=e.caret+1 end
        e.sel = 0
      end
    elseif c == 6647396 then -- end
      if mouse.shift then
        e.sel = -(string.len(e.text)-e.caret)
      else
        e.sel = 0
      end
      e.caret = string.len(e.text)
    elseif c == 1752132965 then --home
      if mouse.shift then
        e.sel = e.caret
      else
        e.sel = 0
      end
      e.caret = 0
    elseif c == 8 then -- backspace
      if e.sel ~= 0 then
        local sc,ec=e.caret,e.caret+e.sel
        if sc > ec then sc,ec=ec,sc end
        e.text=string.sub(e.text,1,sc)..string.sub(e.text,ec+1)
        e.caret=sc
        e.sel=0
      else
        if e.caret > 0 then
          e.text=string.sub(e.text,1,e.caret-1)..string.sub(e.text,e.caret+1)
          e.caret=e.caret-1
        end
      end

    elseif c == 13 then
      EB_Enter = true
    elseif c >= 32 and c <= 125 and string.len(e.text) < e.maxlen then
      if e.sel ~= 0 then
        local sc,ec=e.caret,e.caret+e.sel
        if sc > ec then sc,ec=ec,sc end
        e.text=string.sub(e.text,1,sc)..string.sub(e.text,ec+1)
        e.caret=sc
        e.sel=0
      end
      e.text=string.format("%s%c%s",
      string.sub(e.text,1,e.caret), c, string.sub(e.text,e.caret+1))
      e.caret=e.caret+1
    elseif c == 22 then
      local txt = reaper.CF_GetClipboard()
      if txt then
        e.text=string.format("%s%s%s",
        string.sub(e.text,1,e.caret), txt, string.sub(e.text,e.caret+1))
        e.caret=e.caret+string.len(txt)
      end
    elseif c == 3 then
      if e.sel ~= 0 then
        local sc,ec=e.caret,e.caret+e.sel
        if sc > ec then sc,ec=ec,sc end
        local txt = string.sub(e.text, sc, ec)
        if txt then
          reaper.CF_SetClipboard(txt)
        end
      end
    end
    
    if e.text ~= oetxt and e.liveupdate then
      e.liveupdate(e.text)
    end
  end

  function mb_onchar(c)

    if c == 13 then
      MB_Enter = true
    end

  end

  ---- generic mouse handling ----

  mouse={}

  function OnMouseDown()
    editbox_onmousedown(editbox)
    mouse.down=true ; mouse.capcnt=0
    mouse.ox,mouse.oy=gfx.mouse_x,gfx.mouse_y
  end

  function OnMouseDoubleClick()
    if editbox.hasfocus then editbox_onmousedoubleclick(editbox) end
  end

  function OnMouseMove()
    if editbox.hasfocus then editbox_onmousemove(editbox) end
    mouse.lx,mouse.ly=gfx.mouse_x,gfx.mouse_y
    mouse.capcnt=mouse.capcnt+1
  end

  function OnMouseUp()
    mouse.down=false
    lvar.editbox_mouseLB = nil
    mouse.uptime=os.clock()
  end

  --gfx.setfont(1,"verdana",editbox.fontsz)

  --reaper.defer(runloop)

  function CheckTrackExists(s)
    if strips[s].track.tracknum == -1 then return true end

    local found = false
    local trx = GetTrack(strips[s].track.tracknum)
    if trx then
      if strips[s].track.guid ~= GetTrackGUID(trx) then
        --Find track and update tracknum
        for i = -1, reaper.CountTracks(0) do
          local tr = GetTrack(i)
          if tr ~= nil then
            if strips[s].track.guid == GetTrackGUID(tr) then
              --found
              found = true
              strips[s].track.tracknum = i
              break
            end
          end
        end
      else
        found = true
      end
    else
      for i = 0, reaper.CountTracks(0) do
        local tr = GetTrack(i)
        if tr ~= nil then
          if strips[s].track.guid == GetTrackGUID(tr) then
            --found
            found = true
            strips[s].track.tracknum = i
            break
          end
        end
      end
      --PopulateTracks()
    end
    return found
  end


  function GPES(key, nilallowed)
    if nilallowed == nil then nilallowed = false end

    local _, val = reaper.GetProjExtState(0,lvar.SCRIPT,key)
    if nilallowed then
      if val == '' then
        val = nil
      end
    end
    return val
  end

  function GES(key, nilallowed)
    if nilallowed == nil then nilallowed = false end

    local val = reaper.GetExtState(lvar.SCRIPT,key)
    if nilallowed then
      if val == '' then
        val = nil
      end
    end
    return val
  end

  function readln(ln,nilallowed)
    local v = string.match(ln,'[.-](.*)')
    lsd_ln = lsd_ln + 1
    if nilallowed and v == '' then
      return nil
    else
      return v
    end
  end

  function decipher(ln)
    return string.match(ln,'%[(.-)%](.*)')
  end

  function LoadStripData(s, ss, data)

    t = reaper.time_precise()
    local pfx = ''

    if data == nil then
      local load_path
      local fn = GPES('strips_datafile_'..string.format("%03d",s))

      if settings_savedatainprojectfolder == true then
        load_path=reaper.GetProjectPath('')..'/'
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=paths.projsave_path
        end
      else
        load_path=paths.projsave_path
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=reaper.GetProjectPath('')..'/'
        end
      end

      local ffn=load_path..fn
      if reaper.file_exists(ffn) ~= true then
        DBG('Missing file: '..ffn)
        return 0
      end

      local file

      local ccnt

      data = {}
      for line in io.lines(ffn) do
        local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
          data[idx] = val
        end
      end
    else
      pfx = 'strip_s'..ss..'_'
    end

    strips[ss] = {}

    strips[ss].page = tonumber(zn(data[pfx..'page'],1))
    strips[ss].track = {
                       name = data[pfx..'track_name'],
                       guid = data[pfx..'track_guid'],
                       tracknum = tonumber(data[pfx..'track_num']),
                       strip = tonumber(data[pfx..'track_strip'])
                      }

    for p = 1, lvar.maxpage do

      local key = pfx..'p'..p..'_'

      strips[ss][p] = LoadStripDataX(key, data)
      IndexExtIdentifiers(ss, p)
      
    end
    if pfx ~= '' and data[pfx..'fadercnt'] then
      strips[ss].faders = LoadFaders(data,pfx,true)
    end


  end

  function LoadStripDataX(pfx, data)

    if pfx == nil then pfx = '' end
    local key = pfx

    local strip = { lmode = tonumber(data[key..'lmode']) or 0,
                    surface_x = tonumber(data[key..'surface_x']) or 0,
                    surface_y = tonumber(data[key..'surface_y']) or 0,
                    controls = {},
                    graphics = {},
                    nchan = tonumber(data[key..'NCHAN'] or 2),
                    fxcnt = tonumber(zn(data[key..'fxcnt'])),
                    fxstr = zn(data[key..'fxstr']),
                    trn = tonumber(zn(data[key..'trn'])),
                    showpop = tobool(data[key..'showpop']) or false,
                    quickload = tonumber(data[key..'quickload']) or 0,
                   }
    
    local ccnt = tonumber(data[key..'controls_count'])
    local gcnt = tonumber(data[key..'graphics_count'])
    local pcnt = tonumber(data[key..'pop_count'])

    local rcms = false

    if pcnt and pcnt > 0 then
      strip.pop = {}
      strip.popidx = {}
      local ii = 1
      for i = 1, pcnt do
        local key = pfx..'pop_'..i..'_'
        local swid = tonumber(zn(data[key..'swid']))
        if swid then
          strip.pop[ii] = {swid = swid,
                          x = tonumber(zn(data[key..'x'])),
                          y = tonumber(zn(data[key..'y']))
                         }
          strip.popidx[strip.pop[ii].swid] = ii
          ii = ii + 1
        end
      end
    end

    if ccnt and ccnt > 0 then
      for c = 1, ccnt do

        local key = pfx..'c_'..c..'_'
        strip.controls[c] = {
                                    c_id = tonumber(zn(data[key..'cid'],GenID())),
                                    ctlcat = tonumber(zn(data[key..'ctlcat'],0)),
                                    fxname = data[key..'fxname'],
                                    fxguid = data[key..'fxguid'],
                                    fxnum = tonumber(zn(data[key..'fxnum'])),
                                    fxfound = tobool(data[key..'fxfound']),
                                    param = tonumber(data[key..'param']),
                                    param_info = {
                                                  paramname = data[key..'param_info_name'],
                                                  paramnum = tonumber(zn(data[key..'param_info_paramnum'])),
                                                  paramidx = zn(data[key..'param_info_idx']),
                                                  paramstr = zn(data[key..'param_info_str']),
                                                  paramstr2 = zn(data[key..'param_info_str2']),
                                                  paramdestguid = zn(data[key..'param_info_guid']),
                                                  paramdestchan = tonumber(zn(data[key..'param_info_chan'])),
                                                  paramsrcchan = tonumber(zn(data[key..'param_info_srcchan']))
                                                 },
                                    ctltype = tonumber(data[key..'ctltype']),
                                    knob_select = tonumber(data[key..'knob_select']),
                                    ctl_info = {
                                                fn = data[key..'ctl_info_fn'],
                                                frames = tonumber(data[key..'ctl_info_frames']),
                                                imageidx = tonumber(data[key..'ctl_info_imageidx']),
                                                cellh = tonumber(data[key..'ctl_info_cellh'])
                                               },
                                    x = tonumber(data[key..'x']),
                                    y = tonumber(data[key..'y']),
                                    w = tonumber(data[key..'w']),
                                    scale = tonumber(data[key..'scale']),
                                    show_paramname = tobool(data[key..'show_paramname']),
                                    show_paramval = tobool(data[key..'show_paramval']),
                                    ctlname_override = zn(data[key..'ctlname_override'],''),
                                    textcol = data[key..'textcol'],
                                    textcolv = zn(data[key..'textcolv'],data[key..'textcol']),
                                    textoff = tonumber(data[key..'textoff']),
                                    textoffval = tonumber(zn(data[key..'textoffval'],0)),
                                    textoffx = tonumber(zn(data[key..'textoffx'],0)),
                                    textoffvalx = tonumber(zn(data[key..'textoffvalx'],0)),
                                    textsize = tonumber(zn(data[key..'textsize'],0)),
                                    textsizev = tonumber(zn(data[key..'textsizev'],zn(data[key..'textsize'],0))),
                                    font = zn(data[key..'font'],fontname_def),
                                    val = tonumber(data[key..'val']),
                                    dval = zn(data[key..'dval'],''),
                                    mval = tonumber(data[key..'mval']),
                                    enabledefval = tobool(nz(data[key..'enabledefval'],true)),
                                    defval = tonumber(data[key..'defval']),
                                    maxdp = tonumber(zn(data[key..'maxdp'],-1)),
                                    cycledata = {statecnt = 0,{}},
                                    xydata = {x = tonumber(zn(data[key..'xydata_x'],0.5)),
                                              y = tonumber(zn(data[key..'xydata_y'],0.5)),
                                              snapa = tonumber(zn(data[key..'xydata_snapa'],1)),
                                              snapb = tonumber(zn(data[key..'xydata_snapb'],1)),
                                              snapc = tonumber(zn(data[key..'xydata_snapc'],1)),
                                              snapd = tonumber(zn(data[key..'xydata_snapd'],1))},
                                    id = deconvnum(data[key..'id'],true),
                                    grpid = deconvnum(data[key..'grpid'], true),
                                    gfxpage = tonumber(zn(data[key..'gfxpage'],0)),
                                    scalemode = tonumber(zn(data[key..'scalemodex'],8)),
                                    framemode = tonumber(zn(data[key..'framemodex'],1)),
                                    poslock = tobool(zn(data[key..'poslock'],false)),
                                    ctllock = tobool(zn(data[key..'ctllock'])),
                                    horiz = tobool(zn(data[key..'horiz'],false)),
                                    --macrofader = tonumber(zn(data[key..'macrofader'])),
                                    mod = tonumber(zn(data[key..'mod'])),
                                    switchfader = tonumber(zn(data[key..'switchfader'])),
                                    hidden = tobool(zn(data[key..'hidden'],false),true),
                                    switcherid = tonumber(zn(data[key..'switcherid'])),
                                    switcher = tonumber(zn(data[key..'switcher'])),
                                    noss = tobool(zn(data[key..'noss'])),
                                    bypassbg_c = tobool(zn(data[key..'bypassbg_c'])),
                                    bypassbg_n = tobool(zn(data[key..'bypassbg_n'])),
                                    bypassbg_v = tobool(zn(data[key..'bypassbg_v'])),
                                    clickthrough = tobool(zn(data[key..'clickthrough'])),
                                    dnu = tobool(zn(data[key..'dnu'])),
                                    orr = tobool(zn(data[key..'orr'])),
                                    wwtext = tonumber(zn(data[key..'wwtext'])),
                                    limittext = tonumber(zn(data[key..'limittext'])),
                                    textflags = tonumber(zn(data[key..'textflags'])),
                                    ext_identifier = zn(data[key..'externalidentifier']),
                                   }
        --[[if strip.controls[c].switcherid then
        DBG('load switcherid'..strip.controls[c].switcherid)
        end
        if strip.controls[c].switcher then
        DBG('load switcher  '..strip.controls[c].switcher)
        end]]

        strip.controls[c].o_cid = tonumber(zn(data[key..'ocid'])) or strip.controls[c].c_id

        local animatetime = tonumber(zn(data[key..'animatetime']))
        if animatetime then
          if lvar.ctltype_buttons[strip.controls[c].ctltype] then
            strip.controls[c].animatetime = animatetime
            strip.controls[c].animateshape = tonumber(zn(data[key..'animateshape'])) or 1
          end
        end

        if zn(data[key..'monext_sec']) then
          strip.controls[c].monext = {section = zn(data[key..'monext_sec']) or '',
                                      key = zn(data[key..'monext_key']) or '',
                                      range_start = tonumber(zn(data[key..'monext_start'])) or 0,
                                      range_end = tonumber(zn(data[key..'monext_end'])) or 1}
        end

        g_cids[strip.controls[c].c_id] = true
        if strip.controls[c].id then
          g_cids[strip.controls[c].id] = true
        end
        if strip.controls[c].grpid then
          g_cids[strip.controls[c].grpid] = true
        end

        if strip.controls[c].maxdp == nil or (strip.controls[c].maxdp and strip.controls[c].maxdp == '') then
          strip.controls[c].maxdp = -1
        end

        if strip.controls[c].ctlcat == ctlcats.infoctl then
          if strip.controls[c].param == 2 then

            strip.controls[c].infoctl = {}
            strip.controls[c].infoctl.closefx = tobool(zn(data[key..'infoctl_closefx'])) or false
            strip.controls[c].infoctl.positionfx = tobool(zn(data[key..'infoctl_positionfx'])) or false

          end
        end

        if strip.controls[c].ctlcat == ctlcats.macro then
          strip.controls[c].macrotype = tonumber(zn(data[key..'macrotype'],0))
        end

        if strip.controls[c].ctlcat == ctlcats.threshold then
          local thresh = {}
          thresh.thresh_off = tonumber(zn(data[key..'thresh_threshoff'])) or 5
          thresh.thresh_on = tonumber(zn(data[key..'thresh_threshon'])) or 10
          thresh.val_off = tonumber(zn(data[key..'thresh_valoff'])) or 0
          thresh.val_on = tonumber(zn(data[key..'thresh_valon'])) or 1
          thresh.invert = tobool(zn(data[key..'thresh_invert'])) or false

          strip.controls[c].thresh = thresh
        end

        if strip.controls[c].ctlcat == ctlcats.statectl then
          local extname = zn(data[key..'stateinfo_extname'])
          local extkey = zn(data[key..'stateinfo_key'])
          strip.controls[c].stateinfo = {}
          strip.controls[c].stateinfo.extname = extname
          strip.controls[c].stateinfo.key = extkey
          strip.controls[c].stateinfo.min = tonumber(zn(data[key..'stateinfo_min'])) or 0
          strip.controls[c].stateinfo.max = tonumber(zn(data[key..'stateinfo_max'])) or 1
          strip.controls[c].stateinfo.step = tonumber(zn(data[key..'stateinfo_step'])) or 0.1
        elseif strip.controls[c].ctlcat == ctlcats.statectl_str then
          local extname = zn(data[key..'stateinfo_extname'])
          local extkey = zn(data[key..'stateinfo_key'])
          strip.controls[c].stateinfo = {}
          strip.controls[c].stateinfo.extname = extname
          strip.controls[c].stateinfo.key = extkey
        end

        strip.controls[c].xsc = math.floor(strip.controls[c].x + strip.controls[c].w/2 - (strip.controls[c].w*strip.controls[c].scale)/2)
        strip.controls[c].ysc = math.floor(strip.controls[c].y + strip.controls[c].ctl_info.cellh/2 - (strip.controls[c].ctl_info.cellh*strip.controls[c].scale)/2)
        strip.controls[c].wsc = math.floor(strip.controls[c].w*strip.controls[c].scale)
        strip.controls[c].hsc = math.floor(strip.controls[c].ctl_info.cellh*strip.controls[c].scale)

        strip.controls[c].tracknum = tonumber(zn(data[key..'tracknum']))
        strip.controls[c].otracknum = tonumber(zn(data[key..'otracknum']))
        strip.controls[c].trackguid = zn(data[key..'trackguid'])
        strip.controls[c].dvaloffset = tonumber(zn(data[key..'dvaloffset'],0))
        strip.controls[c].minov = tonumber(zn(data[key..'minov']))
        strip.controls[c].maxov = tonumber(zn(data[key..'maxov']))
        strip.controls[c].membtn = {state = tobool(zn(data[key..'memstate'],false)),
                                            mem = tonumber(zn(data[key..'memmem'],0))
                                            }

        strip.controls[c].knobsens = {norm = tonumber(zn(data[key..'knobsens_norm'],settings_defknobsens.norm)),
                                      fine = tonumber(zn(data[key..'knobsens_fine'],settings_defknobsens.fine)),
                                      wheel = tonumber(zn(data[key..'knobsens_wheel'],settings_defknobsens.wheel)),
                                      wheelfine = tonumber(zn(data[key..'knobsens_wheelfine'],settings_defknobsens.wheelfine)),
                                      m_norm = tonumber(zn(data[key..'knobsens_norm_m'],settings_defknobsens.m_norm)),
                                      m_fine = tonumber(zn(data[key..'knobsens_fine_m'],settings_defknobsens.m_fine)),
                                      m_wheel = tonumber(zn(data[key..'knobsens_wheel_m'],settings_defknobsens.m_wheel)),
                                      m_wheelfine = tonumber(zn(data[key..'knobsens_wheelfine_m'],settings_defknobsens.m_wheelfine))}

        local itemguid = zn(data[key..'iteminfo_guid'])
        if itemguid then
          strip.controls[c].val = -1
          strip.controls[c].iteminfo = {}
          strip.controls[c].iteminfo.guid = itemguid
          strip.controls[c].iteminfo.itemno = tonumber(zn(data[key..'iteminfo_itemno']))
          strip.controls[c].iteminfo.tracknum = tonumber(zn(data[key..'iteminfo_tracknum']))
          strip.controls[c].iteminfo.trackguid = zn(data[key..'iteminfo_trackguid'])
          strip.controls[c].iteminfo.numtakes = tonumber(zn(data[key..'iteminfo_numtakes']))
          strip.controls[c].iteminfo.utilfxn = tonumber(zn(data[key..'iteminfo_utilfxn']))
          strip.controls[c].iteminfo.utilguid = tostring(zn(data[key..'iteminfo_utilguid']))
          strip.controls[c].iteminfo.noteoff = (zn(data[key..'iteminfo_noteoff']))

          local maxtakes = tonumber(zn(data[key..'iteminfo_maxtakes']))
          if maxtakes == nil then maxtakes = 511 end
          strip.controls[c].iteminfo.maxtakes = maxtakes
        end

        strip.controls[c].cycledata.statecnt = tonumber(zn(data[key..'cycledata_statecnt'],0))
        strip.controls[c].cycledata.mapptof = tobool(zn(data[key..'cycledata_mapptof'],false))
        strip.controls[c].cycledata.invert = tobool(zn(data[key..'cycledata_invert'],false))
        strip.controls[c].cycledata.draggable = tobool(zn(data[key..'cycledata_draggable'],false))
        strip.controls[c].cycledata.spread = tobool(zn(data[key..'cycledata_spread'],false))
        strip.controls[c].cycledata.pos = tonumber(zn(data[key..'cycledata_pos'],1))
        strip.controls[c].cycledata.posdirty = tobool(zn(data[key..'cycledata_posdirty'],false))
        strip.controls[c].cycledata.val = 0
        if nz(strip.controls[c].cycledata.statecnt,0) > 0 then
          for i = 1, strip.controls[c].cycledata.statecnt do
            local key = pfx..'c_'..c..'_cyc_'..i..'_'

            strip.controls[c].cycledata[i] = {val = tonumber(zn(data[key..'val'],0)),
                                              dispval = zn(data[key..'dispval'],'no disp val'),
                                              dv = zn(data[key..'dispval']),
                                              startval = tonumber(zn(data[key..'startval'])),
                                              nextval = tonumber(zn(data[key..'nextval']))}
            if strip.controls[c].cycledata[i].dv == nil then
              strip.controls[c].cycledata[i].dv = strip.controls[c].cycledata[i].dispval
            end
            local swid = tonumber(zn(data[key..'tsp_swid']))
            if swid then
              strip.controls[c].cycledata.tspactive = true
              strip.controls[c].cycledata[i].tsp = {swid = swid,
                                                    grpid = tonumber(zn(data[key..'tsp_grpid']))}
            end
          end
        end

        local mout = zn(data[key..'midiout_output'])
        --if mout then
          strip.controls[c].midiout = {output = mout}
          strip.controls[c].midiout.mchan = tonumber(zn(data[key..'midiout_mchan'],1))
          strip.controls[c].midiout.msg3 = tonumber(zn(data[key..'midiout_msg3'],0))
          strip.controls[c].midiout.msgtype = tonumber(zn(data[key..'midiout_msgtype'],4))
          strip.controls[c].midiout.osc = zn(data[key..'midiout_osc'])
          strip.controls[c].midiout.vmin = tonumber(zn(data[key..'midiout_vmin'],0))
          strip.controls[c].midiout.vmax = tonumber(zn(data[key..'midiout_vmax'],127))
          strip.controls[c].midiout.focus = tonumber(zn(data[key..'midiout_focus'],1))
          strip.controls[c].midiout.focus_wintit = zn(data[key..'midiout_focus_wintit'])
          strip.controls[c].midiout.focus_winexact = tobool(zn(data[key..'midiout_focus_winexact'],false))
          strip.controls[c].midiout.updategfx = tobool(zn(data[key..'midiout_updategfx'],false))
          strip.controls[c].midiout.onmu = tobool(zn(data[key..'midiout_onmu'],false))
        --end

        local rcmcnt = tonumber(data[key..'rcmdata_cnt'])
        if rcmcnt and rcmcnt > 0 then
          strip.controls[c].rcmdata = {}
          for r = 1, rcmcnt do
            local key = pfx..'c_'..c..'_rcm_'..r..'_'
            strip.controls[c].rcmdata[r] = {}
            strip.controls[c].rcmdata[r].name = zn(data[key..'name'])
            strip.controls[c].rcmdata[r].msb = tonumber(data[key..'msb'])
            strip.controls[c].rcmdata[r].lsb = tonumber(data[key..'lsb'])
            strip.controls[c].rcmdata[r].prog = tonumber(data[key..'prog'])
            strip.controls[c].rcmdata[r].nebfn = zn(data[key..'nebfn'])
          end
        end

        local rcmrefresh_setvals = tobool(zn(data[key..'rcmrefresh_setvals']))
        local rcmrefresh_guid = data[key..'rcmrefresh_guid']
        local rcmrefresh_delay = tonumber(data[key..'rcmrefresh_delay'])
        if rcmrefresh_guid or rcmrefresh_delay or rcmrefresh_setvals then
          strip.controls[c].rcmrefresh = {guid = rcmrefresh_guid,
                                          delay = rcmrefresh_delay,
                                          setvals = rcmrefresh_setvals}
        end

        local afxcnt = tonumber(data[key..'addfx_cnt'])
        if afxcnt and afxcnt > 0 then
          strip.controls[c].addfx = {}
          for afx = 1, afxcnt do
            local  key = pfx..'c_'..c..'_addfx_'..afx..'_'
            strip.controls[c].addfx[afx] = {}
            strip.controls[c].addfx[afx].trn = tonumber(data[key..'trn'])
            strip.controls[c].addfx[afx].trguid = zn(data[key..'trguid'])
            strip.controls[c].addfx[afx].fxnum = tonumber(data[key..'fxnum'])
            strip.controls[c].addfx[afx].guid = zn(data[key..'guid'])
          end
        end

        local gauge = data[key..'gauge']
        if gauge then
          strip.controls[c].gauge = {}
          strip.controls[c].gauge.type = tonumber(zn(data[key..'gauge_type'],1))
          strip.controls[c].gauge.x_offs = tonumber(zn(data[key..'gauge_x_offs']))
          strip.controls[c].gauge.y_offs = tonumber(zn(data[key..'gauge_y_offs']))
          strip.controls[c].gauge.radius = tonumber(zn(data[key..'gauge_radius']))
          strip.controls[c].gauge.arclen = tonumber(zn(data[key..'gauge_arclen']))
          strip.controls[c].gauge.rotation = tonumber(zn(data[key..'gauge_rotation']))
          strip.controls[c].gauge.ticks = tonumber(zn(data[key..'gauge_ticks']))
          strip.controls[c].gauge.tick_size = tonumber(zn(data[key..'gauge_tick_size']))
          strip.controls[c].gauge.tick_offs = tonumber(zn(data[key..'gauge_tick_offs']))
          strip.controls[c].gauge.val_freq = tonumber(zn(data[key..'gauge_val_freq']))
          strip.controls[c].gauge.col_tick = (zn(data[key..'gauge_col_tick']))
          strip.controls[c].gauge.col_arc = (zn(data[key..'gauge_col_arc']))
          strip.controls[c].gauge.col_val = (zn(data[key..'gauge_col_val']))
          strip.controls[c].gauge.show_arc = tobool(zn(data[key..'gauge_show_arc']))
          strip.controls[c].gauge.show_tick = tobool(zn(data[key..'gauge_show_tick']))
          strip.controls[c].gauge.tick_shape = tonumber(zn(data[key..'gauge_tick_shape']))
          if not strip.controls[c].gauge.tick_shape then
            if strip.controls[c].gauge.show_tick then
              strip.controls[c].gauge.tick_shape = 1
            else
              strip.controls[c].gauge.tick_shape = 0
            end
          end
          strip.controls[c].gauge.show_val = tobool(zn(data[key..'gauge_show_val']))
          strip.controls[c].gauge.val = 0
          strip.controls[c].gauge.dval = ''
          strip.controls[c].gauge.vals = {}
          strip.controls[c].gauge.val_dp = tonumber(zn(data[key..'gauge_val_dp']))
          strip.controls[c].gauge.font = (zn(data[key..'gauge_font'],fontname_def))
          strip.controls[c].gauge.fontsz = tonumber(zn(data[key..'gauge_fontsz']))
          strip.controls[c].gauge.spread = tobool(zn(data[key..'gauge_spread']))
          strip.controls[c].gauge.mapptof = tobool(zn(data[key..'gauge_mapptof']))
          strip.controls[c].gauge.numonly = tobool(zn(data[key..'gauge_numonly']))
          strip.controls[c].gauge.abbrev = tobool(zn(data[key..'gauge_abbrev'],false))
          strip.controls[c].gauge.vals = {}

          local gcnt = tonumber(zn(data[key..'gauge_valcnt']))
          if gcnt and gcnt > 0 then
            for gv = 1, gcnt do
              local key = pfx..'c_'..c..'_gaugevals_'..gv..'_'
              strip.controls[c].gauge.vals[gv] = {}
              strip.controls[c].gauge.vals[gv].val = tonumber(zn(data[key..'val'],0))
              strip.controls[c].gauge.vals[gv].dval = zn(data[key..'dval'],'')
              strip.controls[c].gauge.vals[gv].dover = zn(data[key..'dover'],'')
              strip.controls[c].gauge.vals[gv].nudge = zn(data[key..'nudge'],0)
            end

          end
        end

        local mcnt = tonumber(zn(data[key..'macroctl_cnt'],0))
        if mcnt > 0 then
          strip.controls[c].macroctl = {}
          strip.controls[c].macromon = tonumber(zn(data[key..'macromon']))
          for mc = 1, mcnt do
            local key = pfx..'c_'..c..'_mc_'..mc..'_'
            strip.controls[c].macroctl[mc] = {c_id = tonumber(zn(data[key..'c_id'])),
                                                      ctl = tonumber(zn(data[key..'ctl'])),
                                                      A_val = tonumber(zn(data[key..'A'],0)),
                                                      B_val = tonumber(zn(data[key..'B'],0)),
                                                      shape = tonumber(zn(data[key..'shape'],0)),
                                                      mute = tobool(zn(data[key..'mute'],false)),
                                                      bi = tobool(zn(data[key..'bi'],false)),
                                                      inv = tobool(zn(data[key..'inv'],false)),
                                                      relative = tobool(zn(data[key..'rel'],false))}
          end
        end

        local randomsst = tonumber(zn(data[key..'rnd_sst']))
        if randomsst then

          local key = pfx..'c_'..c..'_rnd_'

          strip.controls[c].random = {}
          strip.controls[c].random.sst = randomsst
          strip.controls[c].random.parent_cid = tonumber(zn(data[key..'par_c_id']))
          strip.controls[c].random.parent = tonumber(zn(data[key..'par_ctl']))
          strip.controls[c].random.snapshotsonly = tobool(zn(data[key..'sso'],false))
          strip.controls[c].random.useadv = tobool(zn(data[key..'ua'],false))

          strip.controls[c].random.ctls = {}
          strip.controls[c].random.linkgrps = {}

          local ccnt = tonumber(zn(data[key..'ccnt'],0))
          if ccnt > 0 then

            local lgs = {}

            for cc = 1, ccnt do
              local key = pfx..'c_'..c..'_rnd_ctls_'..cc..'_'
              strip.controls[c].random.ctls[cc] = {}
              strip.controls[c].random.ctls[cc].c_id = tonumber(zn(data[key..'c_id']))
              strip.controls[c].random.ctls[cc].ctl = tonumber(zn(data[key..'ctl']))
              strip.controls[c].random.ctls[cc].min = tonumber(zn(data[key..'min']))
              strip.controls[c].random.ctls[cc].max = tonumber(zn(data[key..'max']))
              strip.controls[c].random.ctls[cc].linkgrp = tonumber(zn(data[key..'linkgrp']))
              strip.controls[c].random.ctls[cc].rprob = tonumber(zn(data[key..'rprob'],1))
              strip.controls[c].random.ctls[cc].bias = tonumber(zn(data[key..'bias'],0.5))
              strip.controls[c].random.ctls[cc].amount = tonumber(zn(data[key..'amount']))
              strip.controls[c].random.ctls[cc].inverted = tobool(zn(data[key..'inverted'],false))
              strip.controls[c].random.ctls[cc].wild = tonumber(zn(data[key..'wild'],0))
              strip.controls[c].random.ctls[cc].snap = tobool(zn(data[key..'snap'],false))

              if strip.controls[c].random.ctls[cc].linkgrp then
                lgs[#lgs+1] = strip.controls[c].random.ctls[cc].linkgrp
              end
            end

            if #lgs > 0 then
              for l = 1, #lgs do
                local lg = lgs[l]
                local key = pfx..'c_'..c..'_rnd_lgs_'..lg..'_'
                strip.controls[c].random.linkgrps[lg] = {}
                strip.controls[c].random.linkgrps[lg].type = tonumber(zn(data[key..'type'],1))
                strip.controls[c].random.linkgrps[lg].X = tonumber(zn(data[key..'X'],1/128))
                strip.controls[c].random.linkgrps[lg].snap = tobool(zn(data[key..'snap'],false))
              end
            end
          end
        end

        local bcnt = tonumber(zn(data[key..'eqband_cnt'],0))
        if bcnt > 0 then
          strip.controls[c].eqbands = {}

          for bc = 1, bcnt do
            local key = pfx..'c_'..c..'_eqband_'..bc..'_'
            strip.controls[c].eqbands[bc] = {posmin = tonumber(zn(data[key..'posmin'])),
                                                      posmax = tonumber(zn(data[key..'posmax'])),
                                                      gmin = tonumber(zn(data[key..'gmin'],0)),
                                                      gmax = tonumber(zn(data[key..'gmax'],1)),
                                                      col = zn(data[key..'col']),
                                                      fxnum = tonumber(zn(data[key..'fxnum'])),
                                                      fxguid = zn(data[key..'fxguid']),
                                                      fxname = zn(data[key..'fxname']),
                                                      freq_param = tonumber(zn(data[key..'freq_param'])),
                                                      freq_param_name = zn(data[key..'freq_param_name']),
                                                      gain_param = tonumber(zn(data[key..'gain_param'])),
                                                      gain_param_name = zn(data[key..'gain_param_name']),
                                                      q_param = tonumber(zn(data[key..'q_param'])),
                                                      q_param_name = zn(data[key..'q_param_name']),
                                                      bypass_param = tonumber(zn(data[key..'bypass_param'])),
                                                      bypass_param_name = zn(data[key..'bypass_param_name']),
                                                      c1_param = tonumber(zn(data[key..'c1_param'])),
                                                      c1_param_name = zn(data[key..'c1_param_name']),
                                                      c2_param = tonumber(zn(data[key..'c2_param'])),
                                                      c2_param_name = zn(data[key..'c2_param_name']),
                                                      c3_param = tonumber(zn(data[key..'c3_param'])),
                                                      c3_param_name = zn(data[key..'c3_param_name']),
                                                      c4_param = tonumber(zn(data[key..'c4_param'])),
                                                      c4_param_name = zn(data[key..'c4_param_name']),
                                                      c5_param = tonumber(zn(data[key..'c5_param'])),
                                                      c5_param_name = zn(data[key..'c5_param_name']),
                                                      freq_val = tonumber(zn(data[key..'freq_val'])),
                                                      gain_val = tonumber(zn(data[key..'gain_val'])),
                                                      q_val = tonumber(zn(data[key..'q_val'])),
                                                      c1_val = tonumber(zn(data[key..'c1_val'])),
                                                      c2_val = tonumber(zn(data[key..'c2_val'])),
                                                      c3_val = tonumber(zn(data[key..'c3_val'])),
                                                      c4_val = tonumber(zn(data[key..'c4_val'])),
                                                      c5_val = tonumber(zn(data[key..'c5_val'])),
                                                      freq_min = tonumber(zn(data[key..'freq_min'])),
                                                      freq_max = tonumber(zn(data[key..'freq_max'])),
                                                      gain_min = tonumber(zn(data[key..'gain_min'])),
                                                      gain_max = tonumber(zn(data[key..'gain_max'])),
                                                      bandtype = zn(data[key..'bandtype']),
                                                      bandname = zn(data[key..'bandname']),
                                                      khz = tobool(zn(data[key..'khz'],false)),
                                                      gain_inv = tobool(zn(data[key..'gaininv'],false)),
                                                      q_inv = tobool(zn(data[key..'qinv'],false)),
                                                      freq_def = tonumber(zn(data[key..'freq_def'])),
                                                      gain_def = tonumber(zn(data[key..'gain_def'])),
                                                      q_def = tonumber(zn(data[key..'q_def'])),
                                                      c1_def = tonumber(zn(data[key..'c1_def'])),
                                                      c2_def = tonumber(zn(data[key..'c2_def'])),
                                                      c3_def = tonumber(zn(data[key..'c3_def'])),
                                                      c4_def = tonumber(zn(data[key..'c4_def'])),
                                                      c5_def = tonumber(zn(data[key..'c5_def'])),
                                                      }
            local lcnt = tonumber(zn(data[key..'lookmap_cnt'],0))
            if lcnt > 0 then
              strip.controls[c].eqbands[bc].lookmap = {}
              for lc = 1, lcnt do
                local key = pfx..'c_'..c..'_eqband_'..bc..'_lm_'..lc..'_'
                strip.controls[c].eqbands[bc].lookmap[lc] = {pix = tonumber(zn(data[key..'pix'])),
                                                                     hz = tonumber(zn(data[key..'hz']))}
              end

            end

            local lcnt = tonumber(zn(data[key..'gmap_cnt'],0))
            if lcnt > 0 then
              strip.controls[c].eqbands[bc].gmap = {}
              for lc = 1, lcnt do
                local key = pfx..'c_'..c..'_eqband_'..bc..'_gm_'..lc..'_'
                strip.controls[c].eqbands[bc].gmap[lc] = {pix = tonumber(zn(data[key..'pix'])),
                                                                   db = tonumber(zn(data[key..'db']))}
              end

            end
          end
          --strip.controls[c].eqgraph = tonumber(zn(data[key..'eqgraph']))
        end

        local key = pfx..'c_'..c..'_'
        if tobool(zn(data[key..'ecg_graph'],false)) == true then
          strip.controls[c].eqgraph = {posmin = tonumber(zn(data[key..'ecg_posmin'])),
                                               posmax = tonumber(zn(data[key..'ecg_posmax'])),
                                               gmin = tonumber(zn(data[key..'ecg_gmin'],0)),
                                               gmax = tonumber(zn(data[key..'ecg_gmax'],1)),
                                               }

          local lcnt = tonumber(zn(data[key..'ecg_lookmap_cnt'],0))
          if lcnt > 0 then
            strip.controls[c].eqgraph.lookmap = {}
            for lc = 1, lcnt do
              local key = pfx..'c_'..c..'_ecg_lm_'..lc..'_'
              strip.controls[c].eqgraph.lookmap[lc] = {pix = tonumber(zn(data[key..'pix'])),
                                                       hz = tonumber(zn(data[key..'hz']))}
            end

          end

          local key = pfx..'c_'..c..'_'
          local lcnt = tonumber(zn(data[key..'ecg_gmap_cnt'],0))
          if lcnt > 0 then
            strip.controls[c].eqgraph.gmap = {}
            for lc = 1, lcnt do
              local key = pfx..'c_'..c..'_ecg_gm_'..lc..'_'
              strip.controls[c].eqgraph.gmap[lc] = {pix = tonumber(zn(data[key..'pix'])),
                                                            db = tonumber(zn(data[key..'db']))}
            end

          end

        end


        local key = pfx..'c_'..c..'_rs5k_'
        if data[key..'samplefolder'] then
          strip.controls[c].rsdata = {}
          strip.controls[c].rsdata.samplefolder = zn(data[key..'samplefolder'])
          strip.controls[c].rsdata.recurse = tobool(zn(data[key..'recurse']))
          strip.controls[c].rsdata.samples = {}
          strip.controls[c].rsdata.samplesidx = {}
          local scnt = zn(data[key..'samplecnt'],0)

          for sm = 1, scnt do
            local key = pfx..'c_'..c..'_rs5k_sample_'..sm..'_'
            local fol = zn(data[key..'fol'])
            local fn = zn(data[key..'fn'])
            local fav = tobool(zn(data[key..'fav']))
            if fn then
              strip.controls[c].rsdata.samples[sm] = {fol = fol, fn = fn, fav = fav}
              strip.controls[c].rsdata.samplesidx[fol..fn] = sm
            else
              strip.controls[c].rsdata.samples[sm] = {fol = fol, fn = nil, fav = nil}
            end
          end
        else
          strip.controls[c].rsdata = {}
          strip.controls[c].rsdata.samples = {}
          strip.controls[c].rsdata.samplesidx = {}
        end

        local key = pfx..'c_'..c..'_adjust_'
        local act = tonumber(data[key..'active']) or 0
        if act == 1 then
          strip.controls[c].adjust_active = 1
          strip.controls[c].adjust = {}
          strip.controls[c].adjust.bright = tonumber(data[key..'bright']) or 255
          strip.controls[c].adjust.contrast = tonumber(data[key..'contrast']) or 255
          strip.controls[c].adjust.r = tonumber(data[key..'r']) or 255
          strip.controls[c].adjust.g = tonumber(data[key..'g']) or 255
          strip.controls[c].adjust.b = tonumber(data[key..'b']) or 255
        else
          strip.controls[c].adjust_active = 0        
        end

        --load control images - reshuffled to ensure no wasted slots between sessions
        if pfx ~= '' then
          local iidx
          local knob_sel = lvar.ctlfiles_idx[strip.controls[c].ctl_info.fn]
          if not knob_sel then
            knob_sel = -1
          end
          --[[for k = 0, #ctl_files do
            if ctl_files[k].fn == strip.controls[c].ctl_info.fn then
              knob_sel = k
              break
            end
          end]]
          if knob_sel ~= -1 then
            strip.controls[c].knob_select = knob_sel

            if ctl_files[knob_sel].imageidx == nil then
              image_count = F_limit(image_count + 1,0,image_max)
              gfx.loadimg(image_count, paths.controls_path..ctl_files[knob_sel].fn)
              iidx = image_count

              strip.controls[c].ctl_info.imageidx = iidx
              ctl_files[knob_sel].imageidx = iidx
            else
              iidx = ctl_files[knob_sel].imageidx
              strip.controls[c].ctl_info.imageidx = iidx
            end
          else
            --missing
            --DBG('missing '..strip.controls[c].ctl_info.fn)
            strip.controls[c].knob_select = -1
            strip.controls[c].ctl_info.imageidx = 1020
          end
        end

        if strip.controls[c].ctlcat == ctlcats.rcm_switch then
          rcms = true
        end

      end

      if rcms == true then
        RCM_Neb_UpdateProgIDs(strip.controls,false)
      end

    end

    if gcnt and gcnt > 0 then

      for g = 1, gcnt do

        local key = pfx..'g_'..g..'_'

        strip.graphics[g] = {       g_id = tonumber(zn(data[key..'gid'],GenID())),
                                    fn = data[key..'fn'],
                                    imageidx = tonumber(data[key..'imageidx']),
                                    x = tonumber(data[key..'x']),
                                    y = tonumber(data[key..'y']),
                                    w = tonumber(data[key..'w']),
                                    h = tonumber(data[key..'h']),
                                    scale = tonumber(data[key..'scale']),
                                    id = deconvnum(data[key..'id']),
                                    grpid = deconvnum(data[key..'grpid']),
                                    gfxpage = tonumber(zn(data[key..'gfxpage'],0)),
                                    gfxtype = tonumber(zn(data[key..'gfxtype'],lvar.gfxtype.img)),
                                    font = {idx = tonumber(zn(data[key..'font_idx'])),
                                            name = zn(data[key..'font_name']),
                                            size = tonumber(zn(data[key..'font_size'])),
                                            bold = tobool(zn(data[key..'font_bold'])),
                                            italics = tobool(zn(data[key..'font_italics'])),
                                            underline = tobool(zn(data[key..'font_underline'])),
                                            vertical = tobool(zn(data[key..'font_vertical'])),
                                            shadow = tobool(zn(data[key..'font_shadow'],true)),
                                            shadow_x = tonumber(zn(data[key..'font_shadowx'],1)),
                                            shadow_y = tonumber(zn(data[key..'font_shadowy'],1)),
                                            shadow_a = tonumber(zn(data[key..'font_shadowa'],0.6))
                                            },
                                    text = zn(data[key..'text']),
                                    text_col = zn(data[key..'text_col']),
                                    poslock = tobool(zn(data[key..'poslock'],false)),
                                    switcher = tonumber(zn(data[key..'switcher'])),
                                    bright = tonumber(zn(data[key..'bright'],0.5)),
                                    contr = tonumber(zn(data[key..'contr'],0.5)),
                                    rmult = tonumber(zn(data[key..'rmult'],0.5)),
                                    gmult = tonumber(zn(data[key..'gmult'],0.5)),
                                    bmult = tonumber(zn(data[key..'bmult'],0.5)),
                                    alpha = tonumber(zn(data[key..'alpha'],1)),
                                    stretchmode = tonumber(zn(data[key..'stretchmode'],1)),
                                    edgesz = tonumber(zn(data[key..'edgesz'],8)),
                                    shadow = tobool(zn(data[key..'gfx_shadow'],false)),
                                   }
        strip.graphics[g].stretchw = tonumber(zn(data[key..'stretchw'],strip.graphics[g].w))
        strip.graphics[g].stretchh = tonumber(zn(data[key..'stretchh'],strip.graphics[g].h))

        --[[if strip.graphics[g].switcher then
        DBG('load gfx switcher  '..strip.graphics[g].switcher)
        end]]

        --load graphics images
        if pfx ~= '' then
          if strip.graphics[g].gfxtype == lvar.gfxtype.img then

            local iidx = LoadGraphics(strip.graphics[g].fn)
            if iidx then
              strip.graphics[g].imageidx = iidx
            end

          end
        end

      end
    end
    return strip
  end

  function LoadGraphics(fn)

    local iidx
    local gfx_sel = lvar.gfxfiles_idx[fn]
    --[[for k = 0, #graphics_files do
      if graphics_files[k] and graphics_files[k].fn == fn then
        gfx_sel = k
        break
      end
    end]]
    if gfx_sel then

      if graphics_files[gfx_sel].imageidx == nil then
        image_count = F_limit(image_count + 1,0,image_max)
        local fol = ''
        if graphics_files[gfx_sel].fol and graphics_files[gfx_sel].fol ~= 'GENERAL' then
          fol = graphics_files[gfx_sel].fol..'/'
        end
        gfx.loadimg(image_count, paths.graphics_path..fol..graphics_files[gfx_sel].fn)
        iidx = image_count

        graphics_files[gfx_sel].imageidx = iidx

      else
        iidx = graphics_files[gfx_sel].imageidx
      end
    else
      --missing
      iidx = 1020
    end
    return iidx

  end

  function LoadSnapData(s, data)

    local pfx = ''

    if data == nil then
      local load_path
      local fn = GPES('snaps_datafile_'..string.format("%03d",s))

      if settings_savedatainprojectfolder == true then
        load_path=reaper.GetProjectPath('')..'/'
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=paths.projsave_path
        end
      else
        load_path=paths.projsave_path
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=reaper.GetProjectPath('')..'/'
        end
      end

      local ffn=load_path..fn
      if reaper.file_exists(ffn) ~= true then
        DBG('Missing file: '..ffn)
        return 0
      end

      local file

      t = reaper.time_precise()
      local ccnt

      data = {}
      for line in io.lines(ffn) do
        local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
          data[idx] = val
        end
      end
    else
      pfx = 'snap_s'..s..'_'
    end

    snapshots[s] = {}

    for p = 1, lvar.maxpage do

      local key = pfx..'p'..p..'_'
      snapshots[s][p] = LoadSnapDataX(key, data)

    end


  end

  function LoadSnapDataX(pfx, data)

    if pfx == nil then pfx = '' end
    --local key = pfx

    local snaps = {}

    local key = pfx
    local sstcnt = tonumber(zn(data[key..'sstype_count'],0))

    if sstcnt > 0 then

      for sst = 1, sstcnt do

        if sst == 1 then
          local key = pfx..'sst_'..sst..'_'
          snaps[sst] = {}
          snaps[sst].morph_time = tonumber(zn(data[key..'morph_time'],0))
          snaps[sst].morph_sync = tobool(zn(data[key..'morph_sync'],false))
          snaps[sst].morph_syncv = tonumber(zn(data[key..'morph_syncv'],14))
          snaps[sst].morph_scale = tonumber(zn(data[key..'morph_scale'],1))
          snaps[sst].morph_time_fader = tonumber(zn(data[key..'morph_time_fader']))
          snaps[sst].morph_loop = tonumber(zn(data[key..'morph_loop'],1))
          snaps[sst].capturefaders = tobool(zn(data[key..'capturefaders'],false))
          snaps[sst].capturemods = tobool(zn(data[key..'capturemods'],false))
          snaps[sst].ignorevals = tobool(zn(data[key..'ignorevals'],false))

          local sscnt = tonumber(zn(data[key..'ss_count'],0))
          if sscnt > 0 then

            for ss = 1, sscnt do
              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local dcnt = tonumber(data[key..'data_count'])
              snaps[sst][ss] = {name = data[key..'name'],
                                data = {}}
              for d = 1, dcnt do

                local key = pfx..'sst_'..sst..'_ss_'..ss..'_d_'..d..'_'

                snaps[sst][ss].data[d] = {c_id = tonumber(data[key..'cid']),
                                           ctl = tonumber(data[key..'ctl']),
                                           val = tonumber(data[key..'val']),
                                           dval = tonumber(zn(data[key..'dval']))}

                local mf = tonumber(data[key..'mf'])
                snaps[sst][ss].data[d].mfset = tobool(zn(data[key..'mfset']))
                if mf then
                  snaps[sst][ss].data[d].mf = mf
                  snaps[sst][ss].data[d].mfdata = {targettype = tonumber(data[key..'mfdata_targettype']),
                                                   strip = tonumber(data[key..'mfdata_strip']),
                                                   page = tonumber(data[key..'mfdata_page']),
                                                   ctl = tonumber(data[key..'mfdata_ctl']),
                                                   c_id = tonumber(data[key..'mfdata_c_id'])}
                end
              end

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local modcnt = tonumber(zn(data[key..'modcnt']))

              if modcnt and modcnt > 0 then

                snaps[sst][ss].moddata = {}
                snaps[sst][ss].modset = true

                for m = 1, modcnt do

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_'

                  snaps[sst][ss].moddata[m] = {}
                  snaps[sst][ss].moddata[m].active = tobool(zn(data[key..'active']))
                  snaps[sst][ss].moddata[m].steps = tonumber(zn(data[key..'steps']))
                  snaps[sst][ss].moddata[m].stepsmult = tonumber(zn(data[key..'stepsmult'],1))
                  snaps[sst][ss].moddata[m].div = tonumber(zn(data[key..'div'],4))
                  snaps[sst][ss].moddata[m].offset = tonumber(zn(data[key..'offset'],0.5))
                  snaps[sst][ss].moddata[m].min = tonumber(zn(data[key..'min'],0))
                  snaps[sst][ss].moddata[m].max = tonumber(zn(data[key..'max'],1))
                  snaps[sst][ss].moddata[m].mode = tonumber(zn(data[key..'mode'],1))
                  snaps[sst][ss].moddata[m].interpolate = tobool(zn(data[key..'interpolate']))
                  snaps[sst][ss].moddata[m].syncv = tonumber(zn(data[key..'syncv']))
                  snaps[sst][ss].moddata[m].sync = tobool(zn(data[key..'sync']))
                  local targetcnt = tonumber(zn(data[key..'target_cnt']))

                  snaps[sst][ss].moddata[m].targets = {}
                  snaps[sst][ss].moddata[m].data = {}
                  if targetcnt > 0 then
                    for t = 1, targetcnt do
                      local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_target_'..t..'_'
                      snaps[sst][ss].moddata[m].targets[t] = {targettype = tonumber(zn(data[key..'targettype'],1)),
                                                              strip = tonumber(zn(data[key..'strip'])),
                                                              page = tonumber(zn(data[key..'page'])),
                                                              ctl = tonumber(zn(data[key..'ctl'])),
                                                              c_id = tonumber(zn(data[key..'c_id']))
                                                              }
                    end
                  end

                  for d = 1, snaps[sst][ss].moddata[m].steps do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_data_'..d..'_'
                    snaps[sst][ss].moddata[m].data[d] = tonumber(zn(data[key..'val']))
                  end

                end

              end

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local fadcnt = tonumber(zn(data[key..'fadcnt']))

              if fadcnt and fadcnt > 0 then

                snaps[sst][ss].faddata = {}
                snaps[sst][ss].fadset = true

                for m = 1, fadcnt do

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_fad_'..m..'_'

                  snaps[sst][ss].faddata[m] = {}
                  local tt = tonumber(zn(data[key..'mfdata_targettype']))
                  if tt then
                    snaps[sst][ss].faddata[m].targettype = tt
                    snaps[sst][ss].faddata[m].strip = tonumber(zn(data[key..'mfdata_strip']))
                    snaps[sst][ss].faddata[m].page = tonumber(zn(data[key..'mfdata_page']))
                    snaps[sst][ss].faddata[m].ctl = tonumber(zn(data[key..'mfdata_ctl']))
                    snaps[sst][ss].faddata[m].c_id = tonumber(zn(data[key..'mfdata_c_id']))
                    snaps[sst][ss].faddata[m].voffset = tonumber(zn(data[key..'mfdata_voffset'],0))
                  end
                end

              end

            end


            --Snapshots_Check(s,p)
          end

        elseif sst > 1 then

          local key = pfx..'sst_'..sst..'_'
          snaps[sst] = {subsetname = data[key..'subsetname'],
                        subid = tonumber(data[key..'subid']),
                        stripid = tonumber(data[key..'stripid']),
                        morph_time = tonumber(zn(data[key..'morph_time'],0)),
                        morph_sync = tobool(zn(data[key..'morph_sync'],false)),
                        morph_syncv = tonumber(zn(data[key..'morph_syncv'],14)),
                        morph_scale = tonumber(zn(data[key..'morph_scale'],1)),
                        morph_loop = tonumber(zn(data[key..'morph_loop'],1)),
                        capturefaders = tobool(zn(data[key..'capturefaders'],false)),
                        capturemods = tobool(zn(data[key..'capturemods'],false)),
                        ignorevals = tobool(zn(data[key..'ignorevals'],false)),
                        snapshot = {}, ctls = {}}
          snaps[sst].sorted = tobool(zn(data[key..'sorted'],false))
          snaps[sst].mult = tobool(zn(data[key..'mult'],true))
          snaps[sst].stages = tonumber(zn(data[key..'stages'],1))
          snaps[sst].delay = {}
          snaps[sst].mtime = {}
          snaps[sst].deltype = {}
          for sd = 1, lvar.snapstages do
            local pkey = 'sdelay'..sd
            local mkey = 'mtime'..sd
            local tkey = 'deltype'..sd
            snaps[sst].delay[sd] = tonumber(nz(data[key..pkey],0))
            snaps[sst].mtime[sd] = tonumber(nz(data[key..mkey],15))
            snaps[sst].deltype[sd] = tonumber(nz(data[key..tkey],0))
          end

          lvar.snapsubsets_table[sst] = snaps[sst].subsetname

          local sscnt = tonumber(zn(data[key..'ss_count'],0))
          local ctlcnt = tonumber(zn(data[key..'ctl_count'],0))

          if ctlcnt > 0 then
            for ctl = 1, ctlcnt do

              local key = pfx..'sst_'..sst..'_c_'..ctl..'_'
              snaps[sst].ctls[ctl] = {c_id = tonumber(data[key..'cid']),
                                      ctl = tonumber(data[key..'ctl']),
                                      id = tonumber(zn(data[key..'id']))}
              snaps[sst].ctls[ctl].stage = tonumber(zn(data[key..'stage'])) or 1
              snaps[sst].ctls[ctl].morph = tobool(zn(data[key..'morph'],true))
              snaps[sst].ctls[ctl].mem = tobool(zn(data[key..'mem'],false))
            end
          end
          if sscnt > 0 then
            for ss = 1, sscnt do
              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local dcnt = tonumber(data[key..'data_count'])
              snaps[sst].snapshot[ss] = {name = data[key..'name'],
                                         data = {}}
              for d = 1, dcnt do

                local key = pfx..'sst_'..sst..'_ss_'..ss..'_d_'..d..'_'

                snaps[sst].snapshot[ss].data[d] = {c_id = tonumber(data[key..'cid']),
                                                   ctl = tonumber(data[key..'ctl']),
                                                   id = tonumber(zn(data[key..'id'])),
                                                   val = tonumber(data[key..'val']),
                                                   dval = tonumber(zn(data[key..'dval']))}

                local mf = tonumber(data[key..'mf'])
                snaps[sst].snapshot[ss].data[d].mfset = tobool(zn(data[key..'mfset']))
                if mf then
                  snaps[sst].snapshot[ss].data[d].mf = mf
                  snaps[sst].snapshot[ss].data[d].mfdata = {targettype = tonumber(data[key..'mfdata_targettype']),
                                                            strip = tonumber(data[key..'mfdata_strip']),
                                                            page = tonumber(data[key..'mfdata_page']),
                                                            ctl = tonumber(data[key..'mfdata_ctl']),
                                                            c_id = tonumber(data[key..'mfdata_c_id'])}
                end

              end

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local modcnt = tonumber(zn(data[key..'modcnt']))

              if modcnt and modcnt > 0 then

                snaps[sst].snapshot[ss].moddata = {}
                snaps[sst].snapshot[ss].modset = true

                for m = 1, modcnt do

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_'

                  snaps[sst].snapshot[ss].moddata[m] = {}
                  snaps[sst].snapshot[ss].moddata[m].active = tobool(zn(data[key..'active']))
                  snaps[sst].snapshot[ss].moddata[m].steps = tonumber(zn(data[key..'steps']))
                  snaps[sst].snapshot[ss].moddata[m].stepsmult = tonumber(zn(data[key..'stepsmult'],1))
                  snaps[sst].snapshot[ss].moddata[m].div = tonumber(zn(data[key..'div'],4))
                  snaps[sst].snapshot[ss].moddata[m].offset = tonumber(zn(data[key..'offset'],0.5))
                  snaps[sst].snapshot[ss].moddata[m].min = tonumber(zn(data[key..'min'],0))
                  snaps[sst].snapshot[ss].moddata[m].max = tonumber(zn(data[key..'max'],1))
                  snaps[sst].snapshot[ss].moddata[m].mode = tonumber(zn(data[key..'mode'],1))
                  snaps[sst].snapshot[ss].moddata[m].interpolate = tobool(zn(data[key..'interpolate']))
                  snaps[sst].snapshot[ss].moddata[m].syncv = tonumber(zn(data[key..'syncv']))
                  snaps[sst].snapshot[ss].moddata[m].sync = tobool(zn(data[key..'sync']))
                  local targetcnt = tonumber(zn(data[key..'target_cnt']))

                  snaps[sst].snapshot[ss].moddata[m].targets = {}
                  snaps[sst].snapshot[ss].moddata[m].data = {}
                  if targetcnt > 0 then
                    for t = 1, targetcnt do
                      local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_target_'..t..'_'
                      snaps[sst].snapshot[ss].moddata[m].targets[t] = {targettype = tonumber(zn(data[key..'targettype'],1)),
                                                                      strip = tonumber(zn(data[key..'strip'])),
                                                                      page = tonumber(zn(data[key..'page'])),
                                                                      ctl = tonumber(zn(data[key..'ctl'])),
                                                                      c_id = tonumber(zn(data[key..'c_id']))
                                                                      }
                    end
                  end

                  for d = 1, snaps[sst].snapshot[ss].moddata[m].steps do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_data_'..d..'_'
                    snaps[sst].snapshot[ss].moddata[m].data[d] = tonumber(zn(data[key..'val']))
                  end

                end

              end

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              local fadcnt = tonumber(zn(data[key..'fadcnt']))

              if fadcnt and fadcnt > 0 then

                snaps[sst].snapshot[ss].faddata = {}
                snaps[sst].snapshot[ss].fadset = true

                for m = 1, fadcnt do

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_fad_'..m..'_'

                  snaps[sst].snapshot[ss].faddata[m] = {}
                  local tt = tonumber(zn(data[key..'mfdata_targettype']))
                  if tt then
                    snaps[sst].snapshot[ss].faddata[m].targettype = tt
                    snaps[sst].snapshot[ss].faddata[m].strip = tonumber(zn(data[key..'mfdata_strip']))
                    snaps[sst].snapshot[ss].faddata[m].page = tonumber(zn(data[key..'mfdata_page']))
                    snaps[sst].snapshot[ss].faddata[m].ctl = tonumber(zn(data[key..'mfdata_ctl']))
                    snaps[sst].snapshot[ss].faddata[m].c_id = tonumber(zn(data[key..'mfdata_c_id']))
                    snaps[sst].snapshot[ss].faddata[m].voffset = tonumber(zn(data[key..'mfdata_voffset'],0))
                  end
                end

              end

            end
          end


          --Snapshots_Check(s,p)
        end

        local key = pfx..'sst_'..sst..'_'
        if snaps[sst] then
          snaps[sst].selected = tonumber(zn(data[key..'ss_selected']))
        end

      end

      --Snapshots_Check(s,p)
    else
      snaps[1] = {morph_time = 0,
                  morph_sync = false,
                  morph_syncv = 15,
                  morph_scale = 1}

    end
    return snaps

  end


  function LoadXXYData(s, data)

    local pfx = ''

    if data == nil then
      local load_path
      local fn = GPES('metalite_datafile_'..string.format("%03d",s))

      if settings_savedatainprojectfolder == true then
        load_path=reaper.GetProjectPath('')..'/'
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=paths.projsave_path
        end
      else
        load_path=paths.projsave_path
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=reaper.GetProjectPath('')..'/'
        end
      end

      local ffn=load_path..fn
      if reaper.file_exists(ffn) ~= true then
        DBG('Missing file: '..ffn)
        return 0
      end

      local file

      data = {}
      for line in io.lines(ffn) do
        local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
          data[idx] = val
        end
      end
    else
      pfx = 'xxy_s'..s..'_'
    end

    for p = 1, lvar.maxpage do

      for sst = 1, #snapshots[s][p] do

        local key = pfx..'xxy_p'..p..'_sst_'..sst..'_'
        local ptcnt = tonumber(zn(data[key..'pt_count']))
        if ptcnt then

          XXY_INIT(s, p, sst)
          xxy[s][p][sst].pathidx = tonumber(zn(data[key..'pathidx']))
          xxy[s][p][sst].pathfader = tonumber(zn(data[key..'pathfader']))
          xxy[s][p][sst].xfader = tonumber(zn(data[key..'xfader']))
          xxy[s][p][sst].yfader = tonumber(zn(data[key..'yfader']))

          for pt = 1, ptcnt do

            local key = pfx..'xxy_p'..p..'_sst_'..sst..'_pt_'..pt..'_'
            xxy[s][p][sst].points[pt] = {}
            xxy[s][p][sst].points[pt].x = tonumber(data[key..'x'])
            xxy[s][p][sst].points[pt].y = tonumber(data[key..'y'])
            xxy[s][p][sst].points[pt].ss = tonumber(data[key..'ss'])
            xxy[s][p][sst].points[pt].inactive = tobool(zn(data[key..'inactive']))

          end

        end

      end

    end

  end


  function LoadXXYPathData(data)

    local pfx = ''

    if data == nil then
      local load_path
      local fn = GPES('path_datafile', true)

      if fn == nil then return end

      if settings_savedatainprojectfolder == true then
        load_path=reaper.GetProjectPath('')..'/'
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=paths.projsave_path
        end
      else
        load_path=paths.projsave_path
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=reaper.GetProjectPath('')..'/'
        end
      end

      local ffn=load_path..fn
      if reaper.file_exists(ffn) ~= true then
        DBG('Missing file: '..ffn)
        return 0
      end

      local file

      data = {}
      for line in io.lines(ffn) do
        local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
          data[idx] = val
        end
      end
    end

    local key = 'pathcnt'
    local pathcnt = tonumber(zn(data[key]))

    if pathcnt and pathcnt > 0 then

      xxypath = {}

      for p = 1, pathcnt do

        local key = 'xxypath_'..p..'_'
        local ptcnt = tonumber(zn(data[key..'pt_count']))
        local idxcnt = tonumber(zn(data[key..'idxpt_count']))

        xxypath[p] = {}
        xxypath[p].pathlen = tonumber(zn(data[key..'pathlen']))

        xxypath[p].points = {}
        xxypath[p].pathidxpt = {}

        if ptcnt > 0 then

          for pt = 1, ptcnt do

            local key = 'xxypath_'..p..'_pt_'..pt..'_'
            xxypath[p].points[pt] = {}
            xxypath[p].points[pt].len = tonumber(zn(data[key..'len']))
            xxypath[p].points[pt].posstart = tonumber(zn(data[key..'posstart']))
            xxypath[p].points[pt].posend = tonumber(zn(data[key..'posend']))

            xxypath[p].points[pt].x = {}
            xxypath[p].points[pt].y = {}

            for xy = 1,4 do

              xxypath[p].points[pt].x[xy] = tonumber(zn(data[key..'x_'..xy]))
              xxypath[p].points[pt].y[xy] = tonumber(zn(data[key..'y_'..xy]))
            end

            local tcnt = tonumber(zn(data[key..'t_count']))

            if tcnt and tcnt > 0 then

              xxypath[p].points[pt].t = {}
              for t = 0, tcnt do

                xxypath[p].points[pt].t[t] = tonumber(zn(data[key..'t_'..t]))

              end
            end
          end
        end
        if idxcnt > 0 then
          for i = 0, idxcnt do

            local key = 'xxypath_'..p..'_idxpt_'..i
            xxypath[p].pathidxpt[i] = tonumber(zn(data[key]))

          end
        end
      end
    end

  end

  function LoadFaders(data, pfx, donotsetoval, check)

    pfx = pfx or ''

    local fadrs, snapshot_fader

    if data == nil then

      local load_path
      local fn = GPES('fader_datafile', true)
      if fn == nil then return end

      if settings_savedatainprojectfolder == true then
        load_path=reaper.GetProjectPath('')..'/'
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=paths.projsave_path
        end
      else
        load_path=paths.projsave_path
        if reaper.file_exists(load_path..fn) ~= true then
          load_path=reaper.GetProjectPath('')..'/'
        end
      end

      local ffn=load_path..fn
      if reaper.file_exists(ffn) ~= true then
        DBG('Missing file: '..ffn)
        return 0
      end

      fadrs = {}
      if reaper.file_exists(ffn) then
        local file
        file=io.open(ffn,"r")
        local content=file:read("*a")
        file:close()

        fadrs = unpickle(content)
      end
    else

      local key = pfx..'fadercnt'
      local fadercnt = tonumber(zn(data[key]))

      if fadercnt and fadercnt > 0 then

        local key = pfx..'snapshot_fader'
        snapshot_fader = tonumber(zn(data[key]))
        local key = pfx..'capture_fader'
        capture_fader = tonumber(zn(data[key]))

        fadrs = {}

        for f = 1, fadercnt do

          local key = pfx..'fader_'..f..'_'

          fadrs[f] = {}
          fadrs[f].targettype = tonumber(zn(data[key..'targettype']))
          fadrs[f].dm_guid = zn(data[key..'dm_guid'])
          fadrs[f].dm_trn = tonumber(zn(data[key..'dm_trn']))
          fadrs[f].strip = tonumber(zn(data[key..'strip']))
          fadrs[f].page = tonumber(zn(data[key..'page']))
          fadrs[f].ctl = tonumber(zn(data[key..'ctl']))
          fadrs[f].c_id = tonumber(zn(data[key..'c_id']))
          fadrs[f].sstype = tonumber(zn(data[key..'sstype']))
          fadrs[f].xy = tonumber(zn(data[key..'xy']))
          fadrs[f].mode = tonumber(zn(data[key..'mode']))
          fadrs[f].voffset = tonumber(zn(data[key..'voffset']))
          if fadrs[f].targettype == 7 then
            fadrs[f].voffset = nz(fadrs[f].voffset,0)
          end
        end

      end
    end
    if check == true then
      CheckFaders(fadrs)
    end
    if donotsetoval ~= true then
      Faders_SetOVAL()
    end
    if fadrs == nil then
      fadrs = Faders_INIT(true)
    end
    return fadrs, snapshot_fader, capture_fader

  end

  function CheckFaders(fads, donotupdatectl)

    if faders == nil then return end
    if fads == nil then fads = faders end

    --local faders = fads
    --if fads then return end
    for f = 1, #fads do
      if fads[f] then
        if fads[f].targettype == 4 or fads[f].targettype == 7 then
          fnd = false

          local dmg = fads[f].dm_guid
          local s = fads[f].strip
          local p = fads[f].page
          local c = fads[f].ctl
          local cid = fads[f].c_id
          if (dmg and dmg == lvar.dynamicmode_guid and strips[s][p].controls[c] and cid == strips[s][p].controls[c].c_id) or
             (not dmg and strips[s] and strips[s][p].controls[c] and cid == strips[s][p].controls[c].c_id) then
            --all good
            strips[s][p].controls[c].macrofader = f
            fnd = true
          elseif (dmg and dmg ~= lvar.dynamicmode_guid and lvar.stripstore[dmg] and lvar.stripstore[dmg].controls[c] and cid == lvar.stripstore[dmg].controls[c].c_id) then
            lvar.stripstore[dmg].controls[c].macrofader = f
            fnd = true
          else
            if fads[f].dm_guid then
              if lvar.stripstore[dmg] then
                for cc = 1, #lvar.stripstore[dmg].controls do
                  if lvar.stripstore[dmg].controls[cc].c_id == cid then
                    strips[s][p].controls[cc].macrofader = f
                    fads[f].ctl = cc
                    fnd = true
                    break
                  end
                end
                if fnd == false then
                  for guid, tbl in pairs(lvar.stripstore) do
                    for cc = 1, #tbl.controls do
                      if tbl.controls[cc].c_id == cid then
                        if donotupdatectl == nil then
                          tbl.controls[cc].macrofader = f
                        end
                        fads[f].strip = track[track_select].strip
                        fads[f].page = page
                        fads[f].ctl = cc
                        fads[f].dm_guid = guid
                        fnd = true
                        break
                      end
                    end
                    if fnd == true then
                      break
                    end
                  end
                end
              end
            else
              if strips[s] then
                for cc = 1, #strips[s][p].controls do
                  if strips[s][p].controls[cc].c_id == cid then

                    if donotupdatectl == nil then
                      strips[s][p].controls[cc].macrofader = f
                    end
                    fads[f].ctl = cc
                    fnd = true
                    break
                  end
                end
                if fnd == false then
                  for ss = 1, #strips do
                    for pp = 1, lvar.maxpage do
                      for cc = 1, #strips[ss][pp].controls do
                        if strips[ss][pp].controls[cc].c_id == cid then

                          if donotupdatectl == nil then
                            strips[ss][pp].controls[cc].macrofader = f
                            --DBG(f)
                          end
                          fads[f].strip = ss
                          fads[f].page = pp
                          fads[f].ctl = cc
                          fnd = true
                          break
                        end
                      end
                      if fnd == true then
                        break
                      end
                    end
                    if fnd == true then
                      break
                    end
                  end
                end
              end
            end
          end
          if fnd == false then
            --not found
            --DBG('nf '..f)
            fads[f] = {}
          end
        end
      end
    end
    return fads

  end

  function CheckMods(mods, removefirst)

    if mods == nil then return end

    if removefirst == true then

      if strips and #strips > 0 then
        for s = 1, #strips do
          for p = 1, lvar.maxpage do
            if #strips[s][p].controls > 0 then

              for c = 1, #strips[s][p].controls do
                strips[s][p].controls[c].mod = nil
              end
            end
          end
        end
      end
    end

    for m = 1, #mods do
      mods[m] = CheckMod(mods[m],m)
    end
    return mods

  end

  function CheckMod(mod,m)

      if mod == nil then return end

        if mod.targets and #mod.targets > 0 then

          local tcnt = #mod.targets
          local tchange = false
          for t = 1, tcnt do
            fnd = false

            local dmg = mod.targets[t].dm_guid
            local s = mod.targets[t].strip
            local p = mod.targets[t].page
            local c = mod.targets[t].ctl
            local cid = mod.targets[t].c_id
            if strips[s] then
              if (dmg and dmg == lvar.dynamicmode_guid and strips[s] and strips[s][p].controls[c] and cid == strips[s][p].controls[c].c_id) or
                 (not dmg and strips[s] and strips[s][p].controls[c] and cid == strips[s][p].controls[c].c_id) then
                --all good
                strips[s][p].controls[c].mod = m
                fnd = true
              elseif (dmg and dmg ~= lvar.dynamicmode_guid and lvar.stripstore and lvar.stripstore[dmg] and lvar.stripstore[dmg].controls[c] and cid == lvar.stripstore[dmg].controls[c].c_id) then
                lvar.stripstore[dmg].controls[c].mod = m
                fnd = true
              else
                if mod.targets[t].dm_guid then
                  if lvar.stripstore and lvar.stripstore[dmg] then
                    for cc = 1, #lvar.stripstore[dmg].controls do
                      if lvar.stripstore[dmg].controls[cc].c_id == cid then
                        strips[s][p].controls[cc].mod = m
                        mod.targets[t].ctl = cc
                        fnd = true
                        break
                      end
                    end
                    if fnd == false then
                      for guid, tbl in pairs(lvar.stripstore) do
                        for cc = 1, #tbl.controls do
                          if tbl.controls[cc].c_id == cid then
                            tbl.controls[cc].mod = m
                            mod.targets[t].strip = track[track_select].strip
                            mod.targets[t].page = page
                            mod.targets[t].ctl = cc
                            mod.targets[t].dm_guid = guid
                            fnd = true
                            break
                          end
                        end
                        if fnd == true then
                          break
                        end
                      end
                    end
                  end
                else
                  if strips[s] then
                    for cc = 1, #strips[s][p].controls do
                      if strips[s][p].controls[cc].c_id == cid then
                        strips[s][p].controls[cc].mod = m
                        mod.targets[t].ctl = cc
                        fnd = true
                        break
                      end
                    end
                    if fnd == false then
                      for ss = 1, #strips do
                        for pp = 1, lvar.maxpage do
                          for cc = 1, #strips[ss][pp].controls do
                            if strips[ss][pp].controls[cc].c_id == cid then
                              strips[ss][pp].controls[cc].mod = m
                              mod.targets[t].strip = ss
                              mod.targets[t].page = pp
                              mod.targets[t].ctl = cc
                              fnd = true
                              break
                            end
                          end
                          if fnd == true then
                            break
                          end
                        end
                        if fnd == true then
                          break
                        end
                      end
                    end
                  end
                end
              end
            end
            if fnd == false then
              --not found
              tchange = true
              mod.targets[t] = nil
            end

          end

          if tchange == true then
            --DBG('remmmmmm')
            mod.targets = Table_RemoveNils(mod.targets, tcnt)
          end

        end
      return mod
    end

 --[[ function CheckMod(mod,m)
    if mod == nil then return end

      if mod.targets and #mod.targets > 0 then

        local tcnt = #mod.targets
        local tchange = false
        for t = 1, tcnt do
          fnd = false

          local s = mod.targets[t].strip
          local p = mod.targets[t].page
          local c = mod.targets[t].ctl
          local cid = mod.targets[t].c_id
          if strips[s] and strips[s][p].controls[c] and cid == strips[s][p].controls[c].c_id and
             strips[s][p].controls[c].mod == m then
            --all good
            fnd = true
          else
            if strips[s] then
              for cc = 1, #strips[s][p].controls do
                if strips[s][p].controls[cc].c_id == cid then
                  strips[s][p].controls[cc].mod = m
                  mod.targets[t].ctl = cc
                  fnd = true
                  break
                end
              end
              if fnd == false then
                for ss = 1, #strips do
                  for pp = 1, lvar.maxpage do
                    for cc = 1, #strips[ss][pp].controls do
                      if strips[ss][pp].controls[cc].c_id == cid then
                        strips[ss][pp].controls[cc].mod = m
                        mod.targets[t].strip = ss
                        mod.targets[t].page = pp
                        mod.targets[t].ctl = cc
                        fnd = true
                        break
                      end
                    end
                    if fnd == true then
                      break
                    end
                  end
                  if fnd == true then
                    break
                  end
                end
              end
            end
          end
          if fnd == false then
            --not found
            tchange = true
            mod.targets[t] = nil
          end

        end

        if tchange == true then
          mod.targets = Table_RemoveNils(mod.targets, tcnt)
        end

      end
    return mod
  end
]]

  function LoadModPreset(ffn)

    if reaper.file_exists(ffn) ~= true then
      DBG('Missing file: '..ffn)
      return 0
    end

    local data = {}
    local match = string.match

    for line in io.lines(ffn) do
      local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
      if idx then
        val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
        data[idx] = val
      end
    end

    local targets = {}
    local m = mod_select
    if modulators[m] and modulators[m].targets then
      targets = modulators[m].targets
    end

    LoadMod('',m,data)

    modulators[m].targets = targets

  end

  function LoadMod(pfx,m,data)

    local key = pfx
    local steps = tonumber(zn(data[key..'steps']))

    if steps then

      modulators[m] = {}
      modulators[m].steps = steps

      modulators[m].active = tobool(zn(data[key..'active']))
      modulators[m].stepsmult = tonumber(zn(data[key..'stepsmult'],1))
      modulators[m].div = tonumber(zn(data[key..'div'],4))
      modulators[m].offset = tonumber(zn(data[key..'offset'],0.5))
      modulators[m].min = tonumber(zn(data[key..'min'],0))
      modulators[m].max = tonumber(zn(data[key..'max'],1))
      modulators[m].mode = tonumber(zn(data[key..'mode'],1))
      modulators[m].interpolate = tobool(zn(data[key..'interpolate']))
      modulators[m].syncv = tonumber(zn(data[key..'syncv']))
      modulators[m].sync = tobool(zn(data[key..'sync']))
      local targetcnt = tonumber(zn(data[key..'target_cnt']))

      modulators[m].targets = {}
      modulators[m].data = {}
      if targetcnt and targetcnt > 0 then
        for t = 1, targetcnt do
          local key = pfx..'target_'..t..'_'
          modulators[m].targets[t] = {targettype = tonumber(zn(data[key..'targettype'],1)),
                                      dm_guid = zn(data[key..'dm_guid']),
                                      dm_trn = tonumber(zn(data[key..'dm_trn'])),
                                      strip = tonumber(zn(data[key..'strip'])),
                                      page = tonumber(zn(data[key..'page'])),
                                      ctl = tonumber(zn(data[key..'ctl'])),
                                      c_id = tonumber(zn(data[key..'c_id']))
                                      }
        end
      end

      for d = 1, modulators[m].steps do
        local key = pfx..'data_'..d..'_'
        modulators[m].data[d] = tonumber(zn(data[key..'val']))
      end
    end

  end

  function LoadMods(data)

    local key = 'modcnt'
    local modcnt = tonumber(zn(data[key]))

    if modcnt and modcnt > 0 then

      modulator_cnt = modcnt
      --modulators = {}

      for m = 1, modcnt do

        local key = 'mod_'..m..'_'
        LoadMod(key,m,data)

      end
      modulators = INIT_Modulators(modulators)

    end

    modulators = CheckMods(modulators)
    --Faders_SetOVAL()

  end

  function LoadSwitchers(data)

    local key = 'switcher_cnt'
    local scnt = tonumber(zn(data[key]))

    if scnt and scnt > 0 then
      switchers = {}
      for s = 1, scnt do

        local key = 'switch'..s..'_'
        switchers[s] = {grpids = {},
                        current = tonumber(zn(data[key..'current'])),
                        switchmode = tonumber(zn(data[key..'switchmode'],0)),
                        stripfolder = zn(data[key..'stripfolder']),
                        copypinmap = tobool(zn(data[key..'copypinmap'])),
                        dropx = tonumber(zn(data[key..'dropx'])),
                        dropy = tonumber(zn(data[key..'dropy'])),
                        extendmode = tobool(zn(data[key..'extendmode'])),
                        extendid = tonumber(zn(data[key..'extendid'])),
                        extenddir = tonumber(zn(data[key..'extenddir'])),
                        extendpos = tonumber(zn(data[key..'extendpos'])),
                        padx = tonumber(data[key..'padx']) or 0,
                        pady = tonumber(data[key..'pady']) or 0,
                        parent = {switcherid = tonumber(zn(data[key..'par_swid'])),
                                  grpid = tonumber(zn(data[key..'par_grpid'])),
                                 }}
        switchers[s].popx = tonumber(data[key..'popx'])
        switchers[s].popy = tonumber(data[key..'popy'])

        if data[key..'posfirst_x'] then
          switchers[s].posfirstswitcher = {x = tonumber(data[key..'posfirst_x']),
                                           y = tonumber(data[key..'posfirst_y'])}
        end

        swcnt = tonumber(zn(data[key..'grpid_cnt']))
        for swc = 1, swcnt do
          local key = 'switch'..s..'_gid_'..swc..'_'
          switchers[s].grpids[swc] = {}
          switchers[s].grpids[swc].id = tonumber(zn(data[key..'grpid']))
          switchers[s].grpids[swc].name = zn(data[key..'grpname'])
          switchers[s].grpids[swc].stripfn = zn(data[key..'stripfn'])
        end

        gcnt = tonumber(zn(data[key..'fxguid_cnt'])) or 0
        if gcnt > 0 then
          switchers[s].fxguids = {}
          for sgc = 1, gcnt do
            local key = 'switch'..s..'_fxguid_'..sgc..'_'
            switchers[s].fxguids[sgc] = zn(data[key..'guid'])
          end
        end
      end

    end
  end

  function GetProjectName()

    return reaper.GetProjectName(0, '')

  end

  function DBGOut(msg)

    if DBG_mode then
      DBG(msg)
    end

  end

  function FindDataFile(fn)

    local ret = reaper.MB('Missing data file.  Would you like to manually locate it?','Missing data file', 4)
    if ret == 6 then
      local ret, rfn = reaper.GetUserFileNameForRead(fn, 'Locate lbxstripper data file:', string.match(fn, '.+%.(lbxstripper.*)'))
      if ret == true then

        return rfn

      end
    end

  end

  function LoadDataFile(ffn)

    ZeroProjectFlags()

    local s, p, c, g, k

    local t = reaper.time_precise()
    local data = {}


    DBGOut('')
    DBGOut('*** LOADING DATA ***')
    DBGOut('LoadData: Saved OK: '..tostring(GPES('savedok')))

    --gfx.setimgdim(1, -1, -1)
    Img_SetDim(1, gfx1.main_w,gfx1.main_h)
    GUI_DrawMsgX(obj, gui, 'Reading data file...  Please wait...')

    DBGOut('LoadData: ffn: '..tostring(ffn))
    if reaper.file_exists(ffn) ~= true then
      nfn = FindDataFile(ffn)
      if nfn ~= nil and reaper.file_exists(nfn) == true then
        ffn = nfn
      else
        if nfn then
          ffn = nfn
        end
        DBG('Missing file: '..ffn)
        return 0
      end
    end

    local ctr = 0
    datafile = ffn

    for line in io.lines(ffn) do
      ctr = ctr + 1
      if ctr % 4000 == 0 then
        GUI_DrawMsgX(obj, gui, 'Reading data file...  (line: '..ctr..')', nil, nil, true)
      end
      local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
      if idx then
        val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
        data[idx] = val
      end
    end

    DBGOut('LoadData: Read lines: '..tostring(ctr))

    --local scnt = tonumber(nz(GPES('strips_count'),0))
    local v = tonumber(zn(data['version']))
    local cont = true
    if v >= 0.96 then
      if data['EOF'] ~= '#EOF' then
        id = tostring(math.floor(math.random() * 0xFFFFFFFF))
        local rfn = string.match(ffn,'(.+).lbxstripper')..'_'..id..'.lbxincomplete'
        local r = reaper.MB('It appears the data file is incomplete:  Continue loading?\n\nA backup of this file will be made to: '..rfn,'Load Data',4)
        if r == 7 then
          cont = false
        end
        copyfile(ffn, rfn)
      end
    end

    if cont == false then
      reaper.MB('You may wish to locate an alternative or backup data file for this project - use Main Menu->Script Data to search for an alternative data file','Load Aborted',0)
    else
      local scnt = tonumber(zn(data['stripcount']))
      if scnt == nil then data = nil reaper.MB('Not a loadable lbxstripper file','Load Failed',0) return 0 end

      DBGOut('LoadData: strip count: '..tostring(scnt))

      strips = {}
      local ss = 1
      if scnt > 0 then

        for s = 1, scnt do

          GUI_DrawMsgX(obj, gui, 'Loading Strip Data...', s, scnt)
          LoadStripData(s, ss, data)
          ss=ss+1

        end
      end

      PopulateTracks()
      Snapshots_INIT()
      --local scnt = tonumber(nz(GPES('snapshots_count'),0))
      local scnt = tonumber(zn(data['snapshotcount']))
      DBGOut('LoadData: snapshot count: '..tostring(scnt))

      if scnt and scnt > 0 then

        for s = 1, scnt do

          GUI_DrawMsgX(obj, gui, 'Loading Snapshot Data...', s, scnt)
          LoadSnapData(s, data)

        end

        local strip = tracks[track_select].strip
        if sstype_select and snapshots[strip] and snapshots[strip][page][sstype_select].selected then
          ss_select = snapshots[strip][page][sstype_select].selected
        end

      end

      --XXY

      for s = 1, #strips do

        GUI_DrawMsgX(obj, gui, 'Loading Metalite Data...', s, #strips)
        LoadXXYData(s, data)

      end

      LoadXXYPathData(data)
      faders, snapshot_fader, capture_fader = LoadFaders(data,'',_,true)
      if data['global_fadercnt'] then
        lvar.gfaders = LoadFaders(data,'global_',true)
      end
      if faders == nil then
        faders = Faders_INIT(true)
      end

      LoadMods(data)
      LoadSwitchers(data)

      LoadSK2Assign(data)

      LoadCompatibility(v, strips)

      --DBG('Total Load Time: '..reaper.time_precise() - t)
      infomsg = 'Total Load Time: '..round(reaper.time_precise() - t,2)..'s'
      DBGOut(infomsg)
    end

    data = nil

    PopulateTracks() --must be called to link tracks to strips

    if show_editbar then
      plist_w = oplist_w
    else
      plist_w = 0
    end

    if track_select then
      ChangeTrack(track_select)
      local tr = GetTrack(track_select)
      if tr then
        --reaper.SetOnlyTrackSelected(tr)
      end
    end
    if tracks and tracks[track_select] and tracks[track_select].strip and strips[tracks[track_select].strip] then
      surface_offset.x = tonumber(strips[tracks[track_select].strip][page].surface_x)
      surface_offset.y = tonumber(strips[tracks[track_select].strip][page].surface_y)
    end
    GUI_DrawCtlBitmap()

    --ctls_dnu, ctls_upd = CtlDNU()

    ZeroProjectFlags()

  end

  function LoadData()

    local fidx = lvar.ctlfiles_idx

    lvar.dm_switchload = false

    lvar.dynamicmode_trn = nil
    lvar.dynamicmode_guid = nil
    local SCRIPT = lvar.SCRIPT

    lvar.dm_trackbtns = {}
    lvar.dm_trackbtns[1] = {}

    --[[local ret, trb_idx = reaper.GetProjExtState(0,SCRIPT,'dm_tbidx')
    lvar.dm_tbidx = tonumber(trb_idx) or 1
    local ret, trb_gcnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_grp_count')
    trb_gcnt = tonumber(trb_gcnt)
    local legacy
    if not trb_gcnt then
      trb_gcnt = 1
      legacy = true
    end
    lvar.dm_trackbtns = {}
    for ii = 1, trb_gcnt do
      local ret, trb_cnt
      if not legacy then
        ret, trb_cnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_count_'..string.format('%i',ii))
      else
        ret, trb_cnt = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_count') --backwards compat
      end
      trb_cnt = tonumber(trb_cnt) or 0
      lvar.dm_trackbtns[ii] = {}
      if not legacy then
        local ret, name = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_name_'..string.format('%i',ii))
        if ret and name ~= '' then
          lvar.dm_trackbtns[ii].name = name
        end
      end
      if trb_cnt > 0 then
        for i = 1, trb_cnt do
          local key = string.format('%i',ii)..'_'..string.format('%i',i)
          if legacy then
            key = string.format('%i',i)
          end
          local ret, guid = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_guid_'..key)
          local ret, trn = reaper.GetProjExtState(0,SCRIPT,'dm_trackbtns_trn_'..key)
          if tonumber(trn) then
            lvar.dm_trackbtns[ii][i] = {}
            lvar.dm_trackbtns[ii][i].guid = guid
            lvar.dm_trackbtns[ii][i].trn = tonumber(trn)
          end
        end
      else
        lvar.dm_trackbtns[ii] = {}
      end
    end

    lvar.dm_backtrack = nil
    local guid = GPES('dm_backtrack_guid',true)
    if guid then
      lvar.dm_backtrack = {}
      lvar.dm_backtrack.guid = guid
      lvar.dm_backtrack.trn = tonumber(GPES('dm_backtrack_trn',true))
      lvar.dm_backtrack.page = tonumber(GPES('dm_backtrack_page',true))
    end]]

    local find = string.find
    local match = string.match
    local LDF

    ZeroProjectFlags()

    local s, p, c, g, k

    local t = reaper.time_precise()
    local data = {}
    local cont = true

    DBGOut('')
    DBGOut('*** LOADING DATA ***')
    DBGOut('LoadData: Saved OK: '..tostring(GPES('savedok')))

    if lvar.striploadoverride and not reaper.file_exists(lvar.striploadoverride) then
      lvar.striploadoverride = nil
    end

    if GPES('savedok') ~= '' or lvar.striploadoverride then

      local globset = false
      if lvar.striploadoverride then
        PROJECTID = tonumber(GPES('projectid'))
        globset = LoadGlobOvProjSettingsFile()
      end

      if lbxwin_dim then
        lbxwin_dim.w = lbxwin_dim.w or 800
        lbxwin_dim.h = lbxwin_dim.h or 450
        
        gfx1 = {main_w = lbxwin_dim.w,
                main_h = lbxwin_dim.h}
        Lokasenna_Window_At_Center(gfx1.main_w,gfx1.main_h,lbxwin_dim.x,lbxwin_dim.y)
      else
        if globset == false then
          local ww, wh = GPES('win_w',true), GPES('win_h',true)
          if tonumber(ww) ~= nil and tonumber(wh) ~= nil then
            gfx1 = {main_w = tonumber(ww) or 800,
                    main_h = tonumber(wh) or 450}
          else
            gfx1 = {main_w = 800,
                    main_h = 450}
          end
          Lokasenna_Window_At_Center(gfx1.main_w,gfx1.main_h)
          --gfx.dock(dockstate)
        end
      end

      --gfx.setimgdim(1, -1, -1)
      Img_SetDim(1, gfx1.main_w,gfx1.main_h)
      GUI_DrawMsgX(obj, gui, 'Reading data file...  Please wait...')

      local rv, v = reaper.GetProjExtState(0,lvar.SCRIPT,'version')
      DBGOut('LoadData: version: '..tostring(v))
      --DBG('LoadData: version: '..tostring(v))

      if v ~= '' or lvar.striploadoverride then

        if globset == false then

          PROJECTID = tonumber(GPES('projectid'))
          --DBG('LProjid: '..PROJECTID)
          settings_gridsize = tonumber(nz(GPES('gridsize',true),settings_gridsize))
          settings_showgrid = tobool(nz(GPES('showgrid',true),true))
          show_editbar = tobool(nz(GPES('showeditbar',true),not settings_hideeditbaronnewproject))
          ogrid = settings_gridsize
          osg = settings_showgrid
          settings_locksurface = tobool(nz(GPES('locksurface',true),false))
          track_select = tonumber(nz(GPES('lasttrack',true),0))
          xxy_gravity = tonumber(nz(GPES('metalite_gravity',true),xxy_gravity))
          snapshot_win_pos = {x = tonumber(nz(GPES('snapwinpos_x',true))),
                              y = tonumber(nz(GPES('snapwinpos_y',true)))}
          show_snapshots = tobool(nz(GPES('showsnap',true),false))
          hideunusedtracks = tobool(nz(GPES('hidetracks',true),false))

          lvar.stripbrowser.page = tonumber(nz(GPES('sb_page',true),lvar.stripbrowser.page))
          lvar.stripbrowser.favs = tobool(nz(GPES('sb_favs',true),lvar.stripbrowser.favs))
          stripfol_select = tonumber(nz(GPES('sb_fol',true),stripfol_select))
          if not strip_folders[stripfol_select] then
            stripfol_select = 0
          end
          settings_localfaders = tobool(nz(GPES('localfaders',true),settings_localfaders))
        end

        PopulateStrips(lvar.sortcontrols)

        if show_editbar then
          plist_w = oplist_w
        else
          plist_w = 0
        end

        DM_LoadData()

        DBGOut('LoadData: PROJECT ID: '..tostring(PROJECTID))

        if lvar.striploadoverride then
          v = lvar.VERSION
        end

        if lvar.striploadoverride or tostring(v) >= '0.94' then

          data = {}
          local load_path
          local fn = GPES('lbxstripper_datafile', true)

          LDF = fn

          if fn == nil and lvar.striploadoverride == nil then return end

          if lvar.striploadoverride then
            fn = ''
          end

          if settings_savedatainprojectfolder == true then
            load_path=reaper.GetProjectPath('')..'/'
            if reaper.file_exists(load_path..fn) ~= true then
              load_path=paths.projsave_path
            end
          else
            load_path=paths.projsave_path
            if reaper.file_exists(load_path..fn) ~= true then
              load_path=reaper.GetProjectPath('')..'/'
            end
          end

          local ffn
          if lvar.striploadoverride then
            if reaper.file_exists(lvar.striploadoverride) then
              ffn = lvar.striploadoverride
              fn = string.match(ffn,'.+[\\/](.*)')
              lvar.striploadoverride_active = true
            else
              DBG('Missing file: '..lvar.striploadoverride)
              return 0
            end
          else
            ffn=load_path..fn
          end

          DBGOut('LoadData: ffn: '..tostring(ffn))
          if reaper.file_exists(ffn) ~= true then

            nfn = FindDataFile(ffn)
            if nfn ~= nil and reaper.file_exists(nfn) == true then
              ffn = nfn
            else
              if nfn then
                ffn = nfn
              end
              DBG('Missing file: '..ffn)
              return 0
            end
          end

          local ctr = 0
          datafile = ffn
          --DBG(ffn)
          local flines = io.lines
          --local fGUI_DrawMsgX = GUI_DrawMsgX

          for line in flines(ffn) do
            ctr = ctr + 1
            if ctr % 4000 == 0 then
              GUI_DrawMsgX(obj, gui, 'Reading data file...  (line: '..ctr..')', nil, nil, true)
            end
            local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
            if idx then
              val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
              data[idx] = val
            end
          end

          DBGOut('LoadData: Read lines: '..tostring(ctr))

          if tonumber(v) >= 0.96 then
            if data['EOF'] ~= '#EOF' then
              id = tostring(math.floor(math.random() * 0xFFFFFFFF))
              local rfn = string.match(ffn,'(.+).lbxstripper')..'_'..id..'.lbxincomplete'
              local r = reaper.MB('It appears the data file is incomplete:  Continue loading?\n\nA backup of this file will be made to: '..rfn,'Load Data',4)
              if r == 7 then
                cont = false
              end
              copyfile(ffn, rfn)
            end
          end

          if cont == false then
            reaper.MB('You may wish to locate an alternative or backup data file for this project - use Main Menu->Script Data to search for an alternative data file','Load Aborted',0)
          end
        end

        if cont == true then
          local scnt
          if lvar.striploadoverride_active == true then
            scnt = tonumber(data['stripcount'])
          else
            scnt = --[[tonumber(GPES('strips_count')) or ]] tonumber(data['stripcount']) or tonumber(nz(GPES('strips_count'),0))
          end
          DBGOut('LoadData: strip count: '..tostring(scnt))

          strips = {}

          local ss = 1
          if scnt > 0 then
            for s = 1, scnt do

              GUI_DrawMsgX(obj, gui, 'Loading Strip Data...', s, scnt)

              if tostring(v) == '0.93' then
                LoadStripData(s, ss)
                ss=ss+1

                --if not CheckTrackExists(ss) then
                --  ss = ss - 1
                --end
              elseif tostring(v) >= '0.94' then
                LoadStripData(s, ss, data)
                ss=ss+1

              else

                key = 'strips_'..s..'_'

                strips[ss] = {}

                strips[ss].page = tonumber(nz(GPES(key..'page',true),1))

                key = 'strips_'..s..'_track_'

                strips[ss].track = {
                                   name = GPES(key..'name'),
                                   guid = GPES(key..'guid'),
                                   tracknum = tonumber(GPES(key..'tracknum')),
                                   strip = tonumber(GPES(key..'strip'))
                                  }
                if CheckTrackExists(ss) then
                  for p = 1, lvar.maxpage do

                    local key = 'strips_'..s..'_'..p..'_'

                    strips[ss][p] = {
                                    surface_x = tonumber(GPES(key..'surface_x')),
                                    surface_y = tonumber(GPES(key..'surface_y')),
                                    controls = {},
                                    graphics = {}
                                   }

                    local ccnt = tonumber(GPES(key..'controls_count'))
                    local gcnt = tonumber(GPES(key..'graphics_count'))

                    if ccnt > 0 then
                      for c = 1, ccnt do

                        local key = 'strips_'..s..'_'..p..'_controls_'..c..'_'
                        strips[ss][p].controls[c] = {
                                                    c_id = tonumber(nz(GPES(key..'cid',true),GenID() )),
                                                    ctlcat = tonumber(nz(GPES(key..'ctlcat',true),0)),
                                                    fxname = GPES(key..'fxname'),
                                                    fxguid = GPES(key..'fxguid'),
                                                    fxnum = tonumber(GPES(key..'fxnum',true)),
                                                    fxfound = tobool(GPES(key..'fxfound')),
                                                    param = tonumber(GPES(key..'param')),
                                                    param_info = {
                                                                  paramname = GPES(key..'param_info_name'),
                                                                  paramnum = tonumber(GPES(key..'param_info_paramnum',true)),
                                                                  paramidx = GPES(key..'param_info_idx',true),
                                                                  paramstr = GPES(key..'param_info_str',true),
                                                                  paramdestguid = GPES(key..'param_info_guid',true),
                                                                  paramdestchan = tonumber(GPES(key..'param_info_chan',true)),
                                                                  paramsrcchan = tonumber(GPES(key..'param_info_srcchan',true))
                                                                 },
                                                    ctltype = tonumber(GPES(key..'ctltype')),
                                                    knob_select = tonumber(GPES(key..'knob_select')),
                                                    ctl_info = {
                                                                fn = GPES(key..'ctl_info_fn'),
                                                                frames = tonumber(GPES(key..'ctl_info_frames')),
                                                                imageidx = tonumber(GPES(key..'ctl_info_imageidx')),
                                                                cellh = tonumber(GPES(key..'ctl_info_cellh'))
                                                               },
                                                    x = tonumber(GPES(key..'x')),
                                                    y = tonumber(GPES(key..'y')),
                                                    w = tonumber(GPES(key..'w')),
                                                    scale = tonumber(GPES(key..'scale')),
                                                    show_paramname = tobool(GPES(key..'show_paramname')),
                                                    show_paramval = tobool(GPES(key..'show_paramval')),
                                                    ctlname_override = nz(GPES(key..'ctlname_override'),''),
                                                    textcol = GPES(key..'textcol'),
                                                    textoff = tonumber(GPES(key..'textoff')),
                                                    textoffval = tonumber(nz(GPES(key..'textoffval',true),0)),
                                                    textoffx = tonumber(nz(GPES(key..'textoffx',true),0)),
                                                    textoffvalx = tonumber(nz(GPES(key..'textoffvalx',true),0)),
                                                    textsize = tonumber(nz(GPES(key..'textsize'),0)),
                                                    val = tonumber(GPES(key..'val')),
                                                    defval = tonumber(GPES(key..'defval')),
                                                    maxdp = tonumber(nz(GPES(key..'maxdp',true),-1)),
                                                    cycledata = {statecnt = 0,{}},
                                                    xydata = {x = tonumber(nz(GPES(key..'xydata_x',true),0.5)),
                                                              y = tonumber(nz(GPES(key..'xydata_y',true),0.5)),
                                                              snapa = tonumber(nz(GPES(key..'xydata_snapa',true),1)),
                                                              snapb = tonumber(nz(GPES(key..'xydata_snapb',true),1)),
                                                              snapc = tonumber(nz(GPES(key..'xydata_snapc',true),1)),
                                                              snapd = tonumber(nz(GPES(key..'xydata_snapd',true),1))},
                                                    id = deconvnum(GPES(key..'id',true)),
                                                    scalemode = tonumber(nz(GPES(key..'scalemodex',true),8)),
                                                    framemode = tonumber(nz(GPES(key..'framemodex',true),1)),
                                                    poslock = tobool(nz(GPES(key..'poslock',true),false)),
                                                    horiz = tobool(nz(GPES(key..'horiz',true),false)),
                                                    knobsens = {norm = settings_defknobsens.norm,
                                                                fine = settings_defknobsens.fine,
                                                                wheel = settings_defknobsens.wheel,
                                                                wheelfine = settings_defknobsens.wheelfine,
                                                                m_norm = settings_defknobsens.m_norm,
                                                                m_fine = settings_defknobsens.m_fine,
                                                                m_wheel = settings_defknobsens.m_wheel,
                                                                m_wheelfine = settings_defknobsens.m_wheelfine,
                                                                }
                                                   }
                        g_cids[strips[ss][p].controls[c].c_id] = true
                        if strips[ss][p].controls[c].maxdp == nil or (strips[ss][p].controls[c].maxdp and strips[ss][p].controls[c].maxdp == '') then
                          strips[ss][p].controls[c].maxdp = -1
                        end
                        strips[ss][p].controls[c].xsc = math.floor(strips[ss][p].controls[c].x + strips[ss][p].controls[c].w/2 - (strips[ss][p].controls[c].w*strips[ss][p].controls[c].scale)/2)
                        strips[ss][p].controls[c].ysc = math.floor(strips[ss][p].controls[c].y + strips[ss][p].controls[c].ctl_info.cellh/2 - (strips[ss][p].controls[c].ctl_info.cellh*strips[ss][p].controls[c].scale)/2)
                        strips[ss][p].controls[c].wsc = math.floor(strips[ss][p].controls[c].w*strips[ss][p].controls[c].scale)
                        strips[ss][p].controls[c].hsc = math.floor(strips[ss][p].controls[c].ctl_info.cellh*strips[ss][p].controls[c].scale)

                        strips[ss][p].controls[c].tracknum = tonumber(GPES(key..'tracknum',true))
                        strips[ss][p].controls[c].trackguid = GPES(key..'trackguid')
                        strips[ss][p].controls[c].dvaloffset = GPES(key..'dvaloffset',true)
                        strips[ss][p].controls[c].minov = GPES(key..'minov',true)
                        strips[ss][p].controls[c].maxov = GPES(key..'maxov',true)
                        strips[ss][p].controls[c].membtn = {state = tobool(nz(GPES(key..'memstate',true),false)),
                                                            mem = tonumber(nz(GPES(key..'memmem',true),0))
                                                            }

                        strips[ss][p].controls[c].cycledata.statecnt = tonumber(nz(GPES(key..'cycledata_statecnt',true),0))
                        strips[ss][p].controls[c].cycledata.mapptof = tobool(nz(GPES(key..'cycledata_mapptof',true),false))
                        strips[ss][p].controls[c].cycledata.draggable = tobool(nz(GPES(key..'cycledata_draggable',true),false))
                        strips[ss][p].controls[c].cycledata.spread = tobool(nz(GPES(key..'cycledata_spread',true),false))
                        strips[ss][p].controls[c].cycledata.pos = tonumber(nz(GPES(key..'cycledata_pos',true),1))
                        strips[ss][p].controls[c].cycledata.posdirty = tobool(nz(GPES(key..'cycledata_posdirty',true),false))
                        strips[ss][p].controls[c].cycledata.val = 0
                        if nz(strips[ss][p].controls[c].cycledata.statecnt,0) > 0 then
                          for i = 1, strips[ss][p].controls[c].cycledata.statecnt do
                            local key = 'strips_'..s..'_'..p..'_controls_'..c..'_cycledata_'..i..'_'

                            strips[ss][p].controls[c].cycledata[i] = {val = tonumber(nz(GPES(key..'val',true),0)),
                                                                      dispval = nz(GPES(key..'dispval',true),'no disp val'),
                                                                      dv = GPES(key..'dispval',true)}
                            if strips[ss][p].controls[c].cycledata[i].dv == nil then
                              strips[ss][p].controls[c].cycledata[i].dv = strips[ss][p].controls[c].cycledata[i].dispval
                            end
                          end
                        end

                        --load control images - reshuffled to ensure no wasted slots between sessions
                        local iidx
                        local knob_sel = fidx[strips[ss][p].controls[c].ctl_info.fn]
                        if knob_sel then
                          strips[ss][p].controls[c].knob_select = knob_sel

                          if ctl_files[knob_sel].imageidx == nil then
                            image_count = F_limit(image_count + 1,0,image_max)
                            gfx.loadimg(image_count, paths.controls_path..ctl_files[knob_sel].fn)
                            iidx = image_count

                            strips[ss][p].controls[c].ctl_info.imageidx = iidx
                            ctl_files[knob_sel].imageidx = iidx
                          else
                            iidx = ctl_files[knob_sel].imageidx
                            strips[ss][p].controls[c].ctl_info.imageidx = iidx
                          end
                        else
                          --missing
                          strips[ss][p].controls[c].knob_select = -1
                          strips[ss][p].controls[c].ctl_info.imageidx = 1020
                        end
                      end
                    end

                    if gcnt > 0 then

                      for g = 1, gcnt do

                        local key = 'strips_'..s..'_'..p..'_graphics_'..g..'_'

                        strips[ss][p].graphics[g] = {
                                                    fn = GPES(key..'fn'),
                                                    imageidx = tonumber(GPES(key..'imageidx')),
                                                    x = tonumber(GPES(key..'x')),
                                                    y = tonumber(GPES(key..'y')),
                                                    w = tonumber(GPES(key..'w')),
                                                    h = tonumber(GPES(key..'h')),
                                                    scale = tonumber(GPES(key..'scale')),
                                                    id = deconvnum(GPES(key..'id',true)),
                                                    gfxtype = tonumber(nz(GPES(key..'gfxtype',true),lvar.gfxtype.img)),
                                                    font = {idx = tonumber(GPES(key..'font_idx',true)),
                                                            name = GPES(key..'font_name',true),
                                                            size = tonumber(GPES(key..'font_size',true)),
                                                            bold = tobool(GPES(key..'font_bold',true)),
                                                            italics = tobool(GPES(key..'font_italics',true)),
                                                            underline = tobool(GPES(key..'font_underline',true)),
                                                            vertical = tobool(GPES(key..'font_vertical',true)),
                                                            shadow = tobool(nz(GPES(key..'font_shadow',true),true)),
                                                            shadow_x = tonumber(nz(GPES(key..'font_shadowx',true),1)),
                                                            shadow_y = tonumber(nz(GPES(key..'font_shadowy',true),1)),
                                                            shadow_a = tonumber(nz(GPES(key..'font_shadowa',true),0.6))
                                                            },
                                                    text = GPES(key..'text',true),
                                                    text_col = GPES(key..'text_col',true),
                                                    poslock = tobool(nz(GPES(key..'poslock',true),false))
                                                   }
                        strips[ss][p].graphics[g].stretchw = tonumber(nz(GPES(key..'stretchw',true),strips[ss][p].graphics[g].w))
                        strips[ss][p].graphics[g].stretchh = tonumber(nz(GPES(key..'stretchh',true),strips[ss][p].graphics[g].h))
                        strips[ss][p].graphics[g].stretchmode = 1
                        strips[ss][p].graphics[g].edgesz = 8

                        --load graphics images
                        local iidx = LoadGraphics(strips[ss][p].graphics[g].fn)
                        if iidx then
                          strips[ss][p].graphics[g].imageidx = iidx
                        end

                      end
                    end
                  end
                  ss = ss + 1
                else
                  --not found
                  --strips[s] = nil
                end
              end
            end

          end

          PopulateTracks()
          Snapshots_INIT()
          local scnt = tonumber(nz(GPES('snapshots_count'),0))
          DBGOut('LoadData: snapshot count: '..tostring(scnt))

          if scnt and scnt > 0 then

            for s = 1, scnt do

              GUI_DrawMsgX(obj, gui, 'Loading Snapshot Data...', s, scnt)

              if tostring(v) == '0.93' then

                LoadSnapData(s)

              elseif tostring(v) >= '0.94' then

                LoadSnapData(s, data)

              else

                snapshots[s] = {}

                for p = 1, lvar.maxpage do

                  snapshots[s][p] = {}

                  local key = 'snap_strip_'..s..'_'..p..'_'
                  local sstcnt = tonumber(nz(GPES(key..'sstype_count',true),0))

                  if sstcnt > 0 then

                    for sst = 1, sstcnt do

                      if sst == 1 then
                        snapshots[s][p][sst] = {}

                        local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_'
                        local sscnt = tonumber(nz(GPES(key..'ss_count',true),0))
                        if sscnt > 0 then

                          for ss = 1, sscnt do
                            local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_snapshot_'..ss..'_'
                            local dcnt = tonumber(GPES(key..'data_count'))
                            snapshots[s][p][sst][ss] = {name = GPES(key..'name'),
                                                        data = {}}
                            for d = 1, dcnt do

                              local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_snapshot_'..ss..'_data_'..d..'_'

                              snapshots[s][p][sst][ss].data[d] = {c_id = tonumber(GPES(key..'cid')),
                                                                 ctl = tonumber(GPES(key..'ctl')),
                                                                 val = tonumber(GPES(key..'val')),
                                                                 dval = tonumber(GPES(key..'dval',true))}
                            end
                          end

                          --Snapshots_Check(s,p)
                        end
                      elseif sst > 1 then

                        local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_'
                        snapshots[s][p][sst] = {subsetname = GPES(key..'subsetname'), snapshot = {}, ctls = {}}

                        lvar.snapsubsets_table[sst] = snapshots[s][p][sst].subsetname

                        local sscnt = nz(tonumber(GPES(key..'ss_count')),0)
                        local ctlcnt = nz(tonumber(GPES(key..'ctl_count')),0)

                        if ctlcnt > 0 then
                          for ctl = 1, ctlcnt do

                            local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_ctl_'..ctl..'_'
                            snapshots[s][p][sst].ctls[ctl] = {c_id = tonumber(GPES(key..'cid')),
                                                              ctl = tonumber(GPES(key..'ctl'))}
                          end
                        end
                        if sscnt > 0 then
                          for ss = 1, sscnt do
                            local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_snapshot_'..ss..'_'
                            local dcnt = tonumber(GPES(key..'data_count'))
                            snapshots[s][p][sst].snapshot[ss] = {name = GPES(key..'name'),
                                                                 data = {}}
                            for d = 1, dcnt do

                              local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_snapshot_'..ss..'_data_'..d..'_'

                              snapshots[s][p][sst].snapshot[ss].data[d] = {c_id = tonumber(GPES(key..'cid')),
                                                                           ctl = tonumber(GPES(key..'ctl')),
                                                                           val = tonumber(GPES(key..'val')),
                                                                           dval = tonumber(GPES(key..'dval',true))}
                            end
                          end
                        end

                        --Snapshots_Check(s,p)
                      end

                      local key = 'snap_strip_'..s..'_'..p..'_type_'..sst..'_'
                      if snapshots[s][p][sst] then
                        snapshots[s][p][sst].selected = tonumber(GPES(key..'ss_selected',true))
                      end

                    end

                    --Snapshots_Check(s,p)
                  end
                end
              end

            end

            if track_select and tracks[track_select] and tracks[track_select].strip then
              local strip = tracks[track_select].strip
              if sstype_select and snapshots[strip] and snapshots[strip][page][sstype_select] and
                 snapshots[strip][page][sstype_select].selected then
                ss_select = snapshots[strip][page][sstype_select].selected
              end
            end
          end

          --XXY

          for s = 1, #strips do

            GUI_DrawMsgX(obj, gui, 'Loading Metalite Data...', s, #strips)

            if tostring(v) == '0.93' then

              LoadXXYData(s)

            elseif tostring(v) >= '0.94' then

              LoadXXYData(s, data)

            else

              for p = 1, lvar.maxpage do

                for sst = 1, #snapshots[s][p] do

                  local key = 'xxy_strip_'..s..'_'..p..'_type_'..sst..'_'
                  local ptcnt = tonumber(GPES(key..'pt_count',true))
                  if ptcnt then

                    XXY_INIT(s, p, sst)
                    for pt = 1, ptcnt do

                      local key = 'xxy_strip_'..s..'_'..p..'_type_'..sst..'_pt_'..pt..'_'
                      xxy[s][p][sst].points[pt] = {}
                      xxy[s][p][sst].points[pt].x = tonumber(GPES(key..'x'))
                      xxy[s][p][sst].points[pt].y = tonumber(GPES(key..'y'))
                      xxy[s][p][sst].points[pt].ss = tonumber(GPES(key..'ss'))

                    end

                  end

                end

              end
            end

          end

          if tostring(v) == '0.93' then
            LoadXXYPathData()
            faders, snapshot_fader, capture_fader = LoadFaders()
            if faders == nil then
              faders = Faders_INIT(true)
            end

          elseif tostring(v) >= '0.94' then

            LoadXXYPathData(data)
            faders, snapshot_fader, capture_fader = LoadFaders(data,'',_,true)
            if data['global_fadercnt'] then
              lvar.gfaders = LoadFaders(data,'global_',true)
            end
            if faders == nil then
              faders = Faders_INIT(true)
            end

            LoadMods(data)

            --if not lvar.dm_saveenabled then
            if not lvar.dm_switchload then
              LoadSwitchers(data)
            end
            
            LoadSK2Assign(data)
            
            --end
          end
        end
      else
        local status = PCALL_SaveData()
      end

      data = nil

      Switchers_Clean()

      LoadCompatibility(v, strips)

      --DBG('Total Load Time: '..reaper.time_precise() - t)
      infomsg = 'Total Load Time: '..round(reaper.time_precise() - t,2)..'s'
      DBGOut(infomsg)

      PopulateTracks() --must be called to link tracks to strips

    else
      --error with saved data
      local status = PCALL_SaveData()
      PopulateTracks() --must be called to link tracks to strips

      if lbxwin_dim then
        lbxwin_dim.w = lbxwin_dim.w or 800
        lbxwin_dim.h = lbxwin_dim.h or 450
      
        gfx1 = {main_w = lbxwin_dim.w,
                main_h = lbxwin_dim.h}
        Lokasenna_Window_At_Center(gfx1.main_w,gfx1.main_h,lbxwin_dim.x,lbxwin_dim.y)

      else
        local ww, wh = GPES('win_w',true), GPES('win_h',true)
        if tonumber(ww) ~= nil and tonumber(wh) ~= nil then
          gfx1 = {main_w = tonumber(ww) or 800,
                  main_h = tonumber(wh) or 450}
        else
          gfx1 = {main_w = 800,
                  main_h = 450}
        end
        Lokasenna_Window_At_Center(gfx1.main_w,gfx1.main_h)
        --gfx.dock(dockstate)
      end

    end
    if track_select then
      ChangeTrack(track_select)
      --if settings_followselectedtrack then
        local tr = GetTrack(track_select)
        if tr then
          --reaper.SetOnlyTrackSelected(tr)
        end
      --end
    end
    if tracks and tracks[track_select] and tracks[track_select].strip and strips[tracks[track_select].strip] then
    --if tracks[track_select].strip and strips[tracks[track_select].strip] then
      surface_offset.x = tonumber(strips[tracks[track_select].strip][page].surface_x)
      surface_offset.y = tonumber(strips[tracks[track_select].strip][page].surface_y)
    end
    --[[local ww = gfx1.main_w-(plist_w+2)
    if surface_size.w < ww then
      surface_offset.x = -math.floor((ww - surface_size.w)/2)
    end]]
    GUI_DrawCtlBitmap()

    StoreSnapshotControls()
    ZeroProjectFlags()

    if track_select and track_select == LBX_GTRACK then
      gpage = true
      gpage_otrackselect = -1
    end

    force_resize = true
    lupd.update_gfx = true
    lastprojdirty = 0
    LASTPROJECTID = PROJECTID
    lastprojname = GetProjectName()
    LOADEDDATAFILE = LDF

    TrackLabelCheck()
    lvar.readpeaks = PopReadPeaks()

    --lvar.cids = CheckAllCids()
    
  end

  function LoadCompatibility(v, strips)

    if v == nil or (tonumber(v) ~= nil and tonumber(v) < 0.95) then

      if strips and #strips > 0 then
        for s = 1, #strips do
          for p = 1, lvar.maxpage do

            --compatibility


            local ctls = strips[s][p].controls
            if ctls and #ctls > 0 then

              for c = 1, #ctls do
                if ctls[c].lcflag == nil then
                  gfx.setfont(1, ctls[c].font, gui.fontsz_knob + ctls[c].textsize-4)
                  local _, th = gfx.measurestr('|')
                  ctls[c].textoff = ctls[c].textoff - math.floor(th/2)
                  ctls[c].lcflag = true
                end
              end

            end
          end
        end
      end
    end

  end
  
  function LoadTrackStrips()

    local fn = paths.resource_path..'trackstrips.txt'
    if reaper.file_exists(fn) then
      local flines = io.lines
      local data = {}
      local match = string.match
    
      for line in flines(fn) do
        local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          data[idx] = val
        end
      end
      
      for trnm, val in pairs(data) do
      
        if not lvar.trackstrips[trnm] then
          lvar.trackstrips[trnm] = {}
        end
        local p, stripnm = string.match(val,'%[(.-)%](.*)')
        if p then
          lvar.trackstrips[trnm][tonumber(p)] = stripnm
        end
      end
      
      --Scan tracks
      TrackLabelCheck()
      
    end  
  end

  function SaveTrackStrips()

    local fn = paths.resource_path..'trackstrips.txt'
    local DELETE=true
    local file

    if reaper.file_exists(fn) then

    end

    if DELETE then
      file=io.open(fn,"w")
      for trnm, val in pairs(lvar.trackstrips) do
        for p = 1, lvar.maxpage do
          if val[p] then
            local str = '['..trnm..']['..string.format('%i',p)..']'..val[p]
            file:write(str..'\n')
          end
        end
      end
      file:close()
    end
    
  end
  
  function LoadLocation()
    if reaper.JS_Window_SetLong then
      local fn = paths.resource_path..'location.txt'
      if reaper.file_exists(fn) then
        local flines = io.lines
        local data = {}
        local match = string.match

        for line in flines(fn) do
          local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
          if idx then
            data[idx] = val
          end
        end

        local x = tonumber(data['x'])
        local y = tonumber(data['y'])
        local w = tonumber(data['w'])
        local h = tonumber(data['h'])
        local frameless = tonumber(data['frameless'])

        local win = reaper.JS_Window_Find('- LBX Stripper -', true)
        if win then
          if frameless == 1 then
            local style = reaper.JS_Window_GetLong(win, 'STYLE')
            if style then
              style = style & (0xFFFFFFFF - 0x00C40000)
              reaper.JS_Window_SetLong(win, "STYLE", style)
            end
          end
          if x and y and w and h then
            reaper.JS_Window_SetPosition(win, x, y, w, h)
          end
        end
      end
    end
  end

  function xGES(key, nilallowed, data)
    val = data[key]
    --DBG(key..'  '..tostring(val))
    if nilallowed then
      if val == '' or val == 'nil' then
        val = nil
      end
    end
    return val
  end

  function LoadSettings_PreInit()
    local GES = GES
    local data

    if lvar.savesettingstofile then
      if reaper.file_exists(file_settings) then

        data = {}

        GES = xGES

        for line in io.lines(file_settings) do
          local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
          if idx then
            val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
            data[idx] = val
          end
        end

      end

    end
    lvar.sortcontrols = tobool(nz(GES('sortcontrols',true,data),lvar.sortcontrols))
  
    return data
  end
  
  function LoadSettings(preloadeddata)

    local t = reaper.time_precise()

    local GES = GES
    local data

    if lvar.savesettingstofile then
      if preloadeddata then
        data = preloadeddata
        GES = xGES
      else
        if reaper.file_exists(file_settings) then
  
          data = {}
  
          GES = xGES
  
          for line in io.lines(file_settings) do
            local idx, val = string.match(line,'%[(.-)%](.*)') --decipher(line)
            if idx then
              val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
              data[idx] = val
            end
          end
  
        end
      end
    end
    lvar.livemode = tonumber(nz(GES('livemode',0,data),lvar.livemode))
    lvar.glivemode = lvar.livemode

    lvar.zoom = tonumber(nz(GES('surface_zoom',0,data),lvar.zoom))  
    --lvar.enablelargegui = tobool(nz(GES('enablelargegui',true,data),lvar.enablelargegui))
    file_bgimage = nz(GES('file_bgimage',true,data),file_bgimage)
    lvar.mmov_bgimgon = tobool(nz(GES('mmov_bgimgon',true,data),lvar.mmov_bgimgon))
    lvar.bgstretch = tobool(nz(GES('bgstretch',true,data),lvar.bgstretch))
    lvar.bgbright = tonumber(nz(GES('bgbright',true,data),lvar.bgbright))
    lvar.bgcentred = tobool(nz(GES('bgcentred',true,data),lvar.bgcentred))
    lvar.bg_coffx = tonumber(nz(GES('bg_coffx',true,data),lvar.bg_coffx or 0))
    lvar.bg_coffy = tonumber(nz(GES('bg_coffy',true,data),lvar.bg_coffy or 0))
    
    lvar.livebg = tobool(nz(GES('livebg',true,data),lvar.livebg))
    lvar.mm_disablenonpoppedctls = tobool(nz(GES('mm_disablenonpoppedctls',true,data),lvar.mm_disablenonpoppedctls))
    lvar.showpoponly = tobool(nz(GES('showpoponly',true,data),lvar.showpoponly))
    lvar.dm_singlepopup = tobool(nz(GES('dm_singlepopup',true,data),lvar.dm_singlepopup))
    lvar.popout_autoarrange = tobool(nz(GES('popout_autoarrange',true,data),lvar.popout_autoarrange))
    lvar.autoarrange_activefx = tobool(nz(GES('autoarrange_activefx',true,data),lvar.autoarrange_activefx))
    lvar.popout_autoarrange_hideswitchers = tobool(nz(GES('popout_autoarrange_hideswitchers',true,data),lvar.popout_autoarrange_hideswitchers))
    lvar.popout_autoarrange_xgap = tonumber(nz(GES('popout_autoarrange_xgap',true,data),lvar.popout_autoarrange_xgap or 0))
    lvar.popout_autoarrange_ygap = tonumber(nz(GES('popout_autoarrange_ygap',true,data),lvar.popout_autoarrange_ygap or 0))
    
    lvar.mmtouch = tobool(nz(GES('mmtouch',true,data),lvar.mmtouch))
    lvar.dm_autorefresh = tobool(nz(GES('dm_autorefresh',true,data),lvar.dm_autorefresh))
    lvar.dm_maxvistracks = tonumber(nz(GES('dm_maxvistracks',true,data),lvar.dm_maxvistracks))
    lvar.dm_showtrackname = tobool(nz(GES('dm_showtrackname',true,data),lvar.dm_showtrackname))
    lvar.dm_fixtrack = tonumber(nz(GES('dm_fixtrack',true,data),lvar.dm_fixtrack))
    
    lvar.trmix_panelsz = tonumber(nz(GES('trmix_panelsz',true,data),lvar.trmix_panelsz))
    lvar.dm_trackslocked = tobool(nz(GES('dm_trackslocked',true,data),lvar.dm_trackslocked))

    lvar.trmix_sndpnl_show = tonumber(nz(tonumber(GES('trmix_sndpnl_show',true,data)),lvar.trmix_sndpnl_show))
    lvar.trmix_show = tobool(nz(GES('trmix_show',true,data),lvar.trmix_show))
    lvar.trmix_h = tonumber(nz(GES('trmix_h',true,data),lvar.trmix_h))
    lvar.trmix_seth = tonumber(nz(GES('trmix_seth',true,data),lvar.trmix_seth))
    lvar.mmov_tint = tonumber(nz(GES('mmov_tint',true,data),lvar.mmov_tint))

    lvar.limitmw = tobool(nz(GES('limitmw',true,data),lvar.limitmw))
    lvar.sliderzoom = tobool(nz(GES('sliderzoom',true,data),lvar.sliderzoom))

    lvar.Mac_revcol = tobool(nz(GES('mac_revcol',true,data),lvar.Mac_revcol))
    --lvar.sortcontrols = tobool(nz(GES('sortcontrols',true,data),lvar.sortcontrols))
    lvar.analyzer.script = zn(GES('analyzerscript',true,data))

    lvar.dm_padx = tonumber(nz(GES('dm_padx',true,data),lvar.dm_padx))
    lvar.dm_pady = tonumber(nz(GES('dm_pady',true,data),lvar.dm_pady))

    lvar.sb_folbtn_show = tobool(nz(GES('sb_folbtn_show',true,data),lvar.sb_folbtn_show))

    skin_select = nz(GES('skin',true,data),skin_select)
    settings_saveallfxinststrip = tobool(nz(GES('saveallfxinststrip',true,data),settings_saveallfxinststrip))
    settings_followselectedtrack = tobool(nz(GES('followselectedtrack',true,data),settings_followselectedtrack))
    settings_disablesendchecks = tobool(nz(GES('disablesendchecks',false,data),settings_disablesendchecks))
    settings_updatefreq = tonumber(nz(GES('updatefreq',true,data),settings_updatefreq))
    settings_mousewheelknob = tobool(nz(GES('mousewheelknob',true,data),settings_mousewheelknob))
    lvar.sliderxy = tobool(nz(GES('sliderxy',true,data),lvar.sliderxy))
    dockstate = nz(GES('dockstate',true,data),0)

    local wx = GES('winx',true,data)
    local wy = GES('winy',true,data)
    local ww = GES('winw',true,data)
    local wh = GES('winh',true,data)
    if wx and wy and ww and wh then
      lbxwin_dim = {x = tonumber(wx), y = tonumber(wy), w = tonumber(ww), h = tonumber(wh)}
    end

    local fxl = GES('fxpos_l',true,data)
    local fxt = GES('fxpos_t',true,data)
    local fxw = GES('fxpos_w',true,data)
    local fxh = GES('fxpos_h',true,data)
    if fxl and fxt and fxw and fxh then
      lvar.fxpos = {l = tonumber(fxl), t = tonumber(fxt), w = tonumber(fxw), h = tonumber(fxh)}
    end

    lockx = tobool(nz(GES('lockx',true,data),false))
    locky = tobool(nz(GES('locky',true,data),false))
    lockw = tonumber(nz(GES('lockw',true,data),400))
    lockh = tonumber(nz(GES('lockh',true,data),400))

    lvar.lastrenderfolder = GES('renderfolder',true,data)

    lvar.ctlbrowserfav_select = tonumber(nz(GES('ctlbrowserfav_select',true,data),lvar.ctlbrowserfav_select))
    lvar.ctlbrowser_offs = tonumber(nz(GES('ctlbrowser_offs',true,data),lvar.ctlbrowser_offs))
    cbi_filter = tonumber(nz(GES('cbi_filter',true,data),cbi_filter))
    lvar.ctlbrowser_docked = tobool(nz(GES('ctlbrowser_docked',true,data),lvar.ctlbrowser_docked))
    lvar.ctlbrowser_docked_w = tonumber(nz(GES('ctlbrowser_docked_w',true,data),lvar.ctlbrowser_docked_w))

    cbi_offset = 0
    --cbi_filter = -2
    PopulateCtlBrowser_Cbi()

    auto_delay = tonumber(nz(GES('auto_sensitivity',true,data),auto_delay))
    tb_butt_h = tonumber(nz(GES('tb_butt_h',true,data),tb_butt_h))
    pnl_scale = tonumber(nz(GES('pnl_scale',true,data),pnl_scale))

    fontscale = tonumber(nz(GES('fontscale',true,data),fontscale))
    tb_fontscale = tonumber(nz(GES('tb_fontscale',true,data),tb_fontscale))
    lst_fontscale = tonumber(nz(GES('lst_fontscale',true,data),lst_fontscale))

    lvar.addstrip_keepseparateids = tobool(nz(GES('addstrip_sepids',true,data),lvar.addstrip_keepseparateids))

    settings_swapctrlclick = tobool(nz(GES('swapctrlclick',true,data),settings_swapctrlclick))
    settings_showbars = tobool(nz(GES('showbars',true,data),settings_showbars))
    settings_insertdefaultoneverytrack = tobool(nz(GES('insertdefstripontrack',true,data),settings_insertdefaultoneverytrack))
    settings_insertdefaultoneverypage = tobool(nz(GES('insertdefstriponpage',true,data),settings_insertdefaultoneverypage))
    settings_snaplistbgcol = tostring(nz(GES('snaplistbgcol',true,data),settings_snaplistbgcol))
    lvar.gridcolor = tostring(nz(GES('gridcolor',true,data),lvar.gridcolor))
    lvar.showtakeover = tobool(nz(GES('showtakeover',true,data),lvar.showtakeover))
    lvar.mousefadermode = tonumber(nz(GES('mousefadermode',true,data),lvar.mousefadermode))

    lvar.bgmatchestrackcolour = tonumber(nz(GES('bgmatchestrackcolour',true,data),lvar.bgmatchestrackcolour))

    lvar.mixmodedir = tonumber(nz(GES('mixmodedir',0,data),lvar.mixmodedir))
    lvar.mixmodealign = tonumber(nz(GES('mixmodealign',0,data),lvar.mixmodealign))
    lvar.mmov_show = tobool(nz(GES('mmov_show',0,data),lvar.mmov_show))
    lvar.mmov_vsize = tonumber(nz(GES('mmov_vsize',0,data),lvar.mmov_vsize))
    if lvar.mmov_show == true then
      lvar.mmov_offs = math.floor((lvar.mmov_vsize + lvar.mmov_pad*2)/2)
    else
      lvar.mmov_offs = 0
    end
    lvar.trbtns_show = tobool(nz(GES('trbtns_show',0,data),lvar.trbtns_show))
    lvar.trbtns_size = tonumber(nz(GES('trbtns_size',0,data),lvar.trbtns_size))
    lvar.trmixbtns_size = tonumber(nz(GES('trmixbtns_size',0,data),lvar.trmixbtns_size))
    lvar.trbtns_meters = tobool(nz(GES('trbtns_meters',0,data),lvar.trbtns_meters))
    lvar.trbtns_pkcolor = nz(GES('trbtns_pkcolor',0,data),lvar.trbtns_pkcolor)
    lvar.mm_fadepop = tonumber(nz(GES('mm_fadepop',0,data),lvar.mm_fadepop))
    lvar.mm_fadepopamt = tonumber(nz(GES('mm_fadepopamt',0,data),lvar.mm_fadepopamt))

    lvar.enablegfxshadows = tobool(nz(GES('shadow_enabled',true,data),lvar.enablegfxshadows))
    if lvar.enablegfxshadows then
      lvar.shadowmax = lvar.shadowmax_p
    else
      lvar.shadowmax = 0
    end

    lvar.shadow_offsx = tonumber(nz(GES('shadow_sz',true,data),lvar.shadow_offsx))
    lvar.shadow_alpha = tonumber(nz(GES('shadow_alpha',true,data),lvar.shadow_alpha))
    lvar.shadow_feather = tonumber(nz(GES('shadow_feather',true,data),lvar.shadow_feather))

    settings_savedatainprojectfolder = tobool(nz(GES('savedatainprojectfolder',true,data),settings_savedatainprojectfolder))
    save_subfolder = nz(GES('save_subfolder',true,data),save_subfolder)
    settings_createbackuponmanualsave = tobool(nz(GES('createbackup',true,data),settings_createbackuponmanualsave))
    settings_backupduringsave = tobool(nz(GES('createtmpbackup',true,data),settings_backupduringsave))

    settings_usectlbitmap = tobool(GES('usectlbitmap',true,data)) or true
    lvar.ctlupdate_rr = tonumber(nz(GES('ctlupdate_rr',true,data),lvar.ctlupdate_rr))
    settings_macroeditmonitor = tobool(nz(GES('macroeditmonitor',true,data),settings_macroeditmonitor))
    hide_topbar = tobool(nz(GES('hide_topbar',true,data),hide_topbar))
    settings_hideeditbaronnewproject = tobool(nz(GES('hide_editbar',true,data),settings_hideeditbaronnewproject))
    settings_locksurfaceonnewproject = tobool(nz(GES('lock_surface',true,data),settings_locksurfaceonnewproject))
    settings_showminimaltopbar = tobool(nz(GES('settings_showminimaltopbar',true,data),settings_showminimaltopbar))
    backcol = nz(GES('backcol',true,data),'16 16 16')
    nebscanboot_file = zn(GES('nebscanboot',true,data),nil)
    lvar.hidecursordrag = tobool(nz(GES('hidecursordrag',true,data),lvar.hidecursordrag))
    settings_touchmode = tobool(nz(GES('settings_touchmode',true,data),settings_touchmode))
    lvar.TSM_active = settings_touchmode
    settings_touchFB = tobool(nz(GES('settings_touchfb',true,data),settings_touchFB))
    settings_trackchangemidi = tobool(nz(GES('settings_trackchangemidi',true,data),settings_trackchangemidi))
    settings_savefaderboxassinsnapshots = tobool(nz(GES('settings_savefaderboxassinsnapshots',true,data),settings_savefaderboxassinsnapshots))
    settings_savemodsinsnapshots = tobool(nz(GES('settings_savemodsinsnapshots',true,data),settings_savemodsinsnapshots))
    settings_showfaderassignments = tobool(nz(GES('settings_showfaderassignments',false,data),settings_showfaderassignments))
    --[[settings_stripautosnap = tobool(nz(GES('settings_stripautosnap',false,data),settings_stripautosnap))
    autosnap_rowheight = tonumber(nz(GES('autosnap_rowheight',true,data),autosnap_rowheight))
    autosnap_itemgap = tonumber(nz(GES('autosnap_itemgap',true,data),autosnap_itemgap))
    autosnap_itemgapmax = tonumber(nz(GES('autosnap_itemgapmax',true,data),autosnap_itemgapmax))
    gallery_itemgap = tonumber(nz(GES('gallery_itemgap',true,data),gallery_itemgap))]]
    
    sg_view = --[[tonumber(nz(GES('stripgallery_view',true,data),]]stripgallery_view--))

    settings_disablekeysonlockedsurface = tobool(nz(GES('settings_disablekeysonlockedsurface',false,data),settings_disablekeysonlockedsurface))
    settings_deletefxwithstrip = tobool(nz(GES('settings_deletefxwithstrip',false,data),settings_deletefxwithstrip))
    lvar.forcestrippluginguisclosed = tobool(nz(GES('forcestrippluginguisclosed',false,data),lvar.forcestrippluginguisclosed))
    
    settings_morphfaderassignedctls = tobool(nz(GES('settings_morphfaderassignedctls',true,data),settings_morphfaderassignedctls))
    settings_followsnapshot = tobool(nz(GES('settings_followsnapshot',true,data),settings_followsnapshot))
    settings_alwaysrunmods = tobool(nz(GES('settings_alwaysrunmods',true,data),settings_alwaysrunmods))
    settings_showmorphpop = tobool(nz(GES('settings_showmorphpop',true,data),settings_showmorphpop))
    settings_groupsel = tobool(nz(GES('settings_groupsel',true,data),settings_groupsel))
    settings_savesnapafterselected = tobool(nz(GES('settings_savesnapafterselected',true,data),settings_savesnapafterselected))
    settings_drawbglabelsontop = tobool(nz(GES('settings_drawbglabelsontop',true,data),settings_drawbglabelsontop))
    autosnap_itemgapmax = tonumber(nz(GES('autosnap_itemgapmax',true,data),autosnap_itemgapmax))
    settings_ssdock = tobool(nz(GES('settings_ssdock',true,data),settings_ssdock))
    settings_sbdock = tobool(nz(GES('settings_sbdock',true,data),settings_sbdock))
    settings_hideplugnotfound = tobool(nz(GES('settings_hideplugnotfound',true,data),settings_hideplugnotfound))
    settings_enablednu = tobool(nz(GES('settings_enablednu',true,data),settings_enablednu))
    lvar.snapcapture_midi_dt = tobool(nz(GES('snapcapture_midi_dt',true,data),lvar.snapcapture_midi_dt))

    show_stripbrowser = tobool(nz(GES('show_stripbrowser',true,data),show_stripbrowser))
    sbwin.x = tonumber(nz(GES('sbwin_x',true,data),sbwin.x))
    sbwin.y = tonumber(nz(GES('sbwin_y',true,data),sbwin.y))
    sbwin.w = tonumber(nz(GES('sbwin_w',true,data),sbwin.w))
    sbwin.h = tonumber(nz(GES('sbwin_h',true,data),sbwin.h))
    lvar.stripbrowser.minw = tonumber(nz(GES('stripbrowser_minw',true,data),lvar.stripbrowser.minw))
    lvar.stripbrowser.minh = tonumber(nz(GES('stripbrowser_minh',true,data),lvar.stripbrowser.minh))
    lvar.stripbrowser.dockpos = tonumber(nz(GES('stripbrowser_dockpos',true,data),lvar.stripbrowser.dockpos))
    lvar.stripbrowser.showlabel = tobool(nz(GES('stripbrowser_showlabel',true,data),lvar.stripbrowser.showlabel))
    lvar.stripbrowser.tsz = tonumber(nz(GES('stripbrowser_tsz',true,data),lvar.stripbrowser.tsz))
    lvar.stripbrowser.fullscreen = tobool(nz(GES('stripbrowser_fullscreen',true,data),lvar.stripbrowser.fullscreen))
    lvar.stripbrowser.type2 = tobool(nz(GES('stripbrowser_type2',true,data),lvar.stripbrowser.type2))
    if lvar.stripbrowser.fullscreen then
      show_stripbrowser = false
    end

    lvar.macrosech = tonumber(nz(GES('macrosech',true,data),lvar.macrosech))
    undo.max = tonumber(nz(GES('maxundo',true,data),undo.max))

    settings_moddock = tobool(nz(GES('settings_moddock',true,data),settings_moddock))
    modwinsz = {}
    modwinsz.x = tonumber(nz(GES('modwin_x',true,data),0))
    modwinsz.y = tonumber(nz(GES('modwin_y',true,data),0))
    modwinsz.w = tonumber(nz(GES('modwin_w',true,data),500))
    modwinsz.h = tonumber(nz(GES('modwin_h',true,data),300))
    modwinsz.minimized = tobool(nz(GES('modwin_min',true,data),false))
    show_lfoedit = tobool(nz(GES('modwin_show',true,data),false))

    modulator_cnt = tonumber(nz(GES('modulator_cnt',true,data),modulator_cnt))
    lvar.mutate_settings.mutate_max = tonumber(nz(GES('mutate_max',true,data),lvar.mutate_settings.mutate_max))
    settings_pagescrolldir = tonumber(nz(GES('settings_pagescrolldir',true,data),settings_pagescrolldir))

    settings_dragmode = tobool(nz(GES('settings_dragmode',true,data),settings_dragmode))
    settings_runstartbat = tobool(nz(GES('settings_runstartbat',true,data),settings_runstartbat))

    if settings_hideeditbaronnewproject then
      plist_w = 0
      show_editbar = false
    else
      plist_w = oplist_w
      show_editbar = true
    end

    if settings_locksurfaceonnewproject then
      settings_locksurface = true
    end

    local sd = tonumber(GES('strip_default',true,data))
    local sdf = tonumber(GES('stripfol_default',true,data))
    if sd and sdf then
      strip_default = {stripfol_select = sdf, strip_select = sd}
    end

    local sd = tonumber(GES('strip_default_mast',true,data))
    local sdf = tonumber(GES('stripfol_default_mast',true,data))
    if sd and sdf then
      strip_default_mast = {stripfol_select = sdf, strip_select = sd}
    end

    local sd = tonumber(GES('strip_default_glob',true,data))
    local sdf = tonumber(GES('stripfol_default_glob',true,data))
    if sd and sdf then
      strip_default_glob = {stripfol_select = sdf, strip_select = sd}
    end

    lvar.striploadoverride = zn(GES('striploadoverride',true,data))
    if lvar.striploadoverride then
      lvar.striploadoverride_active = true
    end

    --DBG('load '..reaper.time_precise()-t)

    LoadFavStrips()
    LoadMixerSettings()
    LoadDefSwitchFormat()

  end

  function LoadDefSwitchFormat()
    lvar.extswitch_format = {knob = def_switchctl,
                             knob_fn = 'Switcher.png',
                             show_paramname = true,
                             textoff = 1,
                             textoffx = 0,
                             textsize = 2,
                             textcol = '200 200 200',
                             scale = 1,
                             adjust_active = false,
                             adjust_bright = 255,
                             adjust_contrast = 255,
                             adjust_r = 255,
                             adjust_g = 255,
                             adjust_b = 255}

    local load_path=paths.resource_path
    local fn=load_path.."switcher.txt"

    local tmp = {}
    if reaper.file_exists(fn) then
      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      tmp = unpickle(content)
      if tmp then

        local fnd = 0
        for k = 0, #ctl_files do
          if ctl_files[k].fn == tmp.knob_fn then
            --DBG(ctl_files[k].fn..'  '..tmp.knob_fn)
            --DBG(tmp.knob..'  '..k)
            --tmp.knob_fn = ctl_files[k].fn
            tmp.knob = k
            fnd = 1
            break
          end
        end
        if fnd == 1 then
          lvar.extswitch_format = tmp
        end
      end
    end
  end

  function SaveDefSwitchFormat(switchid, ctl)
    if ctl then
      lvar.extswitch_format = {knob = ctl.knob_select,
                               knob_fn = ctl.ctl_info.fn,
                               show_paramname = ctl.show_paramname,
                               textoff = ctl.textoff,
                               textoffx = ctl.textoffx,
                               textsize = ctl.textsize,
                               textcol = ctl.textcol,
                               scale = ctl.scale,
                               limittext = ctl.limittext,
                               textflags = ctl.textflags,
                               wwtext = ctl.wwtext,
                               font = ctl.font or fontname_def,
                               adjust_active = ctl.adjust_active,
                               adjust_bright = 255,
                               adjust_contrast = 255,
                               adjust_r = 255,
                               adjust_g = 255,
                               adjust_b = 255}
      if ctl.adjust then
        lvar.extswitch_format.adjust_bright = ctl.adjust.bright
        lvar.extswitch_format.adjust_contrast = ctl.adjust.contrast
        lvar.extswitch_format.adjust_r = ctl.adjust.r
        lvar.extswitch_format.adjust_g = ctl.adjust.g
        lvar.extswitch_format.adjust_b = ctl.adjust.b
      end

      local save_path=paths.resource_path
      local fn=save_path.."switcher.txt"

      local DELETE=true
      local file

      if reaper.file_exists(fn) then

      end
      if DELETE then
        file=io.open(fn,"w")
        local pickled_table=pickle(lvar.extswitch_format)
        file:write(pickled_table)
        file:close()
      end

    end
  end

  function ClearSettings()
    --reaper.DeleteExtState(SCRIPT)
    local SCRIPT = lvar.SCRIPT
    reaper.DeleteExtState(SCRIPT,'saveallfxinststrip', true)
    reaper.DeleteExtState(SCRIPT,'followselectedtrack', true)
    reaper.DeleteExtState(SCRIPT,'disablesendchecks', true)
    reaper.DeleteExtState(SCRIPT,'updatefreq', true)
    reaper.DeleteExtState(SCRIPT,'mousewheelknob', true)
    reaper.DeleteExtState(SCRIPT,'dockstate', true)
    reaper.DeleteExtState(SCRIPT,'lockx', true)
    reaper.DeleteExtState(SCRIPT,'locky', true)
    reaper.DeleteExtState(SCRIPT,'lockw', true)
    reaper.DeleteExtState(SCRIPT,'lockh', true)
    reaper.DeleteExtState(SCRIPT,'auto_sensitivity', true)
    reaper.DeleteExtState(SCRIPT,'swapctrlclick', true)
    reaper.DeleteExtState(SCRIPT,'showbars',true)
    reaper.DeleteExtState(SCRIPT,'insertdefstripontrack',true)
    reaper.DeleteExtState(SCRIPT,'insertdefstriponpage',true)
    reaper.DeleteExtState(SCRIPT,'snaplistbgcol',true)

    reaper.DeleteExtState(SCRIPT,'savedatainprojectfolder',true)
    reaper.DeleteExtState(SCRIPT,'save_subfolder',true)
    reaper.DeleteExtState(SCRIPT,'createbackup',true)

    reaper.DeleteExtState(SCRIPT,'usectlbitmap',true)
    reaper.DeleteExtState(SCRIPT,'macroeditmonitor',true)
    reaper.DeleteExtState(SCRIPT,'hide_topbar',true)
    reaper.DeleteExtState(SCRIPT,'settings_showminimaltopbar',true)
    reaper.DeleteExtState(SCRIPT,'hide_editbar',true)
    reaper.DeleteExtState(SCRIPT,'lock_surface',true)
    reaper.DeleteExtState(SCRIPT,'backcol',true)

    reaper.DeleteExtState(SCRIPT,'strip_default',true)
    reaper.DeleteExtState(SCRIPT,'stripfol_default',true)
    reaper.DeleteExtState(SCRIPT,'strip_default_mast',true)
    reaper.DeleteExtState(SCRIPT,'stripfol_default_mast',true)
    reaper.DeleteExtState(SCRIPT,'strip_default_glob',true)
    reaper.DeleteExtState(SCRIPT,'stripfol_default_glob',true)
  end

  function xSetExtState(file,key,val)
    file:write('['..key..']'..(val or '')..'\n')
  end

  function SaveSettings()
    local SCRIPT = lvar.SCRIPT

    local t = reaper.time_precise()

    --[[if #lvar.dm_trackbtns > 0 then
      reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_count',#lvar.dm_trackbtns)
      for i = 1, #lvar.dm_trackbtns do
        local key = string.format('%i',i)
        reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_guid_'..key, lvar.dm_trackbtns[i].guid)
        reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_trn_'..key, lvar.dm_trackbtns[i].trn)
      end
    end]]
    local SetExtState = reaper.SetExtState
    local file
    if lvar.savesettingstofile then
      SetExtState = xSetExtState
      file=io.open(file_settings,"w")
      SCRIPT = file
    end

    SetExtState(SCRIPT,'surface_zoom',tostring(lvar.zoom), true)                              

    SetExtState(SCRIPT,'file_bgimage',nz(file_bgimage,''), true)
    SetExtState(SCRIPT,'mmov_bgimgon',tostring(lvar.mmov_bgimgon), true)
    SetExtState(SCRIPT,'bgstretch',tostring(lvar.bgstretch), true)
    SetExtState(SCRIPT,'bgbright',tostring(lvar.bgbright), true)
    SetExtState(SCRIPT,'bgcentred',tostring(lvar.bgcentred), true)
    SetExtState(SCRIPT,'bg_coffx',tostring(lvar.bg_coffx or 0), true)
    SetExtState(SCRIPT,'bg_coffy',tostring(lvar.bg_coffy or 0), true)
    
    SetExtState(SCRIPT,'livebg',tostring(lvar.livebg), true)
    SetExtState(SCRIPT,'mm_disablenonpoppedctls',tostring(lvar.mm_disablenonpoppedctls), true)
    SetExtState(SCRIPT,'showpoponly',tostring(lvar.showpoponly), true)
    SetExtState(SCRIPT,'dm_singlepopup',tostring(lvar.dm_singlepopup), true)
    SetExtState(SCRIPT,'popout_autoarrange',tostring(lvar.popout_autoarrange), true)
    SetExtState(SCRIPT,'autoarrange_activefx',tostring(lvar.autoarrange_activefx), true)
    SetExtState(SCRIPT,'popout_autoarrange_hideswitchers',tostring(lvar.popout_autoarrange_hideswitchers), true)
    SetExtState(SCRIPT,'popout_autoarrange_xgap',tostring(lvar.popout_autoarrange_xgap), true)
    SetExtState(SCRIPT,'popout_autoarrange_ygap',tostring(lvar.popout_autoarrange_ygap), true)
    
    SetExtState(SCRIPT,'mmtouch',tostring(lvar.mmtouch), true)
    SetExtState(SCRIPT,'dm_autorefresh',tostring(lvar.dm_autorefresh), true)
    SetExtState(SCRIPT,'dm_padx',tostring(lvar.dm_padx), true)
    SetExtState(SCRIPT,'dm_pady',tostring(lvar.dm_pady), true)
    SetExtState(SCRIPT,'dm_maxvistracks',tostring(lvar.dm_maxvistracks), true)
    SetExtState(SCRIPT,'dm_showtrackname',tostring(lvar.dm_showtrackname), true)
    SetExtState(SCRIPT,'dm_fixtrack',tostring(lvar.dm_fixtrack), true)
    SetExtState(SCRIPT,'trmix_panelsz',tostring(lvar.trmix_panelsz), true)
    SetExtState(SCRIPT,'dm_trackslocked',tostring(lvar.dm_trackslocked), true)

    SetExtState(SCRIPT,'trmix_sndpnl_show',tostring(lvar.trmix_sndpnl_show), true)
    SetExtState(SCRIPT,'trmix_show',tostring(lvar.trmix_show), true)
    SetExtState(SCRIPT,'trmix_h',tostring(lvar.trmix_h), true)
    SetExtState(SCRIPT,'trmix_seth',tostring(lvar.trmix_seth), true)
    SetExtState(SCRIPT,'mmov_tint',tostring(lvar.mmov_tint), true)

    SetExtState(SCRIPT,'analyzerscript',nz(lvar.analyzer.script,''), true)

    SetExtState(SCRIPT,'sb_folbtn_show',tostring(lvar.sb_folbtn_show), true)

    SetExtState(SCRIPT,'skin',tostring(skin_select), true)
    SetExtState(SCRIPT,'saveallfxinststrip',tostring(settings_saveallfxinststrip), true)
    SetExtState(SCRIPT,'followselectedtrack',tostring(settings_followselectedtrack), true)
    SetExtState(SCRIPT,'disablesendchecks',tostring(settings_disablesendchecks), true)
    SetExtState(SCRIPT,'updatefreq',settings_updatefreq, true)
    SetExtState(SCRIPT,'mousewheelknob',tostring(settings_mousewheelknob), true)
    SetExtState(SCRIPT,'sliderxy',tostring(lvar.sliderxy), true)
    local d,wx,wy,ww,wh = gfx.dock(-1,-1,-1,-1,-1)

    if wx and wy and ww and wh then
      SetExtState(SCRIPT,'winx',wx, true)
      SetExtState(SCRIPT,'winy',wy, true)
      SetExtState(SCRIPT,'winw',ww, true)
      SetExtState(SCRIPT,'winh',wh, true)
    end

    SetExtState(SCRIPT,'dockstate',d, true)
    SetExtState(SCRIPT,'lockx',tostring(lockx), true)
    SetExtState(SCRIPT,'locky',tostring(locky), true)
    SetExtState(SCRIPT,'lockw',tostring(lockw), true)
    SetExtState(SCRIPT,'lockh',tostring(lockh), true)

    --DBG(lvar.ctlbrowserfav_select)
    SetExtState(SCRIPT,'ctlbrowserfav_select',tostring(nz(lvar.ctlbrowserfav_select, '')), true)
    SetExtState(SCRIPT,'ctlbrowser_offs',tostring(nz(lvar.ctlbrowser_offs,'')), true)
    SetExtState(SCRIPT,'cbi_filter',tostring(nz(cbi_filter,-1)), true)
    SetExtState(SCRIPT,'ctlbrowser_docked',tostring(lvar.ctlbrowser_docked), true)
    SetExtState(SCRIPT,'ctlbrowser_docked_w',tostring(nz(lvar.ctlbrowser_docked_w,220)), true)

    SetExtState(SCRIPT,'tb_butt_h',nz(tb_butt_h,20), true)
    SetExtState(SCRIPT,'pnl_scale',nz(pnl_scale,1), true)
    SetExtState(SCRIPT,'fontscale',nz(fontscale,8), true)
    SetExtState(SCRIPT,'tb_fontscale',nz(tb_fontscale,0), true)
    SetExtState(SCRIPT,'lst_fontscale',nz(lst_fontscale,0), true)

    SetExtState(SCRIPT,'renderfolder',nz(lvar.lastrenderfolder,''), true)

    SetExtState(SCRIPT,'addstrip_sepids',tostring(lvar.addstrip_keepseparateids), true)

    SetExtState(SCRIPT,'limitmw',tostring(lvar.limitmw), true)
    SetExtState(SCRIPT,'sliderzoom',tostring(lvar.sliderzoom), true)

    SetExtState(SCRIPT,'auto_sensitivity',auto_delay, true)
    SetExtState(SCRIPT,'swapctrlclick',tostring(settings_swapctrlclick), true)
    SetExtState(SCRIPT,'showbars',tostring(settings_showbars), true)
    SetExtState(SCRIPT,'insertdefstripontrack',tostring(settings_insertdefaultoneverytrack), true)
    SetExtState(SCRIPT,'insertdefstriponpage',tostring(settings_insertdefaultoneverypage), true)
    SetExtState(SCRIPT,'snaplistbgcol',settings_snaplistbgcol, true)
    SetExtState(SCRIPT,'gridcolor',lvar.gridcolor, true)
    SetExtState(SCRIPT,'showtakeover',tostring(lvar.showtakeover), true)
    SetExtState(SCRIPT,'mousefadermode',lvar.mousefadermode or 0, true)

    SetExtState(SCRIPT,'savedatainprojectfolder',tostring(settings_savedatainprojectfolder), true)
    SetExtState(SCRIPT,'save_subfolder',nz(save_subfolder,''), true)
    SetExtState(SCRIPT,'createbackup',tostring(settings_createbackuponmanualsave), true)
    SetExtState(SCRIPT,'createtmpbackup',tostring(settings_backupduringsave), true)

    SetExtState(SCRIPT,'usectlbitmap',tostring(settings_usectlbitmap), true)
    SetExtState(SCRIPT,'ctlupdate_rr',tostring(lvar.ctlupdate_rr), true)

    SetExtState(SCRIPT,'macroeditmonitor',tostring(settings_macroeditmonitor), true)
    SetExtState(SCRIPT,'hide_topbar',tostring(hide_topbar), true)
    SetExtState(SCRIPT,'settings_showminimaltopbar',tostring(settings_showminimaltopbar), true)
    SetExtState(SCRIPT,'hide_editbar',tostring(settings_hideeditbaronnewproject), true)
    SetExtState(SCRIPT,'lock_surface',tostring(settings_locksurfaceonnewproject), true)
    SetExtState(SCRIPT,'backcol',tostring(backcol), true)
    SetExtState(SCRIPT,'nebscanboot',tostring(nebscanboot_file), true)
    SetExtState(SCRIPT,'hidecursordrag',tostring(lvar.hidecursordrag), true)
    SetExtState(SCRIPT,'settings_touchmode',tostring(settings_touchmode), true)
    SetExtState(SCRIPT,'settings_touchfb',tostring(settings_touchFB), true)
    SetExtState(SCRIPT,'settings_trackchangemidi',tostring(settings_trackchangemidi), true)
    SetExtState(SCRIPT,'settings_savefaderboxassinsnapshots',tostring(settings_savefaderboxassinsnapshots), true)
    SetExtState(SCRIPT,'settings_savemodsinsnapshots',tostring(settings_savemodsinsnapshots), true)

    SetExtState(SCRIPT,'settings_showfaderassignments',tostring(settings_showfaderassignments), true)
    --[[SetExtState(SCRIPT,'settings_stripautosnap',tostring(settings_stripautosnap), true)
    SetExtState(SCRIPT,'autosnap_rowheight',tostring(autosnap_rowheight), true)
    SetExtState(SCRIPT,'autosnap_itemgap',tostring(autosnap_itemgap), true)
    SetExtState(SCRIPT,'autosnap_itemgapmax',tostring(autosnap_itemgapmax), true)]]

    SetExtState(SCRIPT,'livemode',tostring(lvar.glivemode), true)
    SetExtState(SCRIPT,'mixmodedir',tostring(lvar.mixmodedir), true)
    SetExtState(SCRIPT,'mixmodealign',tostring(lvar.mixmodealign), true)
    SetExtState(SCRIPT,'mmov_show',tostring(lvar.mmov_show), true)
    SetExtState(SCRIPT,'mmov_vsize',tostring(lvar.mmov_vsize), true)

    SetExtState(SCRIPT,'trbtns_show',tostring(lvar.trbtns_show), true)
    SetExtState(SCRIPT,'trbtns_size',tostring(lvar.trbtns_size), true)
    SetExtState(SCRIPT,'trmixbtns_size',tostring(lvar.trmixbtns_size), true)
    SetExtState(SCRIPT,'trbtns_meters',tostring(lvar.trbtns_meters), true)
    SetExtState(SCRIPT,'trbtns_pkcolor',tostring(lvar.trbtns_pkcolor), true)
    SetExtState(SCRIPT,'mm_fadepopamt',lvar.mm_fadepopamt, true)
    SetExtState(SCRIPT,'mm_fadepop',lvar.mm_fadepop, true)

    SetExtState(SCRIPT,'shadow_enabled',tostring(lvar.enablegfxshadows), true)
    SetExtState(SCRIPT,'shadow_sz',tostring(lvar.shadow_offsx), true)
    SetExtState(SCRIPT,'shadow_alpha',tostring(lvar.shadow_alpha), true)
    SetExtState(SCRIPT,'shadow_feather',tostring(lvar.shadow_feather), true)

    --SetExtState(SCRIPT,'gallery_itemgap',tostring(gallery_itemgap), true)
    SetExtState(SCRIPT,'stripgallery_view',tostring(stripgallery_view), true)
    SetExtState(SCRIPT,'settings_disablekeysonlockedsurface',tostring(settings_disablekeysonlockedsurface), true)
    SetExtState(SCRIPT,'settings_deletefxwithstrip',tostring(settings_deletefxwithstrip), true)
    SetExtState(SCRIPT,'forcestrippluginguisclosed',tostring(lvar.forcestrippluginguisclosed), true)
    
    SetExtState(SCRIPT,'settings_morphfaderassignedctls',tostring(settings_morphfaderassignedctls), true)
    SetExtState(SCRIPT,'settings_alwaysrunmods',tostring(settings_alwaysrunmods), true)
    SetExtState(SCRIPT,'settings_followsnapshot',tostring(settings_followsnapshot), true)
    SetExtState(SCRIPT,'settings_showmorphpop',tostring(settings_showmorphpop), true)
    SetExtState(SCRIPT,'settings_groupsel',tostring(settings_groupsel), true)
    SetExtState(SCRIPT,'settings_savesnapafterselected',tostring(settings_savesnapafterselected), true)
    SetExtState(SCRIPT,'settings_drawbglabelsontop',tostring(settings_drawbglabelsontop), true)
    SetExtState(SCRIPT,'settings_pagescrolldir',tostring(settings_pagescrolldir), true)
    SetExtState(SCRIPT,'settings_ssdock',tostring(settings_ssdock), true)
    SetExtState(SCRIPT,'settings_sbdock',tostring(settings_sbdock), true)
    SetExtState(SCRIPT,'settings_hideplugnotfound',tostring(settings_hideplugnotfound), true)
    SetExtState(SCRIPT,'settings_enablednu',tostring(settings_enablednu), true)
    SetExtState(SCRIPT,'snapcapture_midi_dt',tostring((lvar.snapcapture_midi_dt or false)), true)
    SetExtState(SCRIPT,'mac_revcol',tostring(lvar.Mac_revcol), true)
    SetExtState(SCRIPT,'sortcontrols',tostring(lvar.sortcontrols), true)

    SetExtState(SCRIPT,'show_stripbrowser',tostring(show_stripbrowser), true)
    SetExtState(SCRIPT,'sbwin_x',tostring(sbwin.x), true)
    SetExtState(SCRIPT,'sbwin_y',tostring(sbwin.y), true)
    SetExtState(SCRIPT,'sbwin_w',tostring(sbwin.w), true)
    SetExtState(SCRIPT,'sbwin_h',tostring(sbwin.h), true)
    SetExtState(SCRIPT,'stripbrowser_minw',tostring(lvar.stripbrowser.minw), true)
    SetExtState(SCRIPT,'stripbrowser_minh',tostring(lvar.stripbrowser.minh), true)
    SetExtState(SCRIPT,'stripbrowser_dockpos',tostring(lvar.stripbrowser.dockpos or 1), true)
    SetExtState(SCRIPT,'stripbrowser_showlabel',tostring(lvar.stripbrowser.showlabel), true)
    SetExtState(SCRIPT,'stripbrowser_tsz',tostring(lvar.stripbrowser.tsz or 0), true)
    SetExtState(SCRIPT,'stripbrowser_type2',tostring(lvar.stripbrowser.type2), true)
    SetExtState(SCRIPT,'stripbrowser_fullscreen',tostring(lvar.stripbrowser.fullscreen), true)

    SetExtState(SCRIPT,'settings_moddock',tostring(settings_moddock), true)
    SetExtState(SCRIPT,'modwin_min',tostring(modwinsz.minimized), true)
    SetExtState(SCRIPT,'modwin_h',tostring(modwinsz.h), true)
    SetExtState(SCRIPT,'modwin_w',tostring(modwinsz.w), true)
    SetExtState(SCRIPT,'modwin_x',tostring(modwinsz.x), true)
    SetExtState(SCRIPT,'modwin_y',tostring(modwinsz.y), true)
    SetExtState(SCRIPT,'modwin_show',tostring(show_lfoedit), true)

    SetExtState(SCRIPT,'macrosech',tostring(lvar.macrosech), true)
    SetExtState(SCRIPT,'maxundo',tostring(undo.max), true)

    SetExtState(SCRIPT,'modulator_cnt',tostring(modulator_cnt), true)

    SetExtState(SCRIPT,'mutate_max',tostring(lvar.mutate_settings.mutate_max), true)
    SetExtState(SCRIPT,'mutate_dir',tostring(lvar.mutate_settings.dir), true)

    SetExtState(SCRIPT,'settings_dragmode',tostring(settings_dragmode), true)
    SetExtState(SCRIPT,'settings_runstartbat',tostring(settings_runstartbat or false), true)

    SetExtState(SCRIPT,'bgmatchestrackcolour',tostring(lvar.bgmatchestrackcolour or 0), true)

    if strip_default then
      SetExtState(SCRIPT,'strip_default',tostring(strip_default.strip_select), true)
      SetExtState(SCRIPT,'stripfol_default',tostring(strip_default.stripfol_select), true)
    else
      SetExtState(SCRIPT,'strip_default','',true)
      SetExtState(SCRIPT,'stripfol_default','',true)
    end
    if strip_default_mast then
      SetExtState(SCRIPT,'strip_default_mast',tostring(strip_default_mast.strip_select), true)
      SetExtState(SCRIPT,'stripfol_default_mast',tostring(strip_default_mast.stripfol_select), true)
    else
      SetExtState(SCRIPT,'strip_default_mast', '', true)
      SetExtState(SCRIPT,'stripfol_default_mast', '', true)
    end
    if strip_default_glob then
      SetExtState(SCRIPT,'strip_default_glob',tostring(strip_default_glob.strip_select), true)
      SetExtState(SCRIPT,'stripfol_default_glob',tostring(strip_default_glob.stripfol_select), true)
    else
      SetExtState(SCRIPT,'strip_default_glob', '', true)
      SetExtState(SCRIPT,'stripfol_default_glob', '', true)
    end

    SetExtState(SCRIPT,'striploadoverride', lvar.striploadoverride or '', true)

    SetExtState(SCRIPT,'fxpos_l',tostring(lvar.fxpos.l), true)
    SetExtState(SCRIPT,'fxpos_t',tostring(lvar.fxpos.t), true)
    SetExtState(SCRIPT,'fxpos_w',tostring(lvar.fxpos.w), true)
    SetExtState(SCRIPT,'fxpos_h',tostring(lvar.fxpos.h), true)

    if lvar.savesettingstofile then
      file:close()
    end

    --DBG('save '..reaper.time_precise()-t)

    SaveFavStrips()
    SaveMixerSettings()
    
    XpnlSaveInfo()

  end

  function SaveMixerSettings()

    local save_path=paths.resource_path
    local fn=save_path.."mixer.txt"

    local DELETE=true
    local file

    if reaper.file_exists(fn) then

    end
    if lvar.dm_btnpnl == nil then lvar.dm_btnpnl = {} end

    if DELETE then
      file=io.open(fn,"w")
      local pickled_table=pickle(lvar.dm_btnpnl)
      file:write(pickled_table)
      file:close()
    end

  end

  function LoadMixerSettings()

    local load_path=paths.resource_path
    local fn=load_path.."mixer.txt"

    lvar.dm_btnpnl = {}
    if reaper.file_exists(fn) then
      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      lvar.dm_btnpnl = unpickle(content)
      if lvar.dm_btnpnl == nil then lvar.dm_btnpnl = {} lvar.dm_btnpnl[1] = {} end
    end

  end

  function SaveFavStrips()

    local save_path=paths.strips_path
    local fn=save_path.."favs.txt"

    local DELETE=true
    local file

    if reaper.file_exists(fn) then

    end
    if strip_favs == nil then strip_favs = {} end

    if DELETE then
      file=io.open(fn,"w")
      local pickled_table=pickle(strip_favs)
      file:write(pickled_table)
      file:close()
    end

  end

  function LoadFavStrips()

    local load_path=paths.strips_path
    local fn=load_path.."favs.txt"

    strip_favs = {}
    if reaper.file_exists(fn) then
      local file
      file=io.open(fn,"r")
      local content=file:read("*a")
      file:close()

      strip_favs = unpickle(content)
      if strip_favs == nil then strip_favs = {} end
      CheckFavs()
    end

  end

  function SaveSingleStrip(s)
    local SCRIPT = lvar.SCRIPT

    if strips then
      reaper.SetProjExtState(0,SCRIPT,'strips_count',#strips)
    else
      reaper.SetProjExtState(0,SCRIPT,'strips_count',0)
    end
    SaveStripData_FN(s)

    if snapshots then
      reaper.SetProjExtState(0,SCRIPT,'snapshots_count',#snapshots)
    else
      reaper.SetProjExtState(0,SCRIPT,'snapshots_count',0)
    end
    SaveSnapshotData_FN(s)
    SaveXXYData_FN(s)

  end

  function SaveFaders(file, pfx, faders, excludessfader)

    if file and faders and #faders > 0 then

      CheckFaders(faders)

      local key = pfx..'fadercnt'
      file:write('['..key..']'.. #faders ..'\n')
      if not excludessfader then
        file:write('[snapshot_fader]'.. nz(snapshot_fader,'') ..'\n')
        file:write('[capture_fader]'.. nz(capture_fader,'') ..'\n')
      end

      for f = 1, #faders do

        if faders[f] then

          local key = pfx..'fader_'..f..'_'
          file:write('['..key..'targettype]'.. nz(faders[f].targettype,'') ..'\n')
          file:write('['..key..'dm_guid]'.. nz(faders[f].dm_guid,'') ..'\n')
          file:write('['..key..'dm_trn]'.. nz(faders[f].dm_trn,'') ..'\n')
          file:write('['..key..'strip]'.. nz(faders[f].strip,'') ..'\n')
          file:write('['..key..'page]'.. nz(faders[f].page,'') ..'\n')
          file:write('['..key..'ctl]'.. nz(faders[f].ctl,'') ..'\n')
          file:write('['..key..'c_id]'.. nz(faders[f].c_id,'') ..'\n')
          file:write('['..key..'sstype]'.. nz(faders[f].sstype,'') ..'\n')
          file:write('['..key..'xy]'.. nz(faders[f].xy,'') ..'\n')
          file:write('['..key..'mode]'.. nz(faders[f].mode,'') ..'\n')
          file:write('['..key..'voffset]'.. nz(faders[f].voffset,'') ..'\n')

        end
      end
    end

  end

  function SaveMod(file,pfx,moddata,excludetargets)

    local key = pfx
    file:write('['..key..'active]'.. tostring(nz(moddata.active,false)) ..'\n')
    file:write('['..key..'steps]'.. moddata.steps ..'\n')
    file:write('['..key..'stepsmult]'.. moddata.stepsmult ..'\n')
    file:write('['..key..'div]'.. moddata.div ..'\n')
    file:write('['..key..'interpolate]'.. tostring(nz(moddata.interpolate,true)) ..'\n')
    file:write('['..key..'syncv]'.. nz(moddata.syncv,15) ..'\n')
    file:write('['..key..'sync]'.. tostring(nz(moddata.sync,true)) ..'\n')
    file:write('['..key..'offset]'.. nz(moddata.offset,0.5) ..'\n')
    file:write('['..key..'min]'.. nz(moddata.min,0) ..'\n')
    file:write('['..key..'max]'.. nz(moddata.max,1) ..'\n')
    file:write('['..key..'mode]'.. nz(moddata.mode,1) ..'\n')

    if excludetargets ~= true then
      file:write('['..key..'target_cnt]'.. #moddata.targets ..'\n')
      for t = 1, #moddata.targets do
        local key = pfx..'target_'..t..'_'
        file:write('['..key..'targettype]'.. nz(moddata.targets[t].targettype,'') ..'\n')
        file:write('['..key..'dm_guid]'.. nz(moddata.targets[t].dm_guid,'') ..'\n')
        file:write('['..key..'dm_trn]'.. nz(moddata.targets[t].dm_trn,'') ..'\n')
        file:write('['..key..'strip]'.. nz(moddata.targets[t].strip,'') ..'\n')
        file:write('['..key..'page]'.. nz(moddata.targets[t].page,'') ..'\n')
        file:write('['..key..'ctl]'.. nz(moddata.targets[t].ctl,'') ..'\n')
        file:write('['..key..'c_id]'.. nz(moddata.targets[t].c_id,'') ..'\n')
      end
    else
      file:write('['..key..'target_cnt]'.. 0 ..'\n')
    end

    for d = 1, moddata.steps do
      local key = pfx..'data_'..d..'_'
      file:write('['..key..'val]'.. nz(moddata.data[d],0.5) ..'\n')
    end

  end

  function SaveMods(file)

    if file and modulators and modulator_cnt > 0 then

      modulators = CheckMods(modulators)

      local key = 'modcnt'
      file:write('['..key..']'.. modulator_cnt ..'\n')

      for m = 1, modulator_cnt do

        if modulators[m] then

          local key = 'mod_'..m..'_'
          SaveMod(file,key,modulators[m])

        end
      end
    end

  end

  function SaveSwitchers(file)

    if file and switchers and #switchers > 0 then

      local scnt = #switchers
      file:write('[switcher_cnt]'..scnt..'\n')

      for s = 1, scnt do

        local key = 'switch'..s..'_'

        local swcnt = #switchers[s].grpids
        local gcnt = 0
        if switchers[s].fxguids then
          gcnt = #switchers[s].fxguids
        end
        file:write('['..key..'switchmode]'..(switchers[s].switchmode or 0)..'\n')
        file:write('['..key..'stripfolder]'..(switchers[s].stripfolder or '')..'\n')
        file:write('['..key..'copypinmap]'..(tostring(switchers[s].copypinmap) or '')..'\n')
        file:write('['..key..'dropx]'..(tostring(switchers[s].dropx) or '')..'\n')
        file:write('['..key..'dropy]'..(tostring(switchers[s].dropy) or '')..'\n')
        file:write('['..key..'grpid_cnt]'..swcnt..'\n')
        file:write('['..key..'fxguid_cnt]'..gcnt..'\n')
        file:write('['..key..'current]'..nz(switchers[s].current,-1)..'\n')
        file:write('['..key..'extendmode]'..tostring(nz(switchers[s].extendmode,false))..'\n')
        file:write('['..key..'extendid]'..nz(switchers[s].extendid,'')..'\n')
        file:write('['..key..'extendpos]'..nz(switchers[s].extendpos,'')..'\n')
        file:write('['..key..'extenddir]'..nz(switchers[s].extenddir,'')..'\n')
        file:write('['..key..'padx]'..nz(switchers[s].padx,50)..'\n')
        file:write('['..key..'pady]'..nz(switchers[s].pady,20)..'\n')

        if switchers[s].popx then
          file:write('['..key..'popx]'..switchers[s].popx..'\n')
          file:write('['..key..'popy]'..switchers[s].popy..'\n')
        end

        if switchers[s].parent then
          file:write('['..key..'par_swid]'..nz(switchers[s].parent.switcherid,'')..'\n')
          file:write('['..key..'par_grpid]'..nz(switchers[s].parent.grpid,'')..'\n')
        end
        if switchers[s].posfirstswitcher then
          file:write('['..key..'posfirst_x]'..switchers[s].posfirstswitcher.x..'\n')
          file:write('['..key..'posfirst_y]'..switchers[s].posfirstswitcher.y..'\n')
        end
        for swc = 1,swcnt do
          local key = 'switch'..s..'_gid_'..swc..'_'
          file:write('['..key..'grpid]'..nz(switchers[s].grpids[swc].id,'')..'\n')
          file:write('['..key..'grpname]'..nz(switchers[s].grpids[swc].name,'')..'\n')
          file:write('['..key..'stripfn]'..nz(switchers[s].grpids[swc].stripfn,'')..'\n')
        end
        for sgc = 1,gcnt do
          local key = 'switch'..s..'_fxguid_'..sgc..'_'
          file:write('['..key..'guid]'..nz(switchers[s].fxguids[sgc],'')..'\n')
        end
      end
    else
      file:write('[switcher_cnt]'..0 ..'\n')
    end

  end

  function SaveXXYPathData_FN(fn,save_path,file)

    local nofile = false
    if file == nil then
      nofile = true
      local save_path=paths.projsave_path..'/'
      if settings_savedatainprojectfolder == true then
        save_path=reaper.GetProjectPath('')..'/'
      end

      local ffn=save_path..fn

      file=io.open(ffn,"w")
    end

    if xxypath and #xxypath > 0 then

      local key = 'pathcnt'
      file:write('['..key..']'.. #xxypath ..'\n')

      for p = 1, #xxypath do

        if xxypath[p] then

          local key = 'xxypath_'..p..'_'
          local ptcnt = #xxypath[p].points
          local idxcnt = #xxypath[p].pathidxpt

          file:write('['..key..'pathlen]'.. nz(xxypath[p].pathlen,'') ..'\n')
          file:write('['..key..'pt_count]'.. ptcnt ..'\n')
          file:write('['..key..'idxpt_count]'.. idxcnt ..'\n')

          if ptcnt > 0 then
            for pt = 1, ptcnt do

              local key = 'xxypath_'..p..'_pt_'..pt..'_'
              file:write('['..key..'len]'.. nz(xxypath[p].points[pt].len,'') ..'\n')
              file:write('['..key..'posstart]'.. nz(xxypath[p].points[pt].posstart,'') ..'\n')
              file:write('['..key..'posend]'.. nz(xxypath[p].points[pt].posend,'') ..'\n')

              for xy = 1, 4 do
                file:write('['..key..'x_'..xy..']'.. nz(xxypath[p].points[pt].x[xy],'') ..'\n')
                file:write('['..key..'y_'..xy..']'.. nz(xxypath[p].points[pt].y[xy],'') ..'\n')
              end

              if xxypath[p].points[pt].t then
                local tcnt = #xxypath[p].points[pt].t
                file:write('['..key..'t_count]'.. tcnt ..'\n')

                if tcnt > 0 then
                  for t = 0, tcnt do

                    file:write('['..key..'t_'..t..']'.. nz(xxypath[p].points[pt].t[t],'') ..'\n')

                  end
                end
              end
            end
          end
          if idxcnt > 0 then
            for i = 0, idxcnt do

              local key = 'xxypath_'..p..'_idxpt_'..i
              file:write('['..key..']'.. xxypath[p].pathidxpt[i] ..'\n')

            end
          end
        end

      end
    end

    if nofile == true then
      file:close()
      reaper.SetProjExtState(0,lvar.SCRIPT,'path_datafile',fn)
    end

  end

  function SaveXXYData_FN(s,fn,save_path, file)

    local nofile = false
    local pfx = ''
    if file == nil then
      local save_path=paths.projsave_path..'/'
      if settings_savedatainprojectfolder == true then
        save_path=reaper.GetProjectPath('')..'/'
      end

      local ffn=save_path..fn

      file=io.open(ffn,"w")

    else
      pfx = 'xxy_s'..s..'_'
    end

    if xxy and xxy[s] then
      for p = 1, lvar.maxpage do

        if xxy[s][p] then

          for sst = 1, #snapshots[s][p] do

            if xxy[s][p][sst] then

              local key = pfx..'xxy_p'..p..'_sst_'..sst..'_'
              local ptcnt = #xxy[s][p][sst].points
              file:write('['..key..'x]'.. xxy[s][p][sst].x ..'\n')
              file:write('['..key..'y]'.. xxy[s][p][sst].y ..'\n')
              file:write('['..key..'pt_count]'.. ptcnt ..'\n')
              file:write('['..key..'pathidx]'.. nz(xxy[s][p][sst].pathidx,'') ..'\n')
              file:write('['..key..'pathfader]'.. nz(xxy[s][p][sst].pathfader,'') ..'\n')
              file:write('['..key..'xfader]'.. nz(xxy[s][p][sst].xfader,'') ..'\n')
              file:write('['..key..'yfader]'.. nz(xxy[s][p][sst].yfader,'') ..'\n')

              for pt = 1, ptcnt do

                local key = pfx..'xxy_p'..p..'_sst_'..sst..'_pt_'..pt..'_'
                file:write('['..key..'x]'.. xxy[s][p][sst].points[pt].x ..'\n')
                file:write('['..key..'y]'.. xxy[s][p][sst].points[pt].y ..'\n')
                file:write('['..key..'ss]'.. xxy[s][p][sst].points[pt].ss ..'\n')
                file:write('['..key..'inactive]'.. nz(tostring(xxy[s][p][sst].points[pt].inactive),'') ..'\n')

              end

            end

          end

        end

      end
    end

    if nofile == true then
      file:close()
      reaper.SetProjExtState(0,lvar.SCRIPT,'metalite_datafile_'..string.format("%03d",s),fn)
    end

  end

  function SaveSnapshotData_FN(s,fn,save_path, file)

    t = reaper.time_precise()

    local nofile = false
    local pfx = ''
    if file == nil then

      local save_path=paths.projsave_path..'/'
      if settings_savedatainprojectfolder == true then
        save_path=reaper.GetProjectPath('')..'/'
      end
      local ffn=save_path..fn

      file=io.open(ffn,"w")

    else
      pfx = 'snap_s'..s..'_'
    end

    for p = 1, #snapshots[s] do

      if snapshots[s] and snapshots[s][p] then
        if #snapshots[s][p] > 1 then
          for sst = 2, #snapshots[s][p] do
            if snapshots[s][p][sst].sorted ~= true then
              CleanSortSS(s,p,sst)
            end
          end
        end
      end

      local key = pfx..'p'..p..'_'
      SaveSnapshotDataX(snapshots[s][p],key,file)

    end

    if nofile == true then
      file:close()
      reaper.SetProjExtState(0,lvar.SCRIPT,'snaps_datafile_'..string.format("%03d",s),fn)
    end

    --DBG('Save snapshot time: '..reaper.time_precise() - t)
    return reaper.time_precise() - t

  end

  function SaveSnapshotDataX(snaps, pfx, file, gensubid)

    if pfx == nil then pfx = '' end
    local key = pfx

    file:write('['..key..'sstype_count]'..#snaps..'\n')

    for sst = 1, #snaps do

      local key = pfx..'sst_'..sst..'_'

      local snp = snaps[sst]

      file:write('['..key..'morph_time]'..nz(snp.morph_time,0)..'\n')
      file:write('['..key..'morph_sync]'..tostring(nz(snp.morph_sync,false))..'\n')
      file:write('['..key..'morph_syncv]'..nz(snp.morph_syncv,14)..'\n')
      file:write('['..key..'morph_scale]'..nz(snp.morph_scale,1)..'\n')
      file:write('['..key..'morph_time_fader]'..nz(snp.morph_time_fader,'')..'\n')
      file:write('['..key..'ss_selected]'..nz(snp.selected,'')..'\n')
      file:write('['..key..'morph_loop]'..nz(snp.morph_loop,1)..'\n')
      file:write('['..key..'capturefaders]'..tostring(nz(snp.capturefaders,false))..'\n')
      file:write('['..key..'capturemods]'..tostring(nz(snp.capturemods,false))..'\n')
      file:write('['..key..'ignorevals]'..tostring(nz(snp.ignorevals,false))..'\n')
      file:write('['..key..'sorted]'..tostring(nz(snp.sorted,''))..'\n')

      if sst == 1 then
        file:write('['..key..'ss_count]'..#snp..'\n')

        if #snp > 0 then

          for ss = 1, #snp do

            local key = pfx..'sst_'..sst..'_ss_'..ss..'_'

            local snpss = snp[ss]

            file:write('['..key..'name]'.. snpss.name ..'\n')
            file:write('['..key..'data_count]'.. #snpss.data ..'\n')

            if #snpss.data > 0 then
              for d = 1, #snpss.data do

                local key = pfx..'sst_'..sst..'_ss_'..ss..'_d_'..d..'_'

                local snpssdata = snpss.data[d]

                file:write('['..key..'cid]'.. snpssdata.c_id ..'\n')
                file:write('['..key..'ctl]'.. snpssdata.ctl ..'\n')
                file:write('['..key..'val]'.. snpssdata.val ..'\n')
                file:write('['..key..'dval]'.. nz(snpssdata.dval,'') ..'\n')

                file:write('['..key..'mfset]'.. tostring(nz(snpssdata.mfset,'')) ..'\n')
                if snpssdata.mf then
                  file:write('['..key..'mf]'.. snpssdata.mf ..'\n')
                  file:write('['..key..'mfdata_targettype]'.. snpssdata.mfdata.targettype ..'\n')
                  file:write('['..key..'mfdata_strip]'.. snpssdata.mfdata.strip ..'\n')
                  file:write('['..key..'mfdata_page]'.. snpssdata.mfdata.page ..'\n')
                  file:write('['..key..'mfdata_ctl]'.. snpssdata.mfdata.ctl ..'\n')
                  file:write('['..key..'mfdata_c_id]'.. snpssdata.mfdata.c_id ..'\n')
                end

              end
            end

            file:write('['..key..'modset]'.. tostring(nz(snpss.modset,'')) ..'\n')
            if snpss.modset then
              local mm = snpss.moddata

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              file:write('['..key..'modcnt]'.. #mm ..'\n')

              for m = 1, #mm do

                if mm[m] then

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_'
                  file:write('['..key..'active]'.. tostring(nz(mm[m].active,false)) ..'\n')
                  file:write('['..key..'steps]'.. mm[m].steps ..'\n')
                  file:write('['..key..'stepsmult]'.. mm[m].stepsmult ..'\n')
                  file:write('['..key..'div]'.. mm[m].div ..'\n')
                  file:write('['..key..'interpolate]'.. tostring(nz(mm[m].interpolate,true)) ..'\n')
                  file:write('['..key..'syncv]'.. nz(mm[m].syncv,15) ..'\n')
                  file:write('['..key..'sync]'.. tostring(nz(mm[m].sync,true)) ..'\n')
                  file:write('['..key..'offset]'.. nz(mm[m].offset,0.5) ..'\n')
                  file:write('['..key..'min]'.. nz(mm[m].min,0) ..'\n')
                  file:write('['..key..'max]'.. nz(mm[m].max,1) ..'\n')
                  file:write('['..key..'mode]'.. nz(mm[m].mode,1) ..'\n')
                  file:write('['..key..'target_cnt]'.. #mm[m].targets ..'\n')

                  for t = 1, #mm[m].targets do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_target_'..t..'_'
                    file:write('['..key..'targettype]'.. nz(mm[m].targets[t].targettype,'') ..'\n')
                    file:write('['..key..'strip]'.. nz(mm[m].targets[t].strip,'') ..'\n')
                    file:write('['..key..'page]'.. nz(mm[m].targets[t].page,'') ..'\n')
                    file:write('['..key..'ctl]'.. nz(mm[m].targets[t].ctl,'') ..'\n')
                    file:write('['..key..'c_id]'.. nz(mm[m].targets[t].c_id,'') ..'\n')
                  end

                  for d = 1, mm[m].steps do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_data_'..d..'_'
                    file:write('['..key..'val]'.. nz(mm[m].data[d],0.5) ..'\n')
                  end

                end
              end
            end

            local mm = snpss.faddata
            if mm then
              file:write('['..key..'fadset]'.. tostring(nz(snpss.fadset,'')) ..'\n')
              if snpss.fadset then
                local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
                file:write('['..key..'fadcnt]'.. #faders ..'\n')

                for m = 1, #faders do

                  if mm[m] and mm[m].targettype and (mm[m].targettype == 4 or
                                                     mm[m].targettype == 7) then

                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_fad_'..m..'_'
                    file:write('['..key..'mfdata_targettype]'.. nz(mm[m].targettype,'') ..'\n')
                    file:write('['..key..'mfdata_strip]'.. nz(mm[m].strip,'') ..'\n')
                    file:write('['..key..'mfdata_page]'.. nz(mm[m].page,'') ..'\n')
                    file:write('['..key..'mfdata_ctl]'.. nz(mm[m].ctl,'') ..'\n')
                    file:write('['..key..'mfdata_c_id]'.. nz(mm[m].c_id,'') ..'\n')
                    file:write('['..key..'mfdata_voffset]'.. nz(mm[m].voffset,'') ..'\n')

                  end
                end
              end
            end
          end
        end

      elseif sst > 1 then

        file:write('['..key..'stages]'..tostring(nz(snp.stages,''))..'\n')
        file:write('['..key..'mult]'..tostring(nz(snp.mult,''))..'\n')
        
        for sd = 1, lvar.snapstages do
          local pkey = 'sdelay'..sd
          local mkey = 'mtime'..sd
          local tkey = 'deltype'..sd
          if snp.delay then
            file:write('['..key..pkey..']'..tostring(nz(snp.delay[sd],0))..'\n')
            file:write('['..key..mkey..']'..tostring(nz(snp.mtime[sd],15))..'\n')
            file:write('['..key..tkey..']'..tostring(nz(snp.deltype[sd],0))..'\n')
          end
        end

        file:write('['..key..'subsetname]'.. snp.subsetname ..'\n')
        if gensubid and not snp.subid then
          snp.subid = GenID()
        end
        file:write('['..key..'subid]'..nz(snp.subid,'')..'\n')
        file:write('['..key..'stripid]'..nz(snp.stripid,'')..'\n')
        file:write('['..key..'ss_count]'.. #snp.snapshot ..'\n')
        file:write('['..key..'ctl_count]'.. #snp.ctls ..'\n')

        if #snp.ctls > 0 then

          for ctl = 1, #snp.ctls do
            local key = pfx..'sst_'..sst..'_c_'..ctl..'_'
            file:write('['..key..'cid]'.. snp.ctls[ctl].c_id ..'\n')
            file:write('['..key..'id]'.. nz(snp.ctls[ctl].id,'') ..'\n')
            file:write('['..key..'ctl]'.. snp.ctls[ctl].ctl ..'\n')
            file:write('['..key..'stage]'.. snp.ctls[ctl].stage ..'\n')
            file:write('['..key..'morph]'.. tostring(snp.ctls[ctl].morph) ..'\n')
            file:write('['..key..'mem]'.. tostring(snp.ctls[ctl].mem) ..'\n')
          end
        end
        if #snp.snapshot > 0 then

          for ss = 1, #snp.snapshot do

            local snpss = snp.snapshot[ss]

            local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
            file:write('['..key..'name]'.. snpss.name ..'\n')
            file:write('['..key..'data_count]'.. #snpss.data ..'\n')

            if #snpss.data > 0 then
              for d = 1, #snpss.data do

                local snpssdata = snpss.data[d]

                local key = pfx..'sst_'..sst..'_ss_'..ss..'_d_'..d..'_'

                file:write('['..key..'cid]'.. snpssdata.c_id ..'\n')
                file:write('['..key..'id]'.. nz(snpssdata.id,'') ..'\n')
                file:write('['..key..'ctl]'.. snpssdata.ctl ..'\n')
                file:write('['..key..'val]'.. snpssdata.val ..'\n')
                file:write('['..key..'dval]'.. nz(snpssdata.dval,'') ..'\n')

                file:write('['..key..'mfset]'.. tostring(nz(snpssdata.mfset,'')) ..'\n')
                if snpssdata.mf then
                  file:write('['..key..'mf]'.. snpssdata.mf ..'\n')
                  file:write('['..key..'mfdata_targettype]'.. snpssdata.mfdata.targettype ..'\n')
                  file:write('['..key..'mfdata_strip]'.. snpssdata.mfdata.strip ..'\n')
                  file:write('['..key..'mfdata_page]'.. snpssdata.mfdata.page ..'\n')
                  file:write('['..key..'mfdata_ctl]'.. snpssdata.mfdata.ctl ..'\n')
                  file:write('['..key..'mfdata_c_id]'.. snpssdata.mfdata.c_id ..'\n')
                end

              end
            end

            file:write('['..key..'modset]'.. tostring(nz(snpss.modset,'')) ..'\n')
            if snpss.modset then
              local mm = snpss.moddata

              local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
              file:write('['..key..'modcnt]'.. #mm ..'\n')

              for m = 1, #mm do

                if mm[m] then

                  local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_'
                  file:write('['..key..'active]'.. tostring(nz(mm[m].active,false)) ..'\n')
                  file:write('['..key..'steps]'.. mm[m].steps ..'\n')
                  file:write('['..key..'stepsmult]'.. mm[m].stepsmult ..'\n')
                  file:write('['..key..'div]'.. mm[m].div ..'\n')
                  file:write('['..key..'interpolate]'.. tostring(nz(mm[m].interpolate,true)) ..'\n')
                  file:write('['..key..'syncv]'.. nz(mm[m].syncv,15) ..'\n')
                  file:write('['..key..'sync]'.. tostring(nz(mm[m].sync,true)) ..'\n')
                  file:write('['..key..'offset]'.. nz(mm[m].offset,0.5) ..'\n')
                  file:write('['..key..'min]'.. nz(mm[m].min,0) ..'\n')
                  file:write('['..key..'max]'.. nz(mm[m].max,1) ..'\n')
                  file:write('['..key..'mode]'.. nz(mm[m].mode,1) ..'\n')
                  file:write('['..key..'target_cnt]'.. #mm[m].targets ..'\n')

                  for t = 1, #mm[m].targets do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_target_'..t..'_'
                    file:write('['..key..'targettype]'.. nz(mm[m].targets[t].targettype,'') ..'\n')
                    file:write('['..key..'strip]'.. nz(mm[m].targets[t].strip,'') ..'\n')
                    file:write('['..key..'page]'.. nz(mm[m].targets[t].page,'') ..'\n')
                    file:write('['..key..'ctl]'.. nz(mm[m].targets[t].ctl,'') ..'\n')
                    file:write('['..key..'c_id]'.. nz(mm[m].targets[t].c_id,'') ..'\n')
                  end

                  for d = 1, mm[m].steps do
                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_mod_'..m..'_data_'..d..'_'
                    file:write('['..key..'val]'.. nz(mm[m].data[d],0.5) ..'\n')
                  end

                end
              end
            end

            local mm = snpss.faddata
            if mm then
              file:write('['..key..'fadset]'.. tostring(nz(snpss.fadset,'')) ..'\n')
              if snpss.fadset then
                local key = pfx..'sst_'..sst..'_ss_'..ss..'_'
                file:write('['..key..'fadcnt]'.. #mm ..'\n')

                for m = 1, #mm do

                  if mm[m] and mm[m].targettype then

                    local key = pfx..'sst_'..sst..'_ss_'..ss..'_fad_'..m..'_'
                    file:write('['..key..'mfdata_targettype]'.. nz(mm[m].targettype,'') ..'\n')
                    file:write('['..key..'mfdata_strip]'.. nz(mm[m].strip,'') ..'\n')
                    file:write('['..key..'mfdata_page]'.. nz(mm[m].page,'') ..'\n')
                    file:write('['..key..'mfdata_ctl]'.. nz(mm[m].ctl,'') ..'\n')
                    file:write('['..key..'mfdata_c_id]'.. nz(mm[m].c_id,'') ..'\n')
                    file:write('['..key..'mfdata_voffset]'.. nz(mm[m].voffset,'') ..'\n')

                  end
                end
              end
            end

          end
        end
      end
    end

  end

  function SaveStripData_FN(s,fn,save_path,file,strips_table)

    t = reaper.time_precise()
    local nofile = false
    local pfx = ''
    if file == nil then
      local ffn=save_path..fn

      file=io.open(ffn,"w")
    else
      pfx = 'strip_s'..s..'_'
    end

    local strips = strips_table or strips

    --file:write('[strips_count]'..#strips..'\n')
    if strips[s] then
      file:write('[' .. pfx ..'page]'..nz(strips[s].page,1)..'\n')
      file:write('[' ..pfx ..'track_name]'..strips[s].track.name..'\n')
      file:write('[' ..pfx ..'track_guid]'..nz(strips[s].track.guid,'')..'\n')
      file:write('[' ..pfx ..'track_num]'..strips[s].track.tracknum..'\n')
      file:write('[' ..pfx ..'track_strip]'..strips[s].track.strip..'\n')

      if strips[s].faders then
        SaveFaders(file,pfx,strips[s].faders,true)
      end

      for p = 1, lvar.maxpage do

        local key = pfx..'p'..p..'_'

        GenStripSaveData2(strips[s][p],key,file)

      end

    end

    --file:write(pickled_table)
    if nofile == true then
      file:close()
      reaper.SetProjExtState(0,lvar.SCRIPT,'strips_count',#strips)
      reaper.SetProjExtState(0,lvar.SCRIPT,'strips_datafile_'..string.format("%03d",s),fn)
    end

    --DBG('Save strip time: '..reaper.time_precise() - t)
    return reaper.time_precise() - t

  end

  function GenStripSaveData2(stripdata,pfx,file)

    if file == nil then return end
    if pfx == nil then pfx = '' end

    t = reaper.time_precise()

        local key = pfx

        if stripdata then

          if stripdata.lmode then
            file:write('['..key..'lmode]'..stripdata.lmode..'\n')
          end
          file:write('['..key..'surface_x]'..stripdata.surface_x..'\n')
          file:write('['..key..'surface_y]'..stripdata.surface_y..'\n')
          file:write('['..key..'controls_count]'..#stripdata.controls..'\n')
          file:write('['..key..'graphics_count]'..#stripdata.graphics..'\n')
          file:write('['..key..'fxcnt]'..nz(stripdata.fxcnt,'')..'\n')
          file:write('['..key..'fxstr]'..nz(stripdata.fxstr,'')..'\n')
          file:write('['..key..'trn]'..nz(stripdata.trn,'')..'\n')
          file:write('['..key..'showpop]'..tostring(nz(stripdata.showpop,false))..'\n')

          if stripdata.pop then
            file:write('['..key..'pop_count]'..#stripdata.pop..'\n')
          end
          local tr = GetTrack(tracks[track_select].tracknum)
          local nchan
          if tr then
            nchan = reaper.GetMediaTrackInfo_Value(tr, "I_NCHAN")
          end
          nchan = math.max(nchan or 2, nz(stripdata.nchan,2))
          file:write('['..key..'NCHAN]'..nchan..'\n')

          if stripdata.pop and #stripdata.pop > 0 then
            for i = 1, #stripdata.pop do
              local key = pfx..'pop_'..i..'_'
              file:write('['..key..'swid]'..(stripdata.pop[i].swid or '')..'\n')
              file:write('['..key..'x]'..stripdata.pop[i].x..'\n')
              file:write('['..key..'y]'..stripdata.pop[i].y..'\n')
            end
          end

          if #stripdata.controls > 0 then
            for c = 1, #stripdata.controls do

              local key = pfx..'c_'..c..'_'

              local ctl = stripdata.controls[c]

              file:write('['..key..'cid]'..ctl.c_id..'\n')
              local ocid = ctl.o_cid
              if not ocid then
                ocid = ctl.c_id
              end
              file:write('['..key..'ocid]'..ocid..'\n')
              file:write('['..key..'fxname]'..ctl.fxname..'\n')
              file:write('['..key..'fxguid]'..nz(ctl.fxguid,'')..'\n')
              file:write('['..key..'fxnum]'..nz(ctl.fxnum,'')..'\n')
              file:write('['..key..'fxfound]'..tostring(ctl.fxfound)..'\n')
              file:write('['..key..'param]'..tostring(ctl.param)..'\n')

              file:write('['..key..'param_info_name]'..ctl.param_info.paramname..'\n')
              file:write('['..key..'param_info_paramnum]'..nz(ctl.param_info.paramnum,'')..'\n')
              file:write('['..key..'param_info_idx]'..nz(ctl.param_info.paramidx,'')..'\n')
              file:write('['..key..'param_info_str]'..nz(ctl.param_info.paramstr,'')..'\n')
              file:write('['..key..'param_info_str2]'..nz(ctl.param_info.paramstr2,'')..'\n')
              file:write('['..key..'param_info_guid]'..nz(ctl.param_info.paramdestguid,'')..'\n')
              file:write('['..key..'param_info_chan]'..nz(ctl.param_info.paramdestchan,'')..'\n')
              file:write('['..key..'param_info_srcchan]'..nz(ctl.param_info.paramsrcchan,'')..'\n')
              file:write('['..key..'ctltype]'..ctl.ctltype..'\n')
              file:write('['..key..'knob_select]'..ctl.knob_select..'\n')
              file:write('['..key..'ctl_info_fn]'..ctl.ctl_info.fn..'\n')
              file:write('['..key..'ctl_info_frames]'..ctl.ctl_info.frames..'\n')
              file:write('['..key..'ctl_info_imageidx]'..ctl.ctl_info.imageidx..'\n')
              file:write('['..key..'ctl_info_cellh]'..ctl.ctl_info.cellh..'\n')
              file:write('['..key..'x]'..ctl.x..'\n')
              file:write('['..key..'y]'..ctl.y..'\n')
              file:write('['..key..'w]'..ctl.w..'\n')
              file:write('['..key..'scale]'..ctl.scale..'\n')
              file:write('['..key..'show_paramname]'..tostring(ctl.show_paramname)..'\n')
              file:write('['..key..'show_paramval]'..tostring(ctl.show_paramval)..'\n')
              file:write('['..key..'ctlname_override]'..nz(ctl.ctlname_override,'')..'\n')
              file:write('['..key..'textcol]'..ctl.textcol..'\n')
              file:write('['..key..'textcolv]'..nz(ctl.textcolv,ctl.textcol)..'\n')
              file:write('['..key..'textoff]'..ctl.textoff..'\n')
              file:write('['..key..'textoffval]'..ctl.textoffval..'\n')
              file:write('['..key..'textoffx]'..ctl.textoffx..'\n')
              file:write('['..key..'textoffvalx]'..ctl.textoffvalx..'\n')
              file:write('['..key..'textsize]'..nz(ctl.textsize,0)..'\n')
              file:write('['..key..'textsizev]'..nz(ctl.textsizev,nz(ctl.textsize,0))..'\n')
              file:write('['..key..'font]'..nz(ctl.font,fontname_def)..'\n')
              file:write('['..key..'val]'..nz(ctl.val,0)..'\n')
              file:write('['..key..'dval]'..nz(ctl.dval,'')..'\n')
              file:write('['..key..'mval]'..nz(ctl.mval,nz(ctl.val,0))..'\n')
              file:write('['..key..'enabledefval]'..tostring(nz(ctl.enabledefval,true))..'\n')
              file:write('['..key..'defval]'..nz(ctl.defval,0)..'\n')
              file:write('['..key..'maxdp]'..nz(ctl.maxdp,-1)..'\n')
              file:write('['..key..'dvaloffset]'..nz(ctl.dvaloffset,'')..'\n')
              file:write('['..key..'minov]'..nz(ctl.minov,'')..'\n')
              file:write('['..key..'maxov]'..nz(ctl.maxov,'')..'\n')
              file:write('['..key..'scalemodex]'..nz(ctl.scalemode,8)..'\n')
              file:write('['..key..'framemodex]'..nz(ctl.framemode,1)..'\n')
              file:write('['..key..'poslock]'..nz(tostring(ctl.poslock),false)..'\n')
              file:write('['..key..'ctllock]'..nz(tostring(ctl.ctllock),false)..'\n')
              file:write('['..key..'horiz]'..tostring(nz(ctl.horiz,false))..'\n')
              file:write('['..key..'knobsens_norm]'..tostring(nz(ctl.knobsens.norm,settings_defknobsens.norm))..'\n')
              file:write('['..key..'knobsens_fine]'..tostring(nz(ctl.knobsens.fine,settings_defknobsens.fine))..'\n')
              file:write('['..key..'knobsens_wheel]'..tostring(nz(ctl.knobsens.wheel,settings_defknobsens.wheel))..'\n')
              file:write('['..key..'knobsens_wheelfine]'..tostring(nz(ctl.knobsens.wheelfine,settings_defknobsens.wheelfine))..'\n')
              file:write('['..key..'knobsens_norm_m]'..tostring(nz(ctl.knobsens.m_norm,1))..'\n')
              file:write('['..key..'knobsens_fine_m]'..tostring(nz(ctl.knobsens.m_fine,1))..'\n')
              file:write('['..key..'knobsens_wheel_m]'..tostring(nz(ctl.knobsens.m_wheel,1))..'\n')
              file:write('['..key..'knobsens_wheelfine_m]'..tostring(nz(ctl.knobsens.m_wheelfine,1))..'\n')

              file:write('['..key..'hidden]'..tostring(nz(ctl.hidden,false))..'\n')
              file:write('['..key..'switcherid]'..tostring(nz(ctl.switcherid,''))..'\n')
              file:write('['..key..'switcher]'..tostring(nz(ctl.switcher,''))..'\n')
              file:write('['..key..'noss]'..tostring(nz(ctl.noss,''))..'\n')
              file:write('['..key..'bypassbg_c]'..tostring(nz(ctl.bypassbg_c,''))..'\n')
              file:write('['..key..'bypassbg_n]'..tostring(nz(ctl.bypassbg_n,''))..'\n')
              file:write('['..key..'bypassbg_v]'..tostring(nz(ctl.bypassbg_v,''))..'\n')
              file:write('['..key..'clickthrough]'..tostring(nz(ctl.clickthrough,''))..'\n')
              file:write('['..key..'dnu]'..tostring(nz(ctl.dnu,''))..'\n')
              file:write('['..key..'orr]'..tostring(nz(ctl.orr,''))..'\n')
              file:write('['..key..'wwtext]'..tostring(nz(ctl.wwtext,''))..'\n')
              file:write('['..key..'limittext]'..tostring(nz(ctl.limittext,''))..'\n')
              file:write('['..key..'textflags]'..tostring(nz(ctl.textflags,''))..'\n')

              file:write('['..key..'id]'..convnum(ctl.id)..'\n')
              file:write('['..key..'grpid]'..convnum(ctl.grpid)..'\n')
              file:write('['..key..'gfxpage]'..(ctl.gfxpage or '0')..'\n')

              file:write('['..key..'ctlcat]'..nz(ctl.ctlcat,'')..'\n')
              file:write('['..key..'tracknum]'..nz(ctl.tracknum,'')..'\n')
              file:write('['..key..'otracknum]'..nz(ctl.otracknum,'')..'\n')
              file:write('['..key..'trackguid]'..nz(ctl.trackguid,'')..'\n')
              file:write('['..key..'memstate]'..tostring(nz(ctl.membtn.state,false))..'\n')
              file:write('['..key..'memmem]'..nz(ctl.membtn.mem,0)..'\n')

              file:write('['..key..'xydata_x]'..nz(ctl.xydata.x,0.5)..'\n')
              file:write('['..key..'xydata_y]'..nz(ctl.xydata.y,0.5)..'\n')
              file:write('['..key..'xydata_snapa]'..nz(ctl.xydata.snapa,1)..'\n')
              file:write('['..key..'xydata_snapb]'..nz(ctl.xydata.snapb,1)..'\n')
              file:write('['..key..'xydata_snapc]'..nz(ctl.xydata.snapc,1)..'\n')
              file:write('['..key..'xydata_snapd]'..nz(ctl.xydata.snapd,1)..'\n')

              file:write('['..key..'macrofader]'..nz(ctl.macrofader,'')..'\n')
              file:write('['..key..'mod]'..nz(ctl.mod,'')..'\n')
              file:write('['..key..'switchfader]'..nz(ctl.switchfader,'')..'\n')

              file:write('['..key..'externalidentifier]'..(ctl.ext_identifier or '')..'\n')

              if lvar.ctltype_buttons[ctl.ctltype] then
                if (ctl.animatetime or 0) > 0 then
                  file:write('['..key..'animatetime]'..ctl.animatetime..'\n')                  
                  file:write('['..key..'animateshape]'..(ctl.animateshape or 1)..'\n')                  
                end
              end

              if ctl.infoctl then
                if ctl.param == 2 then
                  file:write('['..key..'infoctl_closefx]'..tostring(nz(ctl.infoctl.closefx,false))..'\n')
                  file:write('['..key..'infoctl_positionfx]'..tostring(nz(ctl.infoctl.positionfx,false))..'\n')
                end
              end

              if ctl.monext then
                file:write('['..key..'monext_sec]'..nz(ctl.monext.section,'')..'\n')
                file:write('['..key..'monext_key]'..nz(ctl.monext.key,'')..'\n')
                file:write('['..key..'monext_start]'..nz(ctl.monext.range_start,0)..'\n')
                file:write('['..key..'monext_end]'..nz(ctl.monext.range_end,1)..'\n')
              end

              if ctl.thresh then

                file:write('['..key..'thresh_threshoff]'..nz(ctl.thresh.thresh_off,'')..'\n')
                file:write('['..key..'thresh_threshon]'..nz(ctl.thresh.thresh_on,'')..'\n')
                file:write('['..key..'thresh_valoff]'..nz(ctl.thresh.val_off,'')..'\n')
                file:write('['..key..'thresh_valon]'..nz(ctl.thresh.val_on,'')..'\n')
                file:write('['..key..'thresh_invert]'..nz(tostring(ctl.thresh.invert),'')..'\n')

              end

              if ctl.iteminfo then

                file:write('['..key..'iteminfo_itemno]'..nz(ctl.iteminfo.itemno,'')..'\n')
                file:write('['..key..'iteminfo_guid]'..nz(ctl.iteminfo.guid,'')..'\n')
                file:write('['..key..'iteminfo_tracknum]'..nz(ctl.iteminfo.tracknum,'')..'\n')
                file:write('['..key..'iteminfo_trackguid]'..nz(ctl.iteminfo.trackguid,'')..'\n')
                file:write('['..key..'iteminfo_numtakes]'..nz(ctl.iteminfo.numtakes,'')..'\n')
                file:write('['..key..'iteminfo_maxtakes]'..nz(ctl.iteminfo.maxtakes,511)..'\n')
                file:write('['..key..'iteminfo_noteoff]'..tostring(nz(ctl.iteminfo.noteoff,''))..'\n')
                file:write('['..key..'iteminfo_utilfxn]'..nz(ctl.iteminfo.utilfxn,'')..'\n')
                file:write('['..key..'iteminfo_utilguid]'..nz(ctl.iteminfo.utilguid,'')..'\n')

              end

              if ctl.stateinfo then
                if ctl.stateinfo.extname and ctl.stateinfo.key then
                  file:write('['..key..'stateinfo_extname]'..ctl.stateinfo.extname..'\n')
                  file:write('['..key..'stateinfo_key]'..ctl.stateinfo.key..'\n')
                  if ctl.ctlcat == ctlcats.statectl then
                    file:write('['..key..'stateinfo_min]'..ctl.stateinfo.min..'\n')
                    file:write('['..key..'stateinfo_max]'..ctl.stateinfo.max..'\n')
                    file:write('['..key..'stateinfo_step]'..ctl.stateinfo.step..'\n')
                  end
                end
              end

              if ctl.cycledata and ctl.cycledata.statecnt then
                file:write('['..key..'cycledata_statecnt]'..nz(ctl.cycledata.statecnt,0)..'\n')
                file:write('['..key..'cycledata_mapptof]'..tostring(nz(ctl.cycledata.mapptof,false))..'\n')
                file:write('['..key..'cycledata_invert]'..tostring(nz(ctl.cycledata.invert,false))..'\n')
                file:write('['..key..'cycledata_draggable]'..tostring(nz(ctl.cycledata.draggable,false))..'\n')
                file:write('['..key..'cycledata_spread]'..tostring(nz(ctl.cycledata.spread,false))..'\n')
                file:write('['..key..'cycledata_pos]'..tostring(nz(ctl.cycledata.pos,1))..'\n')
                file:write('['..key..'cycledata_posdirty]'..tostring(nz(ctl.cycledata.posdirty,false))..'\n')
                if nz(ctl.cycledata.statecnt,0) > 0 then
                  for i = 1, ctl.cycledata.statecnt do
                    local key = pfx..'c_'..c..'_cyc_'..i..'_'
                    file:write('['..key..'val]'..nz(ctl.cycledata[i].val,0)..'\n')
                    file:write('['..key..'dispval]'..nz(ctl.cycledata[i].dispval,'')..'\n')
                    file:write('['..key..'dv]'..nz(ctl.cycledata[i].dv,'')..'\n')
                    file:write('['..key..'startval]'..nz(ctl.cycledata[i].startval,'')..'\n')
                    file:write('['..key..'nextval]'..nz(ctl.cycledata[i].nextval,'')..'\n')
                    if ctl.cycledata[i].tsp then
                      file:write('['..key..'tsp_swid]'..nz(ctl.cycledata[i].tsp.swid,'')..'\n')
                      file:write('['..key..'tsp_grpid]'..nz(ctl.cycledata[i].tsp.grpid,'')..'\n')
                    end
                  end
                end
              else
                file:write('['..key..'cycledata_statecnt]'..0 ..'\n')
              end

              if ctl.midiout then
                file:write('['..key..'midiout_output]'..nz(ctl.midiout.output,'')..'\n')
                file:write('['..key..'midiout_mchan]'..nz(ctl.midiout.mchan,'')..'\n')
                file:write('['..key..'midiout_msg3]'..nz(ctl.midiout.msg3,'')..'\n')
                file:write('['..key..'midiout_msgtype]'..nz(ctl.midiout.msgtype,4)..'\n')
                file:write('['..key..'midiout_osc]'..nz(ctl.midiout.osc,'')..'\n')
                file:write('['..key..'midiout_vmin]'..nz(ctl.midiout.vmin,0)..'\n')
                file:write('['..key..'midiout_vmax]'..nz(ctl.midiout.vmax,127)..'\n')
                file:write('['..key..'midiout_focus]'..nz(ctl.midiout.focus,1)..'\n')
                file:write('['..key..'midiout_focus_wintit]'..nz(ctl.midiout.focus_wintit,'')..'\n')
                file:write('['..key..'midiout_focus_winexact]'..tostring(nz(ctl.midiout.focus_winexact,false))..'\n')
                file:write('['..key..'midiout_updategfx]'..tostring(nz(ctl.midiout.updategfx,false))..'\n')
                file:write('['..key..'midiout_onmu]'..tostring(nz(ctl.midiout.onmu,false))..'\n')
              end

              if ctl.rcmdata and #ctl.rcmdata > 0 then
                file:write('['..key..'rcmdata_cnt]'..#ctl.rcmdata ..'\n')
                for r = 1, #ctl.rcmdata do
                  local key = pfx..'c_'..c..'_rcm_'..r..'_'
                  file:write('['..key..'name]'..ctl.rcmdata[r].name..'\n')
                  file:write('['..key..'msb]'..ctl.rcmdata[r].msb..'\n')
                  file:write('['..key..'lsb]'..ctl.rcmdata[r].lsb..'\n')
                  file:write('['..key..'prog]'..ctl.rcmdata[r].prog..'\n')
                  file:write('['..key..'nebfn]'..nz(ctl.rcmdata[r].nebfn,'')..'\n')
                end
              else
                file:write('['..key..'rcmdata_cnt]'..0 ..'\n')
              end

              if ctl.rcmrefresh then
                file:write('['..key..'rcmrefresh_guid]'..nz(ctl.rcmrefresh.guid,'')..'\n')
                file:write('['..key..'rcmrefresh_delay]'..nz(ctl.rcmrefresh.delay,'')..'\n')
                file:write('['..key..'rcmrefresh_setvals]'..tostring(nz(ctl.rcmrefresh.setvals,''))..'\n')
              end

              if ctl.addfx and #ctl.addfx > 0 then
                file:write('['..key..'addfx_cnt]'..#ctl.addfx ..'\n')
                for afx = 1, #ctl.addfx do
                  local key = pfx..'c_'..c..'_addfx_'..afx..'_'
                  file:write('['..key..'trn]'..nz(ctl.addfx[afx].trn,-2)..'\n')
                  file:write('['..key..'trguid]'..nz(ctl.addfx[afx].trguid,'')..'\n')
                  file:write('['..key..'fxnum]'..nz(ctl.addfx[afx].fxnum,0)..'\n')
                  file:write('['..key..'guid]'..nz(ctl.addfx[afx].guid,'')..'\n')
                end
              end

              if ctl.gauge then
                file:write('['..key..'gauge]'..tostring(true)..'\n')

                file:write('['..key..'gauge_type]'..nz(ctl.gauge.type,1)..'\n')
                file:write('['..key..'gauge_x_offs]'..nz(ctl.gauge.x_offs,0)..'\n')
                file:write('['..key..'gauge_y_offs]'..nz(ctl.gauge.y_offs,0)..'\n')
                file:write('['..key..'gauge_radius]'..nz(ctl.gauge.radius,50)..'\n')
                file:write('['..key..'gauge_arclen]'..nz(ctl.gauge.arclen,1)..'\n')
                file:write('['..key..'gauge_rotation]'..nz(ctl.gauge.rotation,0)..'\n')
                file:write('['..key..'gauge_ticks]'..nz(ctl.gauge.ticks,0)..'\n')
                file:write('['..key..'gauge_tick_size]'..nz(ctl.gauge.tick_size,2)..'\n')
                file:write('['..key..'gauge_tick_offs]'..nz(ctl.gauge.tick_offs,1)..'\n')
                file:write('['..key..'gauge_val_freq]'..nz(ctl.gauge.val_freq,0)..'\n')
                file:write('['..key..'gauge_col_tick]'..nz(ctl.gauge.col_tick,'205 205 205')..'\n')
                file:write('['..key..'gauge_col_arc]'..nz(ctl.gauge.col_arc,'205 205 205')..'\n')
                file:write('['..key..'gauge_col_val]'..nz(ctl.gauge.col_val,'205 205 205')..'\n')
                file:write('['..key..'gauge_show_arc]'..tostring(nz(ctl.gauge.show_arc,true))..'\n')
                file:write('['..key..'gauge_show_tick]'..tostring(nz(ctl.gauge.show_tick,true))..'\n')
                file:write('['..key..'gauge_tick_shape]'..tostring(nz(ctl.gauge.tick_shape,''))..'\n')
                file:write('['..key..'gauge_show_val]'..tostring(nz(ctl.gauge.show_val,true))..'\n')
                file:write('['..key..'gauge_val_dp]'..nz(ctl.gauge.val_dp,0)..'\n')
                file:write('['..key..'gauge_font]'..nz(ctl.gauge.font,fontname_def)..'\n')
                file:write('['..key..'gauge_fontsz]'..nz(ctl.gauge.fontsz,0)..'\n')
                file:write('['..key..'gauge_spread]'..tostring(nz(ctl.gauge.spread,''))..'\n')
                file:write('['..key..'gauge_mapptof]'..tostring(nz(ctl.gauge.mapptof,''))..'\n')
                file:write('['..key..'gauge_numonly]'..tostring(nz(ctl.gauge.numonly,''))..'\n')
                file:write('['..key..'gauge_abbrev]'..tostring(nz(ctl.gauge.abbrev,''))..'\n')
                file:write('['..key..'gauge_valcnt]'..#ctl.gauge.vals..'\n')

                if ctl.gauge.vals and #ctl.gauge.vals > 0 then
                  for gv = 1, #ctl.gauge.vals do
                    local key = pfx..'c_'..c..'_gaugevals_'..gv..'_'
                    file:write('['..key..'val]'..nz(ctl.gauge.vals[gv].val,0)..'\n')
                    file:write('['..key..'dval]'..nz(ctl.gauge.vals[gv].dval,'-')..'\n')
                    file:write('['..key..'dover]'..nz(ctl.gauge.vals[gv].dover,'')..'\n')
                    file:write('['..key..'nudge]'..nz(ctl.gauge.vals[gv].nudge,0)..'\n')
                  end
                end
              end

              if ctl.macrotype then
                file:write('['..key..'macrotype]'..ctl.macrotype..'\n')
              end

              if ctl.macroctl then
                local mcnt = #ctl.macroctl
                file:write('['..key..'macromon]'..nz(ctl.macromon,'')..'\n')
                file:write('['..key..'macroctl_cnt]'..mcnt..'\n')
                for mc = 1,mcnt do
                  local key = pfx..'c_'..c..'_mc_'..mc..'_'
                  file:write('['..key..'c_id]'..ctl.macroctl[mc].c_id..'\n')
                  file:write('['..key..'ctl]'..ctl.macroctl[mc].ctl..'\n')
                  file:write('['..key..'A]'..ctl.macroctl[mc].A_val..'\n')
                  file:write('['..key..'B]'..ctl.macroctl[mc].B_val..'\n')
                  file:write('['..key..'shape]'..ctl.macroctl[mc].shape..'\n')
                  file:write('['..key..'mute]'..tostring(nz(ctl.macroctl[mc].mute,false))..'\n')
                  file:write('['..key..'bi]'..tostring(nz(ctl.macroctl[mc].bi,false))..'\n')
                  file:write('['..key..'inv]'..tostring(nz(ctl.macroctl[mc].inv,false))..'\n')
                  file:write('['..key..'rel]'..tostring(nz(ctl.macroctl[mc].relative,false))..'\n')
                end
              else
                file:write('['..key..'macroctl_cnt]'..0 ..'\n')
              end

              if ctl.random then

                local key = pfx..'c_'..c..'_rnd_'
                file:write('['..key..'par_c_id]'..tostring(ctl.random.parent_cid)..'\n')
                file:write('['..key..'par_ctl]'..tostring(ctl.random.parent)..'\n')
                file:write('['..key..'sst]'..ctl.random.sst..'\n')
                file:write('['..key..'sso]'..tostring(nz(ctl.random.snapshotsonly,false))..'\n')
                file:write('['..key..'ua]'..tostring(nz(ctl.random.useadv,false))..'\n')
                file:write('['..key..'ccnt]'..#ctl.random.ctls..'\n')

                local lgs = {}

                if #ctl.random.ctls > 0 then
                  for cc = 1, #ctl.random.ctls do
                    local key = pfx..'c_'..c..'_rnd_ctls_'..cc..'_'
                    file:write('['..key..'c_id]'..ctl.random.ctls[cc].c_id..'\n')
                    file:write('['..key..'ctl]'..ctl.random.ctls[cc].ctl..'\n')
                    file:write('['..key..'min]'..ctl.random.ctls[cc].min..'\n')
                    file:write('['..key..'max]'..ctl.random.ctls[cc].max..'\n')
                    file:write('['..key..'linkgrp]'..nz(ctl.random.ctls[cc].linkgrp,'')..'\n')
                    file:write('['..key..'rprob]'..ctl.random.ctls[cc].rprob..'\n')
                    file:write('['..key..'bias]'..ctl.random.ctls[cc].bias..'\n')
                    file:write('['..key..'amount]'..nz(ctl.random.ctls[cc].amount,'')..'\n')
                    file:write('['..key..'inverted]'..tostring(nz(ctl.random.ctls[cc].inverted,false))..'\n')
                    file:write('['..key..'wild]'..nz(ctl.random.ctls[cc].wild,0)..'\n')
                    file:write('['..key..'snap]'..tostring(nz(ctl.random.ctls[cc].snap,false))..'\n')

                    if ctl.random.ctls[cc].linkgrp then
                      lgs[#lgs+1] = ctl.random.ctls[cc].linkgrp
                    end
                  end
                end

                if #lgs > 0 then
                  for l = 1, #lgs do
                    local lg = lgs[l]
                    local key = pfx..'c_'..c..'_rnd_lgs_'..lg..'_'
                    file:write('['..key..'type]'..ctl.random.linkgrps[lg].type..'\n')
                    file:write('['..key..'X]'..ctl.random.linkgrps[lg].X..'\n')
                    file:write('['..key..'snap]'..tostring(nz(ctl.random.linkgrps[lg].snap,false))..'\n')
                  end
                end
              end

              if ctl.eqbands then
                local bcnt = #ctl.eqbands
                file:write('['..key..'eqband_cnt]'..bcnt..'\n')
                if bcnt > 0 then
                  for bc = 1,bcnt do
                    local key = pfx..'c_'..c..'_eqband_'..bc..'_'
                    file:write('['..key..'posmin]'..nz(ctl.eqbands[bc].posmin,'')..'\n')
                    file:write('['..key..'posmax]'..nz(ctl.eqbands[bc].posmax,'')..'\n')
                    file:write('['..key..'col]'..nz(ctl.eqbands[bc].col,'')..'\n')
                    file:write('['..key..'fxnum]'..nz(ctl.eqbands[bc].fxnum,'')..'\n')
                    file:write('['..key..'fxguid]'..nz(ctl.eqbands[bc].fxguid,'')..'\n')
                    file:write('['..key..'fxname]'..nz(ctl.eqbands[bc].fxname,'')..'\n')
                    file:write('['..key..'freq_param]'..nz(ctl.eqbands[bc].freq_param,'')..'\n')
                    file:write('['..key..'freq_param_name]'..nz(ctl.eqbands[bc].freq_param_name,'')..'\n')
                    file:write('['..key..'gain_param]'..nz(ctl.eqbands[bc].gain_param,'')..'\n')
                    file:write('['..key..'gain_param_name]'..nz(ctl.eqbands[bc].gain_param_name,'')..'\n')
                    file:write('['..key..'q_param]'..nz(ctl.eqbands[bc].q_param,'')..'\n')
                    file:write('['..key..'q_param_name]'..nz(ctl.eqbands[bc].q_param_name,'')..'\n')
                    file:write('['..key..'bypass_param]'..nz(ctl.eqbands[bc].bypass_param,'')..'\n')
                    file:write('['..key..'bypass_param_name]'..nz(ctl.eqbands[bc].bypass_param_name,'')..'\n')
                    file:write('['..key..'c1_param]'..nz(ctl.eqbands[bc].c1_param,'')..'\n')
                    file:write('['..key..'c1_param_name]'..nz(ctl.eqbands[bc].c1_param_name,'')..'\n')
                    file:write('['..key..'c2_param]'..nz(ctl.eqbands[bc].c2_param,'')..'\n')
                    file:write('['..key..'c2_param_name]'..nz(ctl.eqbands[bc].c2_param_name,'')..'\n')
                    file:write('['..key..'c3_param]'..nz(ctl.eqbands[bc].c3_param,'')..'\n')
                    file:write('['..key..'c3_param_name]'..nz(ctl.eqbands[bc].c3_param_name,'')..'\n')
                    file:write('['..key..'c4_param]'..nz(ctl.eqbands[bc].c4_param,'')..'\n')
                    file:write('['..key..'c4_param_name]'..nz(ctl.eqbands[bc].c4_param_name,'')..'\n')
                    file:write('['..key..'c5_param]'..nz(ctl.eqbands[bc].c5_param,'')..'\n')
                    file:write('['..key..'c5_param_name]'..nz(ctl.eqbands[bc].c5_param_name,'')..'\n')
                    file:write('['..key..'freq_val]'..nz(ctl.eqbands[bc].freq_val,'')..'\n')
                    file:write('['..key..'gain_val]'..nz(ctl.eqbands[bc].gain_val,'')..'\n')
                    file:write('['..key..'q_val]'..nz(ctl.eqbands[bc].q_val,'')..'\n')
                    file:write('['..key..'c1_val]'..nz(ctl.eqbands[bc].c1_val,'')..'\n')
                    file:write('['..key..'c2_val]'..nz(ctl.eqbands[bc].c2_val,'')..'\n')
                    file:write('['..key..'c3_val]'..nz(ctl.eqbands[bc].c3_val,'')..'\n')
                    file:write('['..key..'c4_val]'..nz(ctl.eqbands[bc].c4_val,'')..'\n')
                    file:write('['..key..'c5_val]'..nz(ctl.eqbands[bc].c5_val,'')..'\n')

                    file:write('['..key..'freq_min]'..nz(ctl.eqbands[bc].freq_min,'')..'\n')
                    file:write('['..key..'freq_max]'..nz(ctl.eqbands[bc].freq_max,'')..'\n')
                    file:write('['..key..'gain_min]'..nz(ctl.eqbands[bc].gain_min,'')..'\n')
                    file:write('['..key..'gain_max]'..nz(ctl.eqbands[bc].gain_max,'')..'\n')
                    file:write('['..key..'bandtype]'..nz(ctl.eqbands[bc].bandtype,'')..'\n')
                    file:write('['..key..'bandname]'..nz(ctl.eqbands[bc].bandname,'')..'\n')
                    file:write('['..key..'khz]'..nz(tostring(ctl.eqbands[bc].khz),tostring(false))..'\n')
                    file:write('['..key..'gaininv]'..nz(tostring(ctl.eqbands[bc].gain_inv),tostring(false))..'\n')
                    file:write('['..key..'qinv]'..nz(tostring(ctl.eqbands[bc].q_inv),tostring(false))..'\n')
                    file:write('['..key..'gmin]'..nz(ctl.eqbands[bc].gmin,'')..'\n')
                    file:write('['..key..'gmax]'..nz(ctl.eqbands[bc].gmax,'')..'\n')

                    file:write('['..key..'freq_def]'..nz(ctl.eqbands[bc].freq_def,'')..'\n')
                    file:write('['..key..'gain_def]'..nz(ctl.eqbands[bc].gain_def,'')..'\n')
                    file:write('['..key..'q_def]'..nz(ctl.eqbands[bc].q_def,'')..'\n')
                    file:write('['..key..'c1_def]'..nz(ctl.eqbands[bc].c1_def,'')..'\n')
                    file:write('['..key..'c2_def]'..nz(ctl.eqbands[bc].c2_def,'')..'\n')
                    file:write('['..key..'c3_def]'..nz(ctl.eqbands[bc].c3_def,'')..'\n')
                    file:write('['..key..'c4_def]'..nz(ctl.eqbands[bc].c4_def,'')..'\n')
                    file:write('['..key..'c5_def]'..nz(ctl.eqbands[bc].c5_def,'')..'\n')

                    local key = pfx..'c_'..c..'_eqband_'..bc..'_'
                    if ctl.eqbands[bc].lookmap then
                      local lcnt = #ctl.eqbands[bc].lookmap
                      file:write('['..key..'lookmap_cnt]'..lcnt..'\n')

                      if lcnt > 0 then
                        for lc = 1, lcnt do
                          local key = pfx..'c_'..c..'_eqband_'..bc..'_lm_'..lc..'_'
                          file:write('['..key..'pix]'..nz(ctl.eqbands[bc].lookmap[lc].pix,'')..'\n')
                          file:write('['..key..'hz]'..nz(ctl.eqbands[bc].lookmap[lc].hz,'')..'\n')
                        end
                      end

                    else
                      file:write('['..key..'lookmap_cnt]'..0 ..'\n')
                    end

                    local key = pfx..'c_'..c..'_eqband_'..bc..'_'
                    if ctl.eqbands[bc].gmap then
                      local lcnt = #ctl.eqbands[bc].gmap
                      file:write('['..key..'gmap_cnt]'..lcnt..'\n')

                      if lcnt > 0 then
                        for lc = 1, lcnt do
                          local key = pfx..'c_'..c..'_eqband_'..bc..'_gm_'..lc..'_'
                          file:write('['..key..'pix]'..nz(ctl.eqbands[bc].gmap[lc].pix,'')..'\n')
                          file:write('['..key..'db]'..nz(ctl.eqbands[bc].gmap[lc].db,'')..'\n')
                        end
                      end

                    else
                      file:write('['..key..'gmap_cnt]'..0 ..'\n')
                    end

                  end

                end
              else
                file:write('['..key..'eqband_cnt]'..0 ..'\n')
              end

              if ctl.eqgraph and type(ctl.eqgraph) == 'table' then

                local key = pfx..'c_'..c..'_'
                file:write('['..key..'ecg_graph]'..tostring(true)..'\n')
                file:write('['..key..'ecg_gmin]'..nz(ctl.eqgraph.gmin,'')..'\n')
                file:write('['..key..'ecg_gmax]'..nz(ctl.eqgraph.gmax,'')..'\n')
                file:write('['..key..'ecg_posmin]'..nz(ctl.eqgraph.posmin,'')..'\n')
                file:write('['..key..'ecg_posmax]'..nz(ctl.eqgraph.posmax,'')..'\n')

                if ctl.eqgraph.lookmap then
                  local lcnt = #ctl.eqgraph.lookmap
                  file:write('['..key..'ecg_lookmap_cnt]'..lcnt..'\n')

                  if lcnt > 0 then
                    for lc = 1, lcnt do
                      local key = pfx..'c_'..c..'_ecg_lm_'..lc..'_'
                      file:write('['..key..'pix]'..nz(ctl.eqgraph.lookmap[lc].pix,'')..'\n')
                      file:write('['..key..'hz]'..nz(ctl.eqgraph.lookmap[lc].hz,'')..'\n')
                    end
                  end

                else
                  file:write('['..key..'ecg_lookmap_cnt]'..0 ..'\n')
                end

                local key = pfx..'c_'..c..'_'
                if ctl.eqgraph.gmap then
                  local lcnt = #ctl.eqgraph.gmap
                  file:write('['..key..'ecg_gmap_cnt]'..lcnt..'\n')

                  if lcnt > 0 then
                    for lc = 1, lcnt do
                      local key = pfx..'c_'..c..'_ecg_gm_'..lc..'_'
                      file:write('['..key..'pix]'..nz(ctl.eqgraph.gmap[lc].pix,'')..'\n')
                      file:write('['..key..'db]'..nz(ctl.eqgraph.gmap[lc].db,'')..'\n')
                    end
                  end

                else
                  file:write('['..key..'ecg_gmap_cnt]'..0 ..'\n')
                end

              end

              if ctl.rsdata then
                local key = pfx..'c_'..c..'_rs5k_'
                file:write('['..key..'samplefolder]'..nz(ctl.rsdata.samplefolder,'')..'\n')
                file:write('['..key..'recurse]'..nz(tostring(ctl.rsdata.recurse),'')..'\n')

                file:write('['..key..'samplecnt]'..#ctl.rsdata.samples..'\n')
                for sm = 1, #ctl.rsdata.samples do
                  local key = pfx..'c_'..c..'_rs5k_sample_'..sm..'_'
                  file:write('['..key..'fol]'..nz(ctl.rsdata.samples[sm].fol,'')..'\n')
                  file:write('['..key..'fn]'..nz(ctl.rsdata.samples[sm].fn,'')..'\n')
                  file:write('['..key..'fav]'..nz(tostring(ctl.rsdata.samples[sm].fav),false)..'\n')
                end

              end

              
              local key = pfx..'c_'..c..'_adjust_'
              if ctl.adjust_active == 1 and ctl.adjust then
                file:write('['..key..'active]1\n')
                file:write('['..key..'bright]'..(ctl.adjust.bright or 255)..'\n')
                file:write('['..key..'contrast]'..(ctl.adjust.contrast or 255)..'\n')
                file:write('['..key..'r]'..(ctl.adjust.r or 255)..'\n')
                file:write('['..key..'g]'..(ctl.adjust.g or 255)..'\n')
                file:write('['..key..'b]'..(ctl.adjust.b or 255)..'\n')
              else
                file:write('['..key..'active]0\n')
              end

            end
          end

          if #stripdata.graphics > 0 then
            for g = 1, #stripdata.graphics do

              local key = pfx..'g_'..g..'_'

              file:write('['..key..'gid]'..nz(stripdata.graphics[g].g_id,'')..'\n')
              file:write('['..key..'fn]'..stripdata.graphics[g].fn..'\n')
              --file:write('['..key..'imageidx]'..stripdata.graphics[g].imageidx..'\n')
              file:write('['..key..'x]'..stripdata.graphics[g].x..'\n')
              file:write('['..key..'y]'..stripdata.graphics[g].y..'\n')
              file:write('['..key..'w]'..stripdata.graphics[g].w..'\n')
              file:write('['..key..'h]'..stripdata.graphics[g].h..'\n')
              file:write('['..key..'stretchw]'..nz(stripdata.graphics[g].stretchw,stripdata.graphics[g].w)..'\n')
              file:write('['..key..'stretchh]'..nz(stripdata.graphics[g].stretchh,stripdata.graphics[g].h)..'\n')
              file:write('['..key..'scale]'..stripdata.graphics[g].scale..'\n')
              file:write('['..key..'id]'..convnum(stripdata.graphics[g].id)..'\n')
              file:write('['..key..'grpid]'..convnum(stripdata.graphics[g].grpid)..'\n')
              file:write('['..key..'gfxpage]'..(stripdata.graphics[g].gfxpage or '0')..'\n')

              file:write('['..key..'gfxtype]'..nz(stripdata.graphics[g].gfxtype, lvar.gfxtype.img)..'\n')
              file:write('['..key..'font_idx]'..nz(stripdata.graphics[g].font.idx, '')..'\n')
              file:write('['..key..'font_name]'..nz(stripdata.graphics[g].font.name, '')..'\n')
              file:write('['..key..'font_size]'..nz(stripdata.graphics[g].font.size, '')..'\n')
              file:write('['..key..'font_bold]'..nz(tostring(stripdata.graphics[g].font.bold), '')..'\n')
              file:write('['..key..'font_italics]'..nz(tostring(stripdata.graphics[g].font.italics), '')..'\n')
              file:write('['..key..'font_underline]'..nz(tostring(stripdata.graphics[g].font.underline), '')..'\n')
              file:write('['..key..'font_vertical]'..nz(tostring(stripdata.graphics[g].font.vertical), '')..'\n')
              file:write('['..key..'font_shadow]'..nz(tostring(stripdata.graphics[g].font.shadow), '')..'\n')
              file:write('['..key..'font_shadowx]'..nz(stripdata.graphics[g].font.shadow_x, '')..'\n')
              file:write('['..key..'font_shadowy]'..nz(stripdata.graphics[g].font.shadow_y, '')..'\n')
              file:write('['..key..'font_shadowa]'..nz(stripdata.graphics[g].font.shadow_a, '')..'\n')
              file:write('['..key..'text]'..nz(stripdata.graphics[g].text, '')..'\n')
              file:write('['..key..'text_col]'..nz(stripdata.graphics[g].text_col, '')..'\n')
              file:write('['..key..'poslock]'..nz(tostring(stripdata.graphics[g].poslock), false)..'\n')
              file:write('['..key..'switcher]'..tostring(nz(stripdata.graphics[g].switcher,''))..'\n')
              file:write('['..key..'bright]'..tostring(nz(stripdata.graphics[g].bright,0.5))..'\n')
              file:write('['..key..'contr]'..tostring(nz(stripdata.graphics[g].contr,0.5))..'\n')
              file:write('['..key..'rmult]'..tostring(nz(stripdata.graphics[g].rmult,0.5))..'\n')
              file:write('['..key..'gmult]'..tostring(nz(stripdata.graphics[g].gmult,0.5))..'\n')
              file:write('['..key..'bmult]'..tostring(nz(stripdata.graphics[g].bmult,0.5))..'\n')
              file:write('['..key..'alpha]'..tostring(nz(stripdata.graphics[g].alpha,1))..'\n')
              file:write('['..key..'stretchmode]'..tostring(nz(stripdata.graphics[g].stretchmode,1))..'\n')
              file:write('['..key..'edgesz]'..tostring(nz(stripdata.graphics[g].edgesz,8))..'\n')
              file:write('['..key..'gfx_shadow]'..tostring(nz(stripdata.graphics[g].shadow,false))..'\n')

            end
          end

        else
          file:write('['..key..'surface_x]'..0 ..'\n')
          file:write('['..key..'surface_y]'..0 ..'\n')
          file:write('['..key..'controls_count]'..0 ..'\n')
          file:write('['..key..'graphics_count]'..0 ..'\n')
        end

    return reaper.time_precise() - t

  end


  function SaveEditedData()
    for i, v in pairs(g_edstrips) do
      SaveStripData_FN(tracks[i].strip)
    end
  end

  function GetSaveFN(tmp)

    local save_path=paths.projsave_path..'/'
    if settings_savedatainprojectfolder == true then
      save_path=reaper.GetProjectPath('')..'/'
    end

    local pn = GetProjectName()
    
    local projname = string.sub(pn,0,string.len(pn)-4) --..'_'..PROJECTID
    if projname == nil or projname == '' then
      projname = 'unnamed_project'
    end
    local pn2 = projname
    
    if save_subfolder and save_subfolder ~= '' then
      local sf = save_subfolder
      if sf == '#' then
        sf = projname
        if projname == 'unnamed_project' then
          projname = projname..'_'..PROJECTID
        end
      end
      projname = sf..'/'..projname
      reaper.RecursiveCreateDirectory(save_path..sf,1)
    end

    local setno = string.sub(lvar.STRIPSET,11)
    local setstr = ''
    if setno ~= '1' then
      setstr = '_SS'..setno
    end

    if tmp then
      fn=projname..setstr..".lbxstripper__"
    else
      fn=projname..setstr..".lbxstripper"
    end
    local ffn=save_path..fn

    return ffn, save_path, fn, reaper.GetProjectPath('')..'/'..pn2..'.rpp'

  end

  function LoadGlobOvProjSettingsFile(file,ffn)

    local ffn
    if file == nil then
      ffn=paths.resource_path..'GlobalOverrideProjectSettings.lbxprojsett'
    end

    local ret = false
    if ffn and reaper.file_exists(ffn) then
      local flines = io.lines
      local data = {}
      local match = string.match

      for line in flines(ffn) do
        local idx, val = match(line,'%[(.-)%](.*)') --decipher(line)
        if idx then
          val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
          data[idx] = val
        end
      end

      settings_gridsize = tonumber(zn(data['gridsize'],16))
      settings_showgrid = tobool(zn(data['showgrid'],true))
      show_editbar = tobool(zn(data['showeditbar'],not settings_hideeditbaronnewproject))
      ogrid = settings_gridsize
      osg = settings_showgrid
      settings_locksurface = tobool(zn(data['locksurface'],false))
      track_select = tonumber(zn(data['lasttrack'],0))
      xxy_gravity = tonumber(zn(data['metalite_gravity'],xxy_gravity))
      snapshot_win_pos = {x = tonumber(zn(data['snapwinpos_x'])),
                          y = tonumber(zn(data['snapwinpos_y']))}
      show_snapshots = tobool(zn(data['showsnap'],false))
      hideunusedtracks = tobool(zn(data['hidetracks'],false))

      lvar.stripbrowser.page = tonumber(zn(data['sb_page'],lvar.stripbrowser.page))
      lvar.stripbrowser.favs = tobool(zn(data['sb_favs'],lvar.stripbrowser.favs))
      stripfol_select = tonumber(zn(data['sb_fol'],stripfol_select))
      if not strip_folders[stripfol_select] then
        stripfol_select = 0
      end
      settings_localfaders = tobool(zn(data['localfaders'],settings_localfaders))

      local ww, wh = tonumber(zn(data['win_w'])), tonumber(zn(data['win_h']))
      if tonumber(ww) ~= nil and tonumber(wh) ~= nil then
        gfx1 = {main_w = tonumber(ww),
                main_h = tonumber(wh)}
      else
        gfx1 = {main_w = 800,
                main_h = 450}
      end
      Lokasenna_Window_At_Center(gfx1.main_w,gfx1.main_h)

      ret = true
    end

    return ret
  end

  function SaveGlobOvProjSettingsInFile(file, ffn)

    local ffn
    if file == nil then
      ffn=paths.resource_path..'GlobalOverrideProjectSettings.lbxprojsett'
      file=io.open(ffn,"w")
    end

    if file then
      file:write('[version]'..lvar.VERSION..'\n')

      file:write('[gridsize]'..ogrid..'\n')
      file:write('[showgrid]'..tostring(settings_showgrid)..'\n')
      file:write('[showeditbar]'..tostring(show_editbar)..'\n')
      file:write('[locksurface]'..tostring(settings_locksurface)..'\n')
      file:write('[lasttrack]'..track_select..'\n')
      file:write('[metalite_gravity]'..xxy_gravity..'\n')

      if snapshot_win_pos == nil then snapshot_win_pos = {} end
      file:write('[snapwinpos_x]'..nz(snapshot_win_pos.x,'')..'\n')
      file:write('[snapwinpos_y]'..nz(snapshot_win_pos.y,'')..'\n')

      file:write('[showsnap]'..tostring(show_snapshots)..'\n')
      file:write('[hidetracks]'..tostring(hideunusedtracks)..'\n')
      file:write('[localfaders]'..tostring(settings_localfaders)..'\n')
      file:write('[sb_favs]'..tostring(lvar.stripbrowser.favs)..'\n')
      file:write('[sb_page]'..tostring(lvar.stripbrowser.page)..'\n')
      file:write('[sb_fol]'..tostring(stripfol_select)..'\n')
      file:write('[win_w]'..nz(gfx1.main_w,800)..'\n')
      file:write('[win_h]'..nz(gfx1.main_h,450)..'\n')

    end
    file:close()

  end

  function SaveData(tmp, bak, noclean, fffn, epflag)

    local SCRIPT = lvar.SCRIPT

    ZeroProjectFlags()

    DBGOut('')
    DBGOut('*** SAVING DATA ***')

    --SaveSettings()

    if lvar.striploadoverride_active and not fffn then
      --[[reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_grp_count',#lvar.dm_trackbtns)
      reaper.SetProjExtState(0,SCRIPT,'dm_tbidx',lvar.dm_tbidx)
      for ii = 1, #lvar.dm_trackbtns do
        reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_name_'..string.format('%i',ii),lvar.dm_trackbtns[ii].name or '')
        if #lvar.dm_trackbtns[ii] > 0 then
          reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_count_'..string.format('%i',ii),#lvar.dm_trackbtns[ii])
          for i = 1, #lvar.dm_trackbtns[ii] do
            local key = string.format('%i',ii)..'_'..string.format('%i',i)
            reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_guid_'..key, lvar.dm_trackbtns[ii][i].guid)
            reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_trn_'..key, lvar.dm_trackbtns[ii][i].trn)
          end
        end
      end
      if lvar.dm_backtrack then
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_guid', lvar.dm_backtrack.guid)
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_trn', lvar.dm_backtrack.trn)
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_page', lvar.dm_backtrack.page)
      end]]

      DM_SaveData(tmp)

      reaper.SetProjExtState(0,SCRIPT,'savedok',tostring(true))
      SaveGlobOvProjSettingsInFile()
      return
    end

    local s, p, c, g
    if not fffn then
      --backup datafn
      local datafn = GPES('lbxstripper_datafile', true)
      reaper.SetProjExtState(0,SCRIPT,"","") -- clear first

      local dmfn = DM_SaveData(tmp) 

      --this will retain any original data file name when the overridden datafile is used
      if datafn then
        reaper.SetProjExtState(0,SCRIPT,'lbxstripper_datafile',datafn)
      end
      reaper.SetProjExtState(0,SCRIPT,'version',lvar.VERSION)
      if PROJECTID then
        reaper.SetProjExtState(0,SCRIPT,'projectid',PROJECTID)
      end
      reaper.SetProjExtState(0,SCRIPT,'gridsize',ogrid)
      reaper.SetProjExtState(0,SCRIPT,'showgrid',tostring(settings_showgrid))
      reaper.SetProjExtState(0,SCRIPT,'showeditbar',tostring(show_editbar))
      reaper.SetProjExtState(0,SCRIPT,'locksurface',tostring(settings_locksurface))
      reaper.SetProjExtState(0,SCRIPT,'lasttrack',track_select)
      reaper.SetProjExtState(0,SCRIPT,'metalite_gravity',xxy_gravity)
      if snapshot_win_pos == nil then snapshot_win_pos = {} end
      reaper.SetProjExtState(0,SCRIPT,'snapwinpos_x',nz(snapshot_win_pos.x,''))
      reaper.SetProjExtState(0,SCRIPT,'snapwinpos_y',nz(snapshot_win_pos.y,''))
      reaper.SetProjExtState(0,SCRIPT,'showsnap',tostring(show_snapshots))
      reaper.SetProjExtState(0,SCRIPT,'hidetracks',tostring(hideunusedtracks))
      reaper.SetProjExtState(0,SCRIPT,'localfaders',tostring(settings_localfaders))

      reaper.SetProjExtState(0,SCRIPT,'sb_favs',tostring(lvar.stripbrowser.favs))
      reaper.SetProjExtState(0,SCRIPT,'sb_page',tostring(lvar.stripbrowser.page))
      reaper.SetProjExtState(0,SCRIPT,'sb_fol',tostring(stripfol_select))

      if gfx1 then
        reaper.SetProjExtState(0,SCRIPT,'win_w',nz(gfx1.main_w,800))
        reaper.SetProjExtState(0,SCRIPT,'win_h',nz(gfx1.main_h,450))
      end

      --[[reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_grp_count',#lvar.dm_trackbtns)
      reaper.SetProjExtState(0,SCRIPT,'dm_tbidx',lvar.dm_tbidx)
      for ii = 1, #lvar.dm_trackbtns do
        reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_name_'..string.format('%i',ii),lvar.dm_trackbtns[ii].name or '')
        if #lvar.dm_trackbtns[ii] > 0 then
          reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_count_'..string.format('%i',ii),#lvar.dm_trackbtns[ii])
          for i = 1, #lvar.dm_trackbtns[ii] do
            local key = string.format('%i',ii)..'_'..string.format('%i',i)
            reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_guid_'..key, lvar.dm_trackbtns[ii][i].guid)
            reaper.SetProjExtState(0,SCRIPT,'dm_trackbtns_trn_'..key, lvar.dm_trackbtns[ii][i].trn)
          end
        end
      end

      if lvar.dm_backtrack then
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_guid', lvar.dm_backtrack.guid)
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_trn', lvar.dm_backtrack.trn)
        reaper.SetProjExtState(0,SCRIPT,'dm_backtrack_page', lvar.dm_backtrack.page)
      end]]
    end

    --------------------------------------------

    if noclean ~= true then
      PopulateTracks()
      CleanData()
      --Switchers_Clean()
    else
      --Switchers_Clean()
    end

    local t = reaper.time_precise()

    local ffn, save_path, fn
    if fffn then
      if not string.match(fffn,'.*%.lbxstripper$') then
        fffn = fffn .. '.lbxstripper'
      end
      save_path = string.match(fffn,'(.+[\\/]).*')
      fn = string.match(fffn,'.+[\\/](.*)')
      ffn = fffn
      --DBG(ffn..'  '..save_path..'  '..fn)
    else
      ffn, save_path, fn, projfn = GetSaveFN(tmp)
    end

    local rfn
    if settings_backupduringsave == true then
      local id = tostring(math.floor(math.random() * 0xFFFFFFFF))
      rfn = string.match(ffn,'(.+).lbxstripper')..'_'..id..'.lbxbak_tmp'
      copyfile(ffn, rfn)
    end

    DBGOut('SaveData: ffn: '..tostring(ffn))

    file=io.open(ffn..'.tmp',"w")
    if file == nil then
      DBG('Failed to create save file:\n\n'..ffn)
      return nil
    end

    --------------------------------------------
    if not fffn then
      reaper.SetProjExtState(0,SCRIPT,'lbxstripper_datafile',fn)
      if --[[not]] epflag then
        --manually write datafile name to rpp file
        WriteRPPDirect(projfn, fn, dmfn)
      end
    end

    SaveDataFile(file, save_path, strips, snapshots)
    file:close()
    
    copyfile(ffn..'.tmp',ffn)
    os.remove(ffn..'.tmp')
    
    LOADEDDATAFILE = fn
    reaper.SetProjExtState(0,SCRIPT,'savedok',tostring(true))
    DBGOut('SaveData: Saved OK: '..tostring(true))

    if settings_createbackuponmanualsave and bak == true then
      local srcffn = ffn
      if tmp then
        ffn = string.match(ffn,'(.+)__')
        if ffn == nil then
          ffn = srcffn..'.lbxbak'
        end
        ffn=ffn..'.lbxbak'

      else
        ffn = ffn..'.lbxbak'
      end
      --local t = reaper.time_precise()
      copyfile(srcffn, ffn)


      DBGOut('SaveData: Backup created: '..tostring(true))
    end

    if settings_backupduringsave == true and rfn then
      os.remove(rfn)
    end
    infomsg = 'Total Save Time: '..round(reaper.time_precise() - t,2)..'s'
    DBGOut(infomsg)
    g_savedirty = false

  end

  function GetFileDate(path, created)
    --code from this thread: https://forum.cockos.com/showthread.php?t=220937
    --Thanks to the authors
    
    -- created is optional: if true, returns creation date, otherwise modified date
    local m, date
    if (reaper.GetOS()):find "Win" then
      if created then m = "c" else m = "" end
      path = string.gsub(path, '/', '\\')
      local retval = reaper.ExecProcess( 'cmd.exe /C "dir /T:' .. m .. '  \"' .. path .. '\" "', 0 ):sub(3)
      date = retval:match( "%d-.%d-.%d+%s-%d-:%d+" )
    else
      if created then m = "B" else m = "m" end
      local f = io.popen('stat -f %S' .. m .. ' "' .. path .. '"')
      date = f:read()
      f:close()
    end
    return date
  end

  function WriteRPPDirect(rpp, fn, dmfn)

    if reaper.file_exists(rpp) then

      --check timestamp on file if < 1 minute old
      local ts = GetFileDate(rpp)
      
      --Issue - date is localized - no real way of telling mm and dd apart
      --Could use (on windows 10) wmic datafile where name="E:\\Bureau\\original.wav" get LastModified 
      --But other OS's - dunno
      
      --Possible solution - every minute or so - write the current time into ProjExtState.
      --Use this time (from the saved rpp) to determine how recently it was saved...
      --Hmmmm... - but only if project is dirty maybe - to avoid modified flag being set???
      --Under LBXFLAGS section?
      --Also write into the rpp file when saving
      
      
      local dd,mm,yy,hh,mm = string.match(ts,'(%d+).-(%d+).-(%d+).-(%d+).-(%d+)')
      local tm = os.time{year = yy, month = mm, day = dd, hour = hh, min = mm}
      --DBG(yy..'  '..mm..'  '..hh..'  '..tm)
    
    end
  
  end

  function SaveDataFile(file, save_path, strips, snapshots)
    local SCRIPT = lvar.SCRIPT

    file:write('[version]'..tostring(lvar.VERSION)..'\n')
    if strips and #strips > 0 then

      reaper.SetProjExtState(0,SCRIPT,'strips_count',#strips)
      file:write('[stripcount]'..tostring(#strips)..'\n')
      DBGOut('SaveData: strips count: '..tostring(#strips))

      for s = 1, #strips do
        GUI_DrawMsgX(obj, gui, 'Saving Strip Data...',s,#strips)
        SaveStripData_FN(s,'dummy',save_path,file)
      end

    else
      reaper.SetProjExtState(0,SCRIPT,'strips_count',0)
      file:write('[stripcount]'..tostring(0)..'\n')
      DBGOut('SaveData: strips count: '..tostring(0))
    end

    if snapshots and #snapshots > 0 then
      reaper.SetProjExtState(0,SCRIPT,'snapshots_count',#snapshots)
      file:write('[snapshotcount]'..tostring(#snapshots)..'\n')
      DBGOut('SaveData: snapshots count: '..tostring(#snapshots))

      for s = 1, #snapshots do
        GUI_DrawMsgX(obj, gui, 'Saving Snapshot/Metalite Data...',s,#snapshots)
        SaveSnapshotData_FN(s,'dummy',save_path,file)
        SaveXXYData_FN(s,'dummy',save_path,file)
      end

      SaveXXYPathData_FN('dummy',save_path,file)
    else
      reaper.SetProjExtState(0,SCRIPT,'snapshots_count',0)
      file:write('[snapshotcount]'..tostring(0)..'\n')
      DBGOut('SaveData: snapshots count: '..tostring(0))
    end

    if faders then
      SaveFaders(file, '', faders)
      if lvar.gfaders then
        SaveFaders(file, 'global_', lvar.gfaders)
      end
    end
    if modulators then
      SaveMods(file)
    end
    if switchers then
      SaveSwitchers(file)
    end
    if lvar.sk2overlay then
      SaveSK2Assign(file)
    end
    file:write('[EOF]#EOF\n')

  end

  
  function convnum(val)

    if val == nil then
      val = -0xFFFFFF
    end
    return val

  end

  function deconvnum(val)

    if tonumber(val) == -0xFFFFFF then
      val = nil
    else
      val = tonumber(val)
    end
    return val

  end

  ------------------------------------------------------------

  function SetSurfaceSize()

    for i = 0, lvar.gfxpages do
      Img_SetDim(strip_image+i,surface_size.w, surface_size.h, true)
      Img_SetDim(bg_image+i,surface_size.w, surface_size.h, true)
    end

  end

  ------------------------------------------------------------

  --### Need to also check ctl track (check by guid) exists if ctl.tracknum ~= nil - also should check in any ctls check.
  function Snapshots_Check(strip, page, verbose)
    if snapshots and snapshots[strip] then
      if snapshots[strip][page] and #snapshots[strip][page] > 0 then

        local ctls = {}
        for c = 1, #strips[strip][page].controls do
          --local cc = strips[strip][page].controls[c]
          ctls[strips[strip][page].controls[c].c_id] = c
        end

        for sst = 1, #snapshots[strip][page] do

          if not verbose then
            GUI_DrawMsgX(obj, gui, 'Checking snapshots...',sst,#snapshots[strip][page])
          end

          if sst == 1 then
            if #snapshots[strip][page][sst] > 0 then

              local sscnt = #snapshots[strip][page][sst]
              for ss = 1, sscnt do

                local ss_entry_deleted = false
                local dcnt = #snapshots[strip][page][sst][ss].data
                if dcnt > 0 then
                  local notfoundcnt = 0
                  for d = 1, dcnt do

                    if strips[strip][page].controls[snapshots[strip][page][sst][ss].data[d].ctl] == nil or
                       snapshots[strip][page][sst][ss].data[d].c_id ~= strips[strip][page].controls[snapshots[strip][page][sst][ss].data[d].ctl].c_id then
                      local c = ctls[snapshots[strip][page][sst][ss].data[d].c_id]
                      if c then
                        snapshots[strip][page][sst][ss].data[d].ctl = c
                      else
                        --snapshot entry not found
                        notfoundcnt = notfoundcnt + 1
                        snapshots[strip][page][sst][ss].data[d] = nil
                        ss_entry_deleted = true
                      end
                    end
                  end

                  if ss_entry_deleted == true then
                    snapshots[strip][page][sst][ss].data = Table_RemoveNils(snapshots[strip][page][sst][ss].data, dcnt)
                  end
                end

                if snapshots[strip][page][sst][ss].modset then
                  snapshots[strip][page][sst][ss].moddata = CheckMods(snapshots[strip][page][sst][ss].moddata)
                end

                if snapshots[strip][page][sst][ss].fadset then
                  snapshots[strip][page][sst][ss].faddata = CheckFaders(snapshots[strip][page][sst][ss].faddata, true)
                end
              end
            end
          elseif sst > 1 then

            if #snapshots[strip][page][sst].ctls > 0 then

              local ctlcnt = #snapshots[strip][page][sst].ctls
              local ctl_entry_deleted = false
              for ctl = 1, ctlcnt do

                if strips[strip][page].controls[snapshots[strip][page][sst].ctls[ctl].ctl] == nil or
                   snapshots[strip][page][sst].ctls[ctl].c_id ~= strips[strip][page].controls[snapshots[strip][page][sst].ctls[ctl].ctl].c_id then
                  local c = ctls[snapshots[strip][page][sst].ctls[ctl].c_id]
                  if c then
                    snapshots[strip][page][sst].ctls[ctl].ctl = c
                  else
                    --snapshot entry not found
                    snapshots[strip][page][sst].ctls[ctl] = nil
                    ctl_entry_deleted = true
                  end
                end
              end
              if ctl_entry_deleted == true then
                snapshots[strip][page][sst].ctls = Table_RemoveNils(snapshots[strip][page][sst].ctls, ctlcnt)
              end
            end

            if #snapshots[strip][page][sst].snapshot > 0 then

              local sscnt = #snapshots[strip][page][sst].snapshot
              for ss = 1, #snapshots[strip][page][sst].snapshot do

                local ss_entry_deleted = false
                local dcnt = #snapshots[strip][page][sst].snapshot[ss].data
                if dcnt > 0 then
                  local notfoundcnt = 0
                  for d = 1, dcnt do

                    if strips[strip][page].controls[snapshots[strip][page][sst].snapshot[ss].data[d].ctl] == nil or
                       snapshots[strip][page][sst].snapshot[ss].data[d].c_id ~= strips[strip][page].controls[snapshots[strip][page][sst].snapshot[ss].data[d].ctl].c_id then

                      local c = ctls[snapshots[strip][page][sst].snapshot[ss].data[d].c_id]
                      if c then
                        snapshots[strip][page][sst].snapshot[ss].data[d].ctl = c
                      else
                        --snapshot entry not found
                        notfoundcnt = notfoundcnt + 1
                        snapshots[strip][page][sst].snapshot[ss].data[d] = nil
                        ss_entry_deleted = true
                      end
                    end
                  end

                  if ss_entry_deleted == true then
                    snapshots[strip][page][sst].snapshot[ss].data = Table_RemoveNils(snapshots[strip][page][sst].snapshot[ss].data, dcnt)
                  end
                end

                if snapshots[strip][page][sst].snapshot[ss].modset then
                  snapshots[strip][page][sst].snapshot[ss].moddata = CheckMods(snapshots[strip][page][sst].snapshot[ss].moddata)
                end

                if snapshots[strip][page][sst].snapshot[ss].fadset then
                  snapshots[strip][page][sst].snapshot[ss].faddata = CheckFaders(snapshots[strip][page][sst].snapshot[ss].faddata, true)
                end
              end
            end

          end
        end
      end
    end

  end

  ------------------------------------------------------------

  function Table_RemoveNils(srctbl, dcnt)

    local tbl = {}

    if dcnt > 0 then
      for i = 1, dcnt do
        if srctbl[i] ~= nil then
          table.insert(tbl, srctbl[i])
        end
      end
    end
    return tbl

  end

  ------------------------------------------------------------

  function Table_RemoveEntry(srctbl, dcnt, dremidx)

    local tbl = {}

    if dcnt > 0 then
      for i = 1, dcnt do
        if i ~= dremidx then
          table.insert(tbl, srctbl[i])
        end
      end
    end
    return tbl

  end

  ------------------------------------------------------------

  function Snap_RemoveDeletedSS(strip, page, sstype)

    if snapshots[strip] and snapshots[strip][page][sstype] then

      if #snapshots[strip][page][sstype].ctls > 0 then
        local ctlcnt = #snapshots[strip][page][sstype].ctls
        for ctl = 1, ctlcnt do
          if snapshots[strip][page][sstype].ctls[ctl].delete then

            local cid = snapshots[strip][page][sstype].ctls[ctl].c_id
            local id = snapshots[strip][page][sstype].ctls[ctl].id
            sscnt = #snapshots[strip][page][sstype].snapshot
            for ss = 1, sscnt do
              dcnt = #snapshots[strip][page][sstype].snapshot[ss].data
              for d = 1, dcnt do
                if id then
                  if snapshots[strip][page][sstype].snapshot[ss].data[d].id == id then
                    --remove
                    snapshots[strip][page][sstype].snapshot[ss].data[d] = nil
                  end
                else
                  if snapshots[strip][page][sstype].snapshot[ss].data[d].c_id == cid then
                    --remove
                    snapshots[strip][page][sstype].snapshot[ss].data[d] = nil
                  end
                end
              end
              snapshots[strip][page][sstype].snapshot[ss].data = Table_RemoveNils(snapshots[strip][page][sstype].snapshot[ss].data,dcnt)
            end

            snapshots[strip][page][sstype].ctls[ctl] = nil
          end
        end
        snapshots[strip][page][sstype].ctls = Table_RemoveNils(snapshots[strip][page][sstype].ctls,ctlcnt)
      end

      g_savedirty = true
    end

  end

  function CleanSortSS(strip, page, sstype)

    DBGOut('CleanSortSS: '..sstype)

    if sstype > 1 then
      if (snapshots[strip] and snapshots[strip][page][sstype]) then

        local snaps = snapshots[strip][page][sstype]
        local ctlcnt = #snaps.ctls
        local nctls = {}
        local done = {}
        for stage = 1, 10 do

          for ctl = 1, ctlcnt do
            snaps.ctls[ctl].stage = snaps.ctls[ctl].stage or 1

            if snaps.ctls[ctl].stage == stage and
               strips[strip][page].controls[snaps.ctls[ctl].ctl].ctlcat == ctlcats.fxmulti and
               strips[strip][page].controls[snaps.ctls[ctl].ctl].addfx then
              nctls[#nctls+1] = snaps.ctls[ctl]
              done[ctl] = true
            end
          end
          for ctl = 1, ctlcnt do
            if snaps.ctls[ctl].stage == stage and
               strips[strip][page].controls[snaps.ctls[ctl].ctl].ctlcat == ctlcats.fxmulti and
               not strips[strip][page].controls[snaps.ctls[ctl].ctl].addfx then
              nctls[#nctls+1] = snaps.ctls[ctl]
              done[ctl] = true
            end
          end
          for ctl = 1, ctlcnt do
            if snaps.ctls[ctl].stage == stage and
               strips[strip][page].controls[snaps.ctls[ctl].ctl].ctlcat == ctlcats.fxoffline then
              nctls[#nctls+1] = snaps.ctls[ctl]
              done[ctl] = true
            end
          end

          for ctl = 1, ctlcnt do
            if snaps.ctls[ctl].stage == stage and not done[ctl] then
              nctls[#nctls+1] = snaps.ctls[ctl]
            end
          end

        end
        snaps.ctls = nctls

        if #snaps.snapshot > 0 then
          local latch = false
          for ss = 1, #snaps.snapshot do

            local ndata = {}
            for ctl = 1, ctlcnt do

              local c = snaps.ctls[ctl].ctl
              local cid = snaps.ctls[ctl].c_id
              local id = snaps.ctls[ctl].id
              --DBG(ctl..'  '..tostring(id))
              if id == nil or latch == true then

                latch = true
                --search for c_id + add id
                if id == nil then id = GenID() end

                snaps.ctls[ctl].id = id

                if #snaps.snapshot[ss].data > 0 then
                  local fnd = false
                  for d = 1, #snaps.snapshot[ss].data do
                    if snaps.snapshot[ss].data[d].c_id == cid then
                      ndata[ctl] = snaps.snapshot[ss].data[d]
                      ndata[ctl].id = id
                      fnd = true
                      break
                    end
                  end
                  if fnd == false then
                    --add to data
                    ndata[ctl] = AddCtlValToSS2(strip,page,sstype,ss,c)
                    ndata[ctl].id = id
                  end
                else
                  --add to data
                  ndata[ctl] = AddCtlValToSS2(strip,page,sstype,ss,c)
                  ndata[ctl].id = id
                end
              else

                --search for id
                if #snaps.snapshot[ss].data > 0 then
                  local fnd = false
                  for d = 1, #snaps.snapshot[ss].data do
                    if snaps.snapshot[ss].data[d].id == id then
                      ndata[ctl] = snaps.snapshot[ss].data[d]
                      fnd = true
                      break
                    end
                  end
                  if fnd == false then
                    --add to data
                    ndata[ctl] = AddCtlValToSS2(strip,page,sstype,ss,c)
                    ndata[ctl].id = id
                  end
                else
                  --add to data
                  ndata[ctl] = AddCtlValToSS2(strip,page,sstype,ss,c)
                  ndata[ctl].id = id
                end
              end
            end

            snaps.snapshot[ss].data = ndata

          end
        end
        snaps.sorted = true
      end
    end

  end

  function CleanSS(strip, page, sstype)

    if sstype > 1 then
      if snapshots[strip] and snapshots[strip][page][sstype] then

        if #snapshots[strip][page][sstype].ctls > 0 then

          local ctlcnt = #snapshots[strip][page][sstype].ctls
          for ctl = 1, ctlcnt do

            local c = snapshots[strip][page][sstype].ctls[ctl].ctl

            --check ctl in each snapshot
            if #snapshots[strip][page][sstype].snapshot > 0 then
              for ss = 1, #snapshots[strip][page][sstype].snapshot do

                if #snapshots[strip][page][sstype].snapshot[ss].data > 0 then
                  local fnd = false
                  for d = 1, #snapshots[strip][page][sstype].snapshot[ss].data do
                    if snapshots[strip][page][sstype].snapshot[ss].data[d].ctl == c then
                      fnd = true
                      break
                    end
                  end
                  if fnd == false then
                    --add to data
                    AddCtlValToSS(strip,page,sstype,ss,c)
                  end
                else
                  --add to data
                  AddCtlValToSS(strip,page,sstype,ss,c)
                end
              end

            end
          end

        end

      end
    end
  end

  function AddCtlValToSS(strip, page, sstype, ss, c)

    local track = GetTrack(nz(strips[strip][page].controls[c].tracknum,strips[strip].track.tracknum))
    local cc = strips[strip][page].controls[c].ctlcat
    local fxnum = strips[strip][page].controls[c].fxnum
    local param = strips[strip][page].controls[c].param
    local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,c)
    local dval = DenormalizeValue(min,max,strips[strip][page].controls[c].val)
    if sstype == 1 then
      local sscnt = #snapshots[strip][page][sstype][ss].data + 1
      snapshots[strip][page][sstype][ss].data[sscnt] = {c_id = strips[strip][page].controls[c].c_id,
                                                              ctl = c,
                                                              val = strips[strip][page].controls[c].val,
                                                              dval = dval}
    elseif sstype > 1 then
      local sscnt = #snapshots[strip][page][sstype].snapshot[ss].data + 1
      snapshots[strip][page][sstype].snapshot[ss].data[sscnt] = {c_id = strips[strip][page].controls[c].c_id,
                                                              ctl = c,
                                                              val = strips[strip][page].controls[c].val,
                                                              dval = dval}
    end
  end

  function AddCtlValToSS2(strip, page, sstype, ss, c)

    local ctl = strips[strip][page].controls[c]

    local track = GetTrack(nz(ctl.tracknum,strips[strip].track.tracknum))
    local cc = ctl.ctlcat
    local fxnum = ctl.fxnum
    local param = ctl.param
    local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,c)
    local dval = DenormalizeValue(min,max,ctl.val)

    return {c_id = ctl.c_id,
            ctl = c,
            val = ctl.val,
            dval = dval}

  end

  function XY_Set(strip, page, sstype_select, ctl)

    if sstype_select > 1 then

      local x = strips[strip][page].controls[ctl].xydata.x
      local y = strips[strip][page].controls[ctl].xydata.y

      local ssa = strips[strip][page].controls[ctl].xydata.snapa
      local ssb = strips[strip][page].controls[ctl].xydata.snapb
      local ssc = strips[strip][page].controls[ctl].xydata.snapc
      local ssd = strips[strip][page].controls[ctl].xydata.snapd

      local gtrack = GetTrack(strips[strip].track.tracknum)
      if snapshots[strip][page][sstype_select].snapshot[ssa] then
        for ss = 1, #snapshots[strip][page][sstype_select].snapshot[ssa].data do

          local c = snapshots[strip][page][sstype_select].snapshot[ssa].data[ss].ctl
          local v_A, v_B, v_C, v_D = 0,0,0,0
          if ssa then
            v_A = snapshots[strip][page][sstype_select].snapshot[ssa].data[ss].dval
          end
          if ssb then
            v_B = snapshots[strip][page][sstype_select].snapshot[ssb].data[ss].dval
          end
          if ssc then
            v_C = snapshots[strip][page][sstype_select].snapshot[ssc].data[ss].dval
          end
          if ssd then
            v_D = snapshots[strip][page][sstype_select].snapshot[ssd].data[ss].dval
          end

          --local nv_A = snapshots[strip][page][sstype_select].snapshot[ssa].data[ss].val
          --local nv_B = snapshots[strip][page][sstype_select].snapshot[ssb].data[ss].val

          local v_AB = (v_B-v_A)*x + v_A
          local v_CD = (v_D-v_C)*x + v_C

          local v_ABCD = (v_CD-v_AB)*y + v_AB

          if c and v_ABCD and tostring(v_ABCD) ~= tostring(strips[strip][page].controls[c].val) then
            trackfxparam_select = c
            local trnum = nz(strips[strip][page].controls[c].tracknum,strips[strip].track.tracknum)
            if strips[strip][page].controls[c].tracknum then
              track = GetTrack(strips[strip][page].controls[c].tracknum)
            else
              track = gtrack
            end
            SetParam3_Denorm2_Safe2(track, v_ABCD, strip, page, reaper, c, v_ABCD)
          end
        end
      end
    end
  end

  function table.shuffle(tbl, n)
    size = #tbl
    for i = 1, math.min(n,size) do
      local rand = math.random(size)
      tbl[i], tbl[rand] = tbl[rand], tbl[i]
    end
    return tbl
  end

  function Snapshot_RANDOMADV(strip, p, c, random)

    local sst = random.sst
    local rctls = random.ctls
    local enablednu = settings_enablednu

    if random.snapshotsonly == true then

      local r = math.random()
      local snaps = snapshots[strip][p][sst]
      local ss = round(r*#snaps.snapshot)
      Snapshot_Set(strip,p,sst,ss)

      snaps.selected = ss
      if strip == tracks[track_select].strip and p == page and sst == sstype_select then
        ss_select = ss
        lupd.update_snaps = true
      end
    else

      local r = math.random()
      local lgtabcnt = 0
      local lg = {}
      local lgs = random.linkgrps
      local ctls = strips[strip][page].controls

      for cc = 1, #rctls do
        local rctl = rctls[cc]
        local ctl = ctls[rctls[cc].ctl]
        if ctl.ctllock ~= true then
          if rctl.linkgrp then
            if not lg[rctl.linkgrp] then
              lg[rctl.linkgrp] = {}
            end
            lgtabcnt = math.max(lgtabcnt, rctl.linkgrp)
            local lgptr = #lg[rctl.linkgrp]+1
            lg[rctl.linkgrp][lgptr] = cc
          elseif ctl.ctltype ~= 4 then
            local prob = math.random()
            if prob <= rctl.rprob then

              local v
              local wild = math.random()
              if rctl.wild == 0 or wild >= rctl.wild then
                v = math.random()*(rctl.amount or 1)
                local bias = math.random()
                if (rctl.amount or 0) == 0 then
                  if bias > rctl.bias then
                    v = ctl.val - (ctl.val-math.min(rctl.min,ctl.val))*v
                  else
                    v = ctl.val + (rctl.max-math.min(ctl.val,rctl.max))*v
                  end
                  v = F_limit(v,rctl.min,rctl.max)
                else
                  if rctl.snap == true then
                    local a = round(rctl.amount,5)
                    local cnt = 0
                    repeat
                      cnt = cnt + 1
                      if bias > rctl.bias then
                        local r = math.random()*(ctl.val-math.min(rctl.min,ctl.val))
                        v = -round((r / a)) * a
                      else
                        local r = math.random()*(rctl.max-math.min(ctl.val,rctl.max))
                        v = round((r / a)) * a
                      end
                    until (ctl.val+v > 0 and ctl.val+v < 1) or cnt == 5
                    if ctl.val+v < 0 or ctl.val+v > 1 then
                      v = 0
                    end
                  elseif bias > rctl.bias then
                    v = -v
                  end
                  v = F_limit(ctl.val+v,rctl.min,rctl.max)
                end
              else
                --WILD
                v = math.random()
              end
              if ctl.ctltype == 2 or
                 ctl.ctltype == 3 or
                 ctl.ctltype == 7 or
                 ctl.ctltype == 8 or
                 ctl.ctltype == 9 or
                 ctl.ctltype == 10 then
                 v = round(v)
              end
              if ctl.ctlcat == ctlcats.rs5k then
                v = v * ((#ctl.rsdata.samples-1)/lvar.maxsamples)
              end

              if v ~= ctl.val --[[or ctl.forceval]] then
                SetParam3(strip,page,rctls[cc].ctl,ctl,v)
                if enablednu == true and ctl.dnu == true then
                  SetCtlDirty(rctls[cc].ctl)
                end
              end
            end
          else
            --CYCLE CTL
            local cycle = ctl.cycledata
            local pos = cycle.pos or 1
            local cnt = cycle.statecnt
            --snap ignored
            --amount ignored
            local bias = math.random()
            if bias > rctl.bias then
              local np = math.min(round(math.random() * math.max((pos-2),1) +1),pos)
              if cycle[np] and cycle[np].val then
                cycle.pos = np
                v = cycle[np].val
                if v ~= ctl.val then
                  SetParam3(strip,page,rctls[cc].ctl,ctl,v)
                  if enablednu == true and ctl.dnu == true then
                    SetCtlDirty(rctls[cc].ctl)
                  end
                end
              end
            else
              local np = round(math.random() * (cnt-pos) +pos)
              if cycle[np] and cycle[np].val then
                cycle.pos = np
                v = cycle[np].val
                if v ~= ctl.val then
                  SetParam3(strip,page,rctls[cc].ctl,ctl,v)
                  if enablednu == true and ctl.dnu == true then
                    SetCtlDirty(rctls[cc].ctl)
                  end
                end
              end
            end
          end
        end
      end
      if lgtabcnt > 0 then
        for l = 1, lgtabcnt do
          if lg[l] then
            local lgcnt = #lg[l]
            if lgs[l].type == 1 then
              --random x

              local XX = round(lgs[l].X*128)
              lg[l] = table.shuffle(lg[l],XX)
              for x = 1, math.min(XX,lgcnt) do
                local ccc = lg[l][x]

                local rctl = rctls[ccc]
                local ctl = ctls[rctls[ccc].ctl]
                if ctl and ctl.ctltype ~= 4 then
                  local v = math.random()*(rctl.amount or 1)
                  local bias = math.random()
                  if (rctl.amount or 0) == 0 then
                    if bias > rctl.bias then
                      v = ctl.val - (ctl.val-math.min(rctl.min,ctl.val))*v
                    else
                      v = ctl.val + (rctl.max-math.min(ctl.val,rctl.max))*v
                    end
                    v = F_limit(v,rctl.min,rctl.max)
                  else
                    if rctl.snap == true then
                      local cnt = 0
                      repeat
                        cnt = cnt + 1
                        local a = round(rctl.amount,5)
                        if bias > rctl.bias then
                          local r = math.random()*(ctl.val-math.min(rctl.min,ctl.val))
                          v = -round((r / a)) * a
                        else
                          local r = math.random()*(rctl.max-math.min(ctl.val,rctl.max))
                          v = round((r / a)) * a
                        end
                      until (ctl.val+v > 0 and ctl.val+v < 1) or cnt == 5
                      if ctl.val+v < 0 or ctl.val+v > 1 then
                        v = 0
                      end
                    elseif bias > rctl.bias then
                      v = -v
                    end
                    v = F_limit(ctl.val+v,rctl.min,rctl.max)
                  end
                  if ctl.ctltype == 2 or
                     ctl.ctltype == 3 or
                     ctl.ctltype == 7 or
                     ctl.ctltype == 8 or
                     ctl.ctltype == 9 or
                     ctl.ctltype == 10 then
                     v = round(v)
                  end
                  if v ~= ctl.val then
                    SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                    if enablednu == true and ctl.dnu == true then
                      SetCtlDirty(rctls[ccc].ctl)
                    end
                  end
                elseif ctl and ctl.ctltype == 4 then
                  --CYCLE CTL
                  local cycle = ctl.cycledata
                  local pos = cycle.pos or 1
                  local cnt = cycle.statecnt
                  --snap ignored
                  --amount ignored
                  local bias = math.random()
                  if bias > rctl.bias then
                    local np = math.min(round(math.random() * math.max((pos-2),1) +1),pos)
                    if cycle[np] and cycle[np].val then
                      cycle.pos = np
                      v = cycle[np].val
                      if v ~= ctl.val then
                        SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                        if enablednu == true and ctl.dnu == true then
                          SetCtlDirty(rctls[ccc].ctl)
                        end
                      end
                    end
                  else
                    local np = round(math.random() * (cnt-pos) +pos)
                    if cycle[np] and cycle[np].val then
                      cycle.pos = np
                      v = cycle[np].val
                      if v ~= ctl.val then
                        SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                        if enablednu == true and ctl.dnu == true then
                          SetCtlDirty(rctls[ccc].ctl)
                        end
                      end
                    end
                  end
                end
              end

            elseif lgs[l].type == 2 or lgs[l].type == 3 then
              --random x on

              local a, b = 1, 0
              if lgs[l].type == 3 then
                a, b = 0, 1
              end
              local XX = round(lgs[l].X*128)
              lg[l] = table.shuffle(lg[l],XX)

              for x = 1, math.min(XX,lgcnt) do
                local ccc = lg[l][x]

                local ctl = ctls[rctls[ccc].ctl]
                if ctl then
                    --trackfxparam_select = rctls[ccc].ctl
                  local v = a
                  if v ~= ctl.val then
                    SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                    if enablednu == true and ctl.dnu == true then
                      SetCtlDirty(rctls[ccc].ctl)
                    end
                  end
                end
              end

              if math.min(XX,lgcnt) < lgcnt then
                for x = math.min(XX,lgcnt)+1, lgcnt do
                  local ccc = lg[l][x]

                  local ctl = ctls[rctls[ccc].ctl]
                  if ctl then
                    local v = b
                    if v ~= ctl.val then
                      SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                      if enablednu == true and ctl.dnu == true then
                        SetCtlDirty(rctls[ccc].ctl)
                      end
                    end
                  end
                end
              end

            elseif lgs[l].type == 4 then

              if lgs[l].snap == true then

                local cccc = lg[l][1]
                local dv = ctls[rctls[cccc].ctl].defval
                local r = math.random()
                local a = lgs[l].X
                local vv = round((r / a)) * a
                if vv > dv then vv = vv-dv end
                if math.random(2) == 2 then
                  vv = -vv
                end

                for x = 1, lgcnt do
                  local ccc = lg[l][x]
                  local ctl = ctls[rctls[ccc].ctl]
                  if ctl then
                    if rctls[ccc].inverted ~= true then
                      v = ctl.defval + vv
                    else
                      v = ctl.defval - vv
                    end

                    v = F_limit(v,rctls[ccc].min,rctls[ccc].max)
                    if ctl.ctltype == 2 or
                       ctl.ctltype == 3 or
                       ctl.ctltype == 7 or
                       ctl.ctltype == 8 or
                       ctl.ctltype == 9 or
                       ctl.ctltype == 10 then
                       v = round(v)
                    end
                    if v ~= ctl.val then
                      SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                      if enablednu == true and ctl.dnu == true then
                        SetCtlDirty(rctls[ccc].ctl)
                      end
                    end
                  end
                end


              else
                --NO SNAP
                local cccc = lg[l][1]
                local dv = ctls[rctls[cccc].ctl].defval
                local d
                local range = math.max(dv, 1-dv)
                if dv == 0 then
                  d = 1
                elseif dv == 1 then
                  d = -1
                else
                  d = math.random(2)
                  if d == 2 then
                    d = -1
                  end
                end
                local vv = math.random() * (range * lgs[l].X) * d
                for x = 1, lgcnt do
                  local ccc = lg[l][x]
                  local ctl = ctls[rctls[ccc].ctl]
                  if ctl then
                    local v
                    if rctls[ccc].inverted ~= true then
                      v = dv + vv
                    else
                      v = dv - vv
                    end
                    --[[if v < 0 or v > 1 then
                      v = ctl.val
                    end]]
                    v = F_limit(v,rctls[ccc].min,rctls[ccc].max)
                    if ctl.ctltype == 2 or
                       ctl.ctltype == 3 or
                       ctl.ctltype == 7 or
                       ctl.ctltype == 8 or
                       ctl.ctltype == 9 or
                       ctl.ctltype == 10 then
                       v = round(v)
                    end
                    if v ~= ctl.val then
                      SetParam3(strip,page,rctls[ccc].ctl,ctl,v)
                      if enablednu == true and ctl.dnu == true then
                        SetCtlDirty(rctls[ccc].ctl)
                      end
                    end
                  end
                end

              end
            end
          end
        end

      end

    end

  end

  function Snapshot_RANDOMIZE(strip, page, sstype_select, respectminmax)

    if not strips[strip] then return end

    if sstype_select == 1 then
      --page
      if #strips[strip][page].controls > 0 then
        for c = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[c]
          if ctl and ctl.noss ~= true and ctl.ctllock ~= true then
            if ctl.ctlcat == ctlcats.fxparam or
               ctl.ctlcat == ctlcats.trackparam or
               ctl.ctlcat == ctlcats.tracksend then
              trackfxparam_select = c
              local v = math.random()
              if ctl.ctltype == 2 or
                 ctl.ctltype == 3 or
                 ctl.ctltype == 7 or
                 ctl.ctltype == 8 or
                 ctl.ctltype == 9 or
                 ctl.ctltype == 10 then
                 v = round(v)
              end
              if respectminmax == true then
                --local min, max = GetParamMinMax_ctl(ctl,true)
                --v = v*(max-min)+min
                SetParam3(strip,page,c,ctl,v)
              else
                SetParam5(v)
              end
              SetCtlDirty(c)

            elseif ctl.ctlcat == ctlcats.takeswitcher then
              if ctl.iteminfo then
                local v = math.max(round(math.random()*(ctl.iteminfo.numtakes-1))/takeswitch_max,0)
                ctl.val = v
                SetItemTake(strip, page, c)
                SetCtlDirty(c)
                --lupd.update_ctls = true
              end
            elseif ctl.ctlcat == ctlcats.rs5k then
              local v = math.max(round(math.random()*(#ctl.rsdata.samples-1))/lvar.maxsamples,0)
              ctl.oval = ctl.val
              ctl.val = v

              A_SetParam(strip, page, c, ctl)

              SetCtlDirty(c)
              --lupd.update_ctls = true
            end
          end
        end
      end

    elseif sstype_select > 1 then
      if snapshots[strip][page][sstype_select] then
        if #snapshots[strip][page][sstype_select].ctls > 0 then
          for ctl = 1, #snapshots[strip][page][sstype_select].ctls do
            local c = snapshots[strip][page][sstype_select].ctls[ctl].ctl
            local cctl = strips[strip][page].controls[c]
            if cctl.ctllock ~= true then
              if cctl and cctl.ctlcat ~= ctlcats.takeswitcher and cctl.ctlcat ~= ctlcats.rs5k then
              --[[if cctl and (cctl.ctlcat == ctlcats.fxparam or
                 cctl.ctlcat == ctlcats.trackparam or
                 cctl.ctlcat == ctlcats.tracksend) then]]
                trackfxparam_select = c
                local v = math.random()
                if cctl.ctltype == 2 or
                   cctl.ctltype == 3 or
                   cctl.ctltype == 7 or
                   cctl.ctltype == 8 or
                   cctl.ctltype == 9 or
                   cctl.ctltype == 10 then
                   v = round(v)
                end
                if respectminmax == true then
                  SetParam3(strip,page,c,cctl,v)
                else
                  SetParam5(v)
                end
                SetCtlDirty(c)
                --lupd.update_ctls = true

              elseif cctl and cctl.ctlcat == ctlcats.takeswitcher then
                if cctl.iteminfo then
                  local v = math.max(round(math.random()*cctl.iteminfo.numtakes-1)/takeswitch_max,0)
                  cctl.val = v
                  SetItemTake(strip, page, c)
                  SetCtlDirty(c)
                  --lupd.update_ctls = true
                end
              elseif cctl and cctl.ctlcat == ctlcats.rs5k then
                local v = math.max(round(math.random()*(#cctl.rsdata.samples-1))/lvar.maxsamples,0)
                cctl.oval = cctl.val
                cctl.val = v

                A_SetParam(strip, page, c, cctl)

                SetCtlDirty(c)
                --lupd.update_ctls = true
              end
            end
          end
        end
      end

    end
    lupd.update_ctls = true

  end

  function Snapshot_MUTATE(strip, page, sstype_select, respectminmax)

    if not strips[strip] then return end
    local mutate_settings = lvar.mutate_settings

    local mutate_range = (mutate_settings.mutate_max-mutate_settings.mutate_min)/100
    local mutate_range2 = ((mutate_settings.mutate_max-mutate_settings.mutate_min)/100)*2
    local min = mutate_settings.range_min/100
    local max = mutate_settings.range_max/100
    local range = max-min

    if sstype_select == 1 then
      --page
      if #strips[strip][page].controls > 0 then
        for c = 1, #strips[strip][page].controls do
          local ctl = strips[strip][page].controls[c]
          if ctl.noss ~= true and ctl.ctllock ~= true then
            if ctl.ctlcat == ctlcats.fxparam or
               ctl.ctlcat == ctlcats.trackparam or
               ctl.ctlcat == ctlcats.tracksend then
              trackfxparam_select = ctl
              local v
              if mutate_settings.mutate == true then
                if mutate_settings.dir == 0 then
                  v = math.min(math.max(ctl.val + (math.random()*mutate_range2)-mutate_range,min),max)
                elseif mutate_settings.dir == 1 then
                  v = math.min(math.max(ctl.val + math.random()*mutate_range,min),max)
                else
                  v = math.min(math.max(ctl.val - math.random()*mutate_range,min),max)
                end
              else
                v = math.random()*range+min
              end
              if ctl.ctltype == 2 or
                 ctl.ctltype == 3 or
                 ctl.ctltype == 7 or
                 ctl.ctltype == 8 or
                 ctl.ctltype == 9 or
                 ctl.ctltype == 10 then
                 v = round(v)
              end
              if respectminmax == true then
                SetParam3(strip,page,c,ctl,v)
              else
                SetParam5(v)
              end
              SetCtlDirty(c)
            end
          end
        end
      end

    elseif sstype_select > 1 then
      if snapshots[strip][page][sstype_select] then
        if #snapshots[strip][page][sstype_select].ctls > 0 then
          for ctl = 1, #snapshots[strip][page][sstype_select].ctls do
            local c = snapshots[strip][page][sstype_select].ctls[ctl].ctl
            local cctl = strips[strip][page].controls[c]
            if cctl.ctllock ~= true then
              trackfxparam_select = c
              local v
              if mutate_settings.mutate == true then
                if mutate_settings.dir == 0 then
                  v = math.min(math.max(cctl.val + (math.random()*mutate_range2)-mutate_range,min),max)
                elseif mutate_settings.dir == 1 then
                  v = math.min(math.max(cctl.val + math.random()*mutate_range,min),max)
                else
                  v = math.min(math.max(cctl.val - math.random()*mutate_range,min),max)
                end
              else
                v = math.random()*range+min
              end
              if cctl.ctltype == 2 or
                 cctl.ctltype == 3 or
                 cctl.ctltype == 7 or
                 cctl.ctltype == 8 or
                 cctl.ctltype == 9 or
                 cctl.ctltype == 10 then
                 v = round(v)
              end
              if respectminmax == true then
                SetParam3(strip,page,c,cctl,v)
              else
                SetParam5(v)
              end
              SetCtlDirty(c)
            end
          end
        end
      end

    end
    lupd.update_ctls = true
  end

  function XXYPath_Delete(path)

    if XXYPath and XXYPath[path] then

      local pcnt = #XXYPath
      XXYPath[path] = nil

      local ptbl = Table_RemoveNils(XXYPath, pcnt)
      XXYPath = ptbl

      for s = 1, #xxy do
        if xxy[s] then
          for p = 1, #xxy[s] do
            if xxy[s][p] then
              for sst = 1, #xxy[s][p] do
                if xxy[s][p][sst] then

                  if xxy[s][p][sst].pathidx == path then
                    xxy[s][p][sst].pathidx = nil
                  elseif xxy[s][p][sst].pathidx > path then
                    xxy[s][p][sst].pathidx = xxy[s][p][sst].pathidx -1
                  end
                end
              end
            end
          end
        end
      end

    end

  end

  function Snapshot_CloneToSubset(strip, page, sst, copy)

    local newsst
    if sst == 1 then
      local strip = tracks[track_select].strip
      local ctls = strips[strip][page].controls
      if ctls and #ctls > 0 then
        newsst = #snapshots[strip][page]+1
        snapshots[strip][page][newsst] = {subsetname = 'SUBSET '..newsst-1,
                                          morph_time = 0,
                                          morph_sync = false,
                                          morph_syncv = 15,
                                          morph_scale = 1,
                                          stages = 1,
                                          delay = {},
                                          mtime = {},
                                          deltype = {},
                                          snapshot = {}, ctls = {}}
        for i = 1, lvar.snapstages do
          snapshots[strip][page][newsst].delay[i] = 0
          snapshots[strip][page][newsst].mtime[i] = 15
          snapshots[strip][page][newsst].deltype[i] = 0
        end

        lvar.snapsubsets_table[newsst] = 'SUBSET '..newsst-1

        for i = 1, #ctls do

          if ctls[i].ctlcat == ctlcats.fxparam or
             ctls[i].ctlcat == ctlcats.trackparam or
             ctls[i].ctlcat == ctlcats.tracksend or
             ctls[i].ctlcat == ctlcats.fxoffline or
             ctls[i].ctlcat == ctlcats.takeswitcher then
            --add
            if ctls[i].noss ~= true then
              local ctlidx = #snapshots[strip][page][newsst].ctls + 1
              snapshots[strip][page][newsst].ctls[ctlidx] = {c_id = ctls[i].c_id,
                                                             ctl = i,
                                                             morph = true,
                                                             stage = 1}
            end
          end
        end
      end
    elseif sst > 1 then

      local strip = tracks[track_select].strip
      local ctls = snapshots[strip][page][sst].ctls
      if ctls and #ctls > 0 then
        newsst = #snapshots[strip][page]+1
        snapshots[strip][page][newsst] = {subsetname = 'SUBSET '..newsst-1,
                                          morph_time = 0,
                                          morph_sync = false,
                                          morph_syncv = 15,
                                          morph_scale = 1,
                                          stages = snapshots[strip][page][sst].stages or 1,
                                          delay = table.deepcopy(snapshots[strip][page][sst].delay),
                                          mtime = table.deepcopy(snapshots[strip][page][sst].mtime),
                                          deltype = table.deepcopy(snapshots[strip][page][sst].deltype),
                                          snapshot = {}, ctls = {}}
        lvar.snapsubsets_table[newsst] = 'SUBSET '..newsst-1
        for i = 1, #ctls do

          --add
          local ctlidx = #snapshots[strip][page][newsst].ctls + 1
          local mrp = true
          if ctls[i].morph ~= nil then
            mrp = ctls[i].morph
          end
          local mem = false
          if ctls[i].mem ~= nil then
            mem = ctls[i].mem
          end
          snapshots[strip][page][newsst].ctls[ctlidx] = {c_id = ctls[i].c_id,
                                                         ctl = ctls[i].ctl,
                                                         id = ctls[i].id,
                                                         morph = mrp,
                                                         mem = mem,
                                                         stage = ctls[i].stage or 1}
        end
      end

    end
    return newsst
  end

  function Snapshot_DeleteOrphanedSubsets(strip, page)

    local dsst = {}
    local dsstidx = {}
    if #snapshots[strip][page] > 1 then

      --create index
      local cids = {}
      for c = 1, #strips[strip][page].controls do
        cids[strips[strip][page].controls[c].c_id] = c
      end

      for sst = #snapshots[strip][page], 2, -1  do

        if #snapshots[strip][page][sst].ctls == 0 then
          if snapshots[strip][page][sst].ignorevals ~= true or #snapshots[strip][page][sst].snapshot == 0 then
            if not dsstidx[sst] then
              local cnt = #dsst+1
              dsst[cnt] = sst
              dsstidx[sst] = cnt
            end
          end
        else
          if snapshots[strip][page][sst].ignorevals ~= true then
            local fnd = false
            for c = 1, #snapshots[strip][page][sst].ctls do
              local cc = snapshots[strip][page][sst].ctls[c]
              --if strips[strip][page].controls[cc.ctl] then
              if cids[cc.c_id] then
                fnd = true
                break
              end
            end
            if fnd == false then
              --No linked ctls exist
              local cnt = #dsst+1
              dsst[cnt] = sst
              dsstidx[sst] = cnt1
            end
          else
            if #snapshots[strip][page][sst].snapshot == 0 then
              local cnt = #dsst+1
              dsst[cnt] = sst
              dsstidx[sst] = cnt1
            end
          end
        end

      end

      if #dsst > 0 then
        for i = 1, #dsst do

          Snapshot_DeleteSubset(strip, page, dsst[i])

        end
      end
    end

  end

  function Snapshot_DeleteSubset(strip, page, sst)

    if sst > 1 and snapshots[strip][page][sst] then

      local scnt = #snapshots[strip][page]
      local xcnt

      snapshots[strip][page][sst] = nil
      if xxy and xxy[strip] and xxy[strip][page] then
        xcnt = #xxy[strip][page]
        if xxy[strip][page][sst] then
          local pathidx = xxy[strip][page][sst].pathidx
          xxy[strip][page][sst] = nil
          XXYPath_Delete(pathidx)
        end
      end

      local stbl = Table_RemoveEntry(snapshots[strip][page], scnt, sst)
      snapshots[strip][page] = stbl
      if xcnt then
        local xtbl = Table_RemoveEntry(xxy[strip][page], xcnt, sst)
        xxy[strip][page] = xtbl
      end

      ctl_select = {}
      gfx2_select = nil
      gfx3_select = nil
      gfx4_select = nil
      gfx4_selectidx = nil

      for c = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[c]
        if ctl.ctlcat == ctlcats.snapshot or
           ctl.ctlcat == ctlcats.xy or
           ctl.ctlcat == ctlcats.snapshotrand then
          if ctl.param == sst then
            ctl_select[#ctl_select+1] = {ctl = c}
          elseif ctl.param > sst then
            ctl.param = ctl.param -1
            if tonumber(ctl.param_info.paramidx) then
              ctl.param_info.paramidx = ctl.param_info.paramidx -1
            end
            if ctl.random then
              ctl.random.sst = ctl.param
            end
          end
        end

      end
      if #ctl_select > 0 then
        DeleteSelectedCtls()
      end

      if sstype_select > #snapshots[strip][page] then

        sstype_select = #snapshots[strip][page]

      end

    end

  end

  function Snapshot_Move(src, dst)

    local strip = tracks[track_select].strip
    if sstype_select == 1 then
      local snaptbl = snapshots[strip][page][sstype_select]
      local ssdst = {morph_time = snaptbl.morph_time,
                     morph_sync = snaptbl.morph_sync,
                     morph_syncv = snaptbl.morph_syncv,
                     morph_scale = snaptbl.morph_scale,
                     capturefaders = snaptbl.capturefaders,
                     capturemods = snaptbl.capturemods,
                     ignorevals = snaptbl.ignorevals}
      local inserted = false
      local npos = 0
      for i = 1, #snaptbl do
        if i == src then
          --skip
        else
          if inserted == false then
            npos = npos + 1
          end
          if i == dst then
            table.insert(ssdst, snaptbl[src])
            inserted = true
          end
          table.insert(ssdst, snaptbl[i])
        end
      end
      if inserted == false then
        table.insert(ssdst, snaptbl[src])
        npos = npos + 1
      end
      snapshots[strip][page][sstype_select] = ssdst
      ss_select = math.min(npos,#snapshots[strip][page][sstype_select])

    else
      local snaptbl = snapshots[strip][page][sstype_select].snapshot
      local ssdst = {morph_time = snaptbl.morph_time,
                     morph_sync = snaptbl.morph_sync,
                     morph_syncv = snaptbl.morph_syncv,
                     morph_scale = snaptbl.morph_scale,
                     }
      local inserted = false
      local npos = 0
      for i = 1, #snaptbl do
        if i == src then
          --skip
        else
          if inserted == false then
            npos = npos + 1
          end
          if i == dst then
            table.insert(ssdst, snaptbl[src])
            inserted = true
          end
          table.insert(ssdst, snaptbl[i])
        end
      end
      if inserted == false then
        table.insert(ssdst, snaptbl[src])
        npos = npos + 1
      end
      snapshots[strip][page][sstype_select].snapshot = ssdst
      ss_select = math.min(npos,#snapshots[strip][page][sstype_select].snapshot)
    end
    lupd.update_snaps = true
    lupd.update_fsnaps = true

  end

  function StoreFaders()
    if settings_localfaders == true or lvar.livemode == 2 then
      if strips and tracks[track_select].strip then
        if faders and strips[tracks[track_select].strip] then
          strips[tracks[track_select].strip].faders = table.deepcopy(faders)
        elseif strips[tracks[track_select].strip] then
          strips[tracks[track_select].strip].faders = nil
        end
      end
    else
      lvar.gfaders = table.deepcopy(faders)
    end
  end

  function RecallFaders(dm)
    if faders == nil then return end

    local fdata
    if not dm then
      if settings_localfaders == true then
        local strip = tracks[track_select].strip
        fdata = {}
        if strips[strip] and strips[strip].faders then
          fdata = strips[strip].faders
        end
      else
        fdata = lvar.gfaders or {}
      end
    else
      if lvar.faderstore then
        fdata = lvar.faderstore[lvar.dynamicmode_guid] or {}
      else
        fdata = {}
      end
    end
    
    for f = 1, #faders do
      if fdata[f] then
        if fdata[f].targettype == 4 or
           fdata[f].targettype == 7 then
          if not faders[f].targettype or (faders[f].targettype == 4 or
                                          faders[f].targettype == 7) then
            local ctl = strips[fdata[f].strip][fdata[f].page].controls[fdata[f].ctl]
            if ctl then

              AssignFader(f,fdata[f])
              --SetFader(ctl.macrofader, ctl.val)

            end
          end

        else
          if faders[f].targettype == 4 or
             faders[f].targettype == 7 then
            DeleteFader(f)
          end
        end
      else
        if faders[f] and (faders[f].targettype == 4 or
                          faders[f].targettype == 7) then
          DeleteFader(f)
        end
      end
    end
  end

  function Snapshot_Set(strip, page, sstype_sel, ss_sel, nomorph, stage, stageidx, retaindata, morph_st)

    local reaper = reaper
    local snaps = snapshots[strip][page][sstype_sel]
    if stage == nil then stage = 1 end

    --DBG('ss stage'..stage)

    local setdirty
    if settings_enablednu == true and strip == tracks[track_select].strip and page == page then
      setdirty = true
    end
    if snaps.ignorevals ~= true then
      if nomorph == true or (snaps.morph_sync == false and snaps.morph_time == 0) or
         (snaps.morph_sync == true and snaps.morph_syncv == 1) then
        local mfs
        local enablednu = settings_enablednu

        if sstype_sel == 1 then
          local snaptbl = snaps[ss_sel]
          if snaptbl then
            local gtrack = GetTrack(strips[strip].track.tracknum)
            mfchk = {}
            for ss = 1, #snaptbl.data do

              local c = snaptbl.data[ss].ctl
              local v = snaptbl.data[ss].dval
              local nv = snaptbl.data[ss].val
              local ctl = strips[strip][page].controls[c]

              mfs = snaptbl.data[ss].mfset
              if mfs then
                local mf = snaptbl.data[ss].mf
                if mf and ctl.macrofader ~= mf then
                  local f = snaptbl.data[ss].mfdata

                  if ctl.macrofader and not mfchk[ctl.macrofader] then
                    faders[ctl.macrofader] = {}
                  end

                  ctl.macrofader = mf

                  mfchk[mf] = true
                  faders[mf] = {targettype = 4,
                                strip = f.strip,
                                page = f.page,
                                ctl = f.ctl,
                                c_id = f.c_id}
                  if f.strip == tracks[track_select].strip and f.page == page then
                    SetCtlDirty(c)
                  end

                elseif mf == nil then
                  if ctl.macrofader and not mfchk[ctl.macrofader] then
                    faders[ctl.macrofader] = {}
                    SetCtlDirty(c)
                  end

                  ctl.macrofader = nil
                end
              end

              if ctl.noss ~= true and ctl.ctllock ~= true and c and v and (tostring(nv) ~= tostring(ctl.val) or (ctl.dnu == true and enablednu == true))
                 and (settings_morphfaderassignedctls == true or ctl.macrofader == nil) then
                trackfxparam_select = c
                if ctl.tracknum then
                  track = GetTrack(ctl.tracknum)
                else
                  track = gtrack
                end

                SetParam3_Denorm2_Safe2(track, v, strip, page, reaper, c, nv)
                if setdirty then
                  if enablednu == true and ctl.dnu == true and ctl.show_paramval == true then
                    ctl.dval = GetParamDisp(ctl.ctlcat,ctl.tracknum or tracks[track_select].tracknum,ctl.fxnum,ctl.param,ctl.dvaloffset,c)
                  end
                  SetCtlDirty(c)
                end
              end

              if ctl.macrofader and (settings_morphfaderassignedctls == true) then
                SetFader(ctl.macrofader, nv)
              end
            end

            if snaptbl.modset then
              for m = 1, #modulators do
                local mm = modulators[m]
                for t = 1, #mm.targets do
                  if mm.targets[t].targettype == 1 then
                    if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                      strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = nil
                      if mm.targets[t].strip == tracks[track_select].strip and
                         mm.targets[t].page == page then
                        SetCtlDirty(mm.targets[t].ctl)
                      end
                    end
                  end
                end
              end
              modulators = table.deepcopy(snaptbl.moddata)
              for m = 1, #modulators do
                local mm = modulators[m]
                for t = 1, #mm.targets do
                  if mm.targets[t].targettype == 1 then
                    if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                      strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = m
                      if mm.targets[t].strip == tracks[track_select].strip and
                         mm.targets[t].page == page then
                        SetCtlDirty(mm.targets[t].ctl)
                      end
                    end
                  end
                end
              end
              lupd.update_lfoedit = true
              lupd.update_sidebar = true
            end
          end

        elseif sstype_sel > 1 then

          local snaptbl = snaps.snapshot[ss_sel]
          local snapctls = snaps.ctls

          --DBG('ss'..stage)

          if snaptbl then
            local gtrack = GetTrack(strips[strip].track.tracknum)
            mfchk = {}
            if #snaptbl.data > 0 then

              for ss = 1, #snaptbl.data do

                if snapctls[ss] and snapctls[ss].stage == stage then
                  local c = snaptbl.data[ss].ctl
                  local v = snaptbl.data[ss].dval
                  local nv = snaptbl.data[ss].val
                  local ctl = strips[strip][page].controls[c]

                  mfs = snaptbl.data[ss].mfset
                  if mfs then
                    local mf = snaptbl.data[ss].mf
                    if mf and ctl.macrofader ~= mf then
                      local f = snaptbl.data[ss].mfdata

                      if ctl.macrofader and not mfchk[ctl.macrofader] then
                        faders[ctl.macrofader] = {}
                      end

                      ctl.macrofader = mf
                      mfchk[mf] = true
                      faders[mf] = {targettype = 4,
                                    strip = f.strip,
                                    page = f.page,
                                    ctl = f.ctl,
                                    c_id = f.c_id}

                      if f.strip == tracks[track_select].strip and f.page == page then
                        SetCtlDirty(c)
                      end

                    elseif mf == nil then
                      if ctl.macrofader and not mfchk[ctl.macrofader] then
                        faders[ctl.macrofader] = {}
                        SetCtlDirty(c)
                      end

                      ctl.macrofader = nil
                    end
                  end

                  if c and v and ctl.ctllock ~= true and (tostring(nv) ~= tostring(ctl.val) or (ctl.dnu == true and enablednu == true))
                     and (settings_morphfaderassignedctls == true or ctl.macrofader == nil) then
                    trackfxparam_select = c
                    if ctl.tracknum then
                      track = GetTrack(ctl.tracknum)
                    else
                      track = gtrack
                    end
                    SetParam3_Denorm2_Safe2(track, v, strip, page, reaper, c, nv)
                    if setdirty then
                      if enablednu == true and ctl.dnu == true and ctl.show_paramval == true then
                        ctl.dval = GetParamDisp(ctl.ctlcat,ctl.tracknum or tracks[track_select].tracknum,ctl.fxnum,ctl.param,ctl.dvaloffset,c)
                      end
                      SetCtlDirty(c)
                    end
                  end

                  if ctl.macrofader and (settings_morphfaderassignedctls == true) then
                    SetFader(ctl.macrofader, nv)
                  end

                end

              end

              if stage < (snaps.stages or 1) then
                if snaps.delay[stage+1] == 0 then
                  Snapshot_Set(strip, page, sstype_sel, ss_sel, nomorph, stage+1)
                else

                  local fnd = -1
                  if stageidx then
                    fnd = stageidx
                  else
                    for md = 1, #snapstage_data do
                      if snapstage_data[md] then

                        if snapstage_data[md].sstype_sel == sstype_sel and
                           snapstage_data[md].strip == strip and
                           snapstage_data[md].page == page then
                          fnd = md
                          break
                        end
                      end
                    end
                  end
                  local mdcnt = fnd
                  if fnd == -1 then
                    mdcnt = #snapstage_data+1
                  end

                  local trigtime = reaper.time_precise()+snaps.delay[stage+1]
                  snapstage_data[mdcnt] = {active = true,
                                            strip = strip,
                                            page = page,
                                            sstype_sel = sstype_sel,
                                            ss_sel = ss_sel,
                                            trigtime = trigtime,
                                            nomorph = nomorph,
                                            stage = stage+1}

                end
              end
            end

            if stage == 1 then
              if snaptbl.modset then
                for m = 1, #modulators do
                  local mm = modulators[m]
                  for t = 1, #mm.targets do
                    if mm.targets[t].targettype == 1 then
                      if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                        strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = nil
                        if mm.targets[t].strip == tracks[track_select].strip and
                           mm.targets[t].page == page then
                          SetCtlDirty(mm.targets[t].ctl)
                        end
                      end
                    end
                  end
                end
                modulators = table.deepcopy(snaptbl.moddata)
                for m = 1, #modulators do
                  local mm = modulators[m]
                  for t = 1, #mm.targets do
                    if mm.targets[t].targettype == 1 then
                      if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                        strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = m
                        if mm.targets[t].strip == tracks[track_select].strip and
                           mm.targets[t].page == page then
                          SetCtlDirty(mm.targets[t].ctl)
                        end
                      end
                    end
                  end
                end
                lupd.update_lfoedit = true
                lupd.update_sidebar = true
              end
            end

          end

        end
        snaps.selected = ss_sel

        for i = 1, #morph_data do
          if morph_data[i].strip == strip and
             morph_data[i].page == page and
             morph_data[i].sstype == sstype_sel then
            morph_data[i] = {}
          end
        end

        local sctls = strips[strip][page].snapctls
        if sctls and #sctls > 0 then
          for sn = 1, #sctls do
            SetCtlDirty(sctls[sn])
          end
        end

        if mfs and mode0_submode == 1 then
          lupd.update_sidebar = true
        end


      else

        --MORPH

        local fnd = -1
        for md = 1, #morph_data do
          if morph_data[md] then
            if morph_data[md].sstype == sstype_sel and
               morph_data[md].strip == strip and
               morph_data[md].page == page then

              fnd = md
              break
            end
          end
        end
        local mdcnt = fnd
        --local capmem
        --[[if fnd ~= -1 then
          DBG('FOUND')
        else
          DBG('NOT FOUND')
          capmem = true
        end]]

        if fnd == -1 then
          mdcnt = #morph_data+1
          --capmem = true
        end

        local start_time = morph_st or reaper.time_precise()
        local mt

        if (snaps.stages or 1) > 1 then
          mt = Morph_GetStageTime(snaps,stage)
        else
          if snaps.morph_sync == true then
            mt = CalcSyncTime(snaps.morph_syncv)
          else
            mt = (snaps.morph_time*100)
          end
        end

        --[[if not morph_data[mdcnt] then
          DBG('*** NO DATA ***')
        elseif morph_data[mdcnt].data and not retaindata then
          DBG('NOT RETAIN')
        elseif morph_data[mdcnt].data then
          DBG('RETAIN')
        end]]

        local ddd = {}
        local mem
        local pop = start_time
        if morph_data[mdcnt] then
          pop = morph_data[mdcnt].popstart
          mem = morph_data[mdcnt].mem
        elseif retaindata then
          pop = 0
        end
        if fnd ~= -1 and retaindata then
          ddd = morph_data[mdcnt].data
        end

        morph_data[mdcnt] = {active = true,
                             popstart = pop,
                             start_time = start_time,
                             end_time = start_time + mt,
                             morph_time = mt,
                             morph_sync = snaps.morph_sync,
                             morph_syncv = snaps.morph_syncv,
                             morph_scale = snaps.morph_scale,
                             morph_loop = snaps.morph_loop,
                             strip = strip,
                             page = page,
                             sstype = sstype_sel,
                             targetss = ss_sel,
                             sourcess = snaps.selected,
                             dir = 0,
                             p = 0,
                             psc = 0,
                             stage = stage,
                             stages = snaps.stages or 1,
                             data = ddd,
                             mem = mem}
        snaps.selected = ss_sel
      end

    else

      --faders mods only
      local snaptbl
      if sstype_sel == 1 then
        snaptbl = snaps[ss_sel]
      else
        snaptbl = snaps.snapshot[ss_sel]
      end

      if snaptbl.modset then
        for m = 1, #modulators do
          local mm = modulators[m]
          for t = 1, #mm.targets do
            if mm.targets[t].targettype == 1 then
              if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = nil
                if mm.targets[t].strip == tracks[track_select].strip and
                   mm.targets[t].page == page then
                  SetCtlDirty(mm.targets[t].ctl)
                end
              end
            end
          end
        end
        modulators = table.deepcopy(snaptbl.moddata)
        for m = 1, #modulators do
          local mm = modulators[m]
          for t = 1, #mm.targets do
            if mm.targets[t].targettype == 1 then
              if strips[mm.targets[t].strip] and strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl] then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = m
                if mm.targets[t].strip == tracks[track_select].strip and
                   mm.targets[t].page == page then
                  SetCtlDirty(mm.targets[t].ctl)
                end
              end
            end
          end
        end
        lupd.update_lfoedit = true
        lupd.update_sidebar = true
      end

      if snaptbl.fadset then
        local fdata = snaptbl.faddata
        if fdata then
          for f = 1, #faders do
            if fdata[f] then
              if fdata[f].targettype == 4 or
                 fdata[f].targettype == 7 then
                if not faders[f].targettype or (faders[f].targettype == 4 or
                                                faders[f].targettype == 7) then
                  local ctl = strips[fdata[f].strip][fdata[f].page].controls[fdata[f].ctl]
                  if ctl then

                    AssignFader(f,fdata[f])
                    --SetFader(ctl.macrofader, ctl.val)

                  end
                end

              else
                if faders[f].targettype == 4 or
                   faders[f].targettype == 7 then
                  DeleteFader(f)
                end
              end
            else
              if faders[f] and (faders[f].targettype == 4 or
                                faders[f].targettype == 7) then
                DeleteFader(f)
              end
            end
          end
        else

        end
      end
      snaps.selected = ss_sel

    end

    if settings_followsnapshot and sstype_sel == sstype_select then
      if ss_sel < ssoffset+1 or ss_sel > ssoffset+SS_butt_cnt then
        if sstype_sel == 1 then
          ssoffset = math.max(math.min(ss_sel-math.floor(SS_butt_cnt/2),#snaps-SS_butt_cnt),0)
        else
          ssoffset = math.max(math.min(ss_sel-math.floor(SS_butt_cnt/2),#snaps.snapshot-SS_butt_cnt),0)
        end
        lupd.update_snaps = true
      end
    end

    --reaper.Undo_EndBlock2(0,"LBX_Snapshot_Set",-1)
    --DBG(nil..nil)
  end

  function Morph_GetStageTime(snaps, stage)

    --DBG(snaps.deltype[stage]..'  '..stage)
    if snaps.deltype[stage] == 0 then
      mt = snaps.delay[stage]
    elseif snaps.deltype[stage] == 1 then
      mt = CalcSyncTime(snaps.mtime[stage])
    elseif snaps.mult ~= true then

      local st = 0
      if stage > 1 then
        for d = 1, stage-1 do
          if snaps.deltype[d] == 0 then
            st = st + snaps.delay[d]
          elseif snaps.deltype[d] == 1 then
            st = st + CalcSyncTime(snaps.mtime[d])
          elseif snaps.deltype[d] == 2 then
            st = 0
          end
        end
      end

      if snaps.morph_sync == true then
        tt = CalcSyncTime(snaps.morph_syncv)
      else
        tt = (snaps.morph_time*100)
      end

      mt = tt - st

    end

    if snaps.mult == true and snaps.morph_sync == true then
      if snaps.morph_syncv > 1 then
        mt = mt * lvar.sync_mult_table[snaps.morph_syncv]
      end
    end

    return mt

  end

  function CalcSyncTime(syncidx)

    local ts_b,ts_d,bpm = reaper.TimeMap_GetTimeSigAtTime(0,reaper.GetPlayPosition())
    local tm
    if syncidx < 20 then  --less than a bar
      tm = ((60 * ts_d)/bpm) * lvar.sync_mult_table[syncidx]
    else
      tm = ((60 * ts_d)/bpm) * lvar.sync_mult_table[syncidx] * (ts_b/ts_d)
    end
    return tm

  end

  function CalcBarTime()

    local ts_b,ts_d,bpm = reaper.TimeMap_GetTimeSigAtTime(0,reaper.GetPlayPosition())
    local tm = ((60 * ts_d)/bpm) * (ts_b/ts_d)

    return tm

  end

  function CalcBeatTime()

    local ts_b,ts_d,bpm = reaper.TimeMap_GetTimeSigAtTime(0,reaper.GetPlayPosition())
    local tm = ((60 * ts_d)/bpm) * (1/4)

    return tm

  end

  function Snapshot_Morph(strip, page, sstype_select, ss_select, data_id, p, stageidx)

    local reaper = reaper
    local gather = false
    if #morph_data[data_id].data == 0 then
      --DBG('GATHER')
      gather = true
      morph_data[data_id].data = {}
    end

    p=math.max(math.min(p,1),0)

    if not morph_data[data_id].paused or morph_data[data_id].manual then
      if morph_data[data_id].dir == 1 then
        p = 1-p
      end
      morph_data[data_id].p = p
      p = macScale(morph_data[data_id].morph_scale,p)
      morph_data[data_id].psc = p
    end

    if sstype_select == 1 then

      local snaptbl = snapshots[strip][page][sstype_select][ss_select]

      if snaptbl then
        local gtrack = GetTrack(strips[strip].track.tracknum)

        if p == 1 and snaptbl.modset then
          for m = 1, #modulators do
            local mm = modulators[m]
            for t = 1, #mm.targets do
              if mm.targets[t].targettype == 1 then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = nil
              end
            end
          end
          modulators = table.deepcopy(snaptbl.moddata)
          for m = 1, #modulators do
            local mm = modulators[m]
            for t = 1, #mm.targets do
              if mm.targets[t].targettype == 1 then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = m
              end
            end
          end
          lupd.update_lfoedit = true
          lupd.update_sidebar = true
        end

        mfchk = {}
        for ss = 1, #snaptbl.data do

          local c = snaptbl.data[ss].ctl
          local ctl = strips[strip][page].controls[c]
          if gather == true then
            morph_data[data_id].data[ss] = {}
            morph_data[data_id].data[ss].val = tonumber(ctl.val)
            --ctl.dirty = true
            lupd.update_ctls = true
          end

          local mfs = snaptbl.data[ss].mfset

          if mfs and gather == true then
            local mf = snaptbl.data[ss].mf
            if mf and ctl.macrofader ~= mf then
              local f = snaptbl.data[ss].mfdata

              if ctl.macrofader and not mfchk[ctl.macrofader] then
                faders[ctl.macrofader] = {}
              end
              ctl.macrofader = mf
              mfchk[mf] = true
              faders[mf] = {targettype = 4,
                            strip = f.strip,
                            page = f.page,
                            ctl = f.ctl,
                            c_id = f.c_id}

            elseif mf == nil then
              if ctl.macrofader and not mfchk[ctl.macrofader] then
                faders[ctl.macrofader] = {}
              end

              ctl.macrofader = nil
              --ctl.dirty = true
            end
          end

          local nv = morph_data[data_id].data[ss].val + ((snaptbl.data[ss].val - morph_data[data_id].data[ss].val)*p)
          if ctl.noss ~= true and ctl.ctllock ~= true and c and nv and tostring(nv) ~= tostring(ctl.val)
             and (settings_morphfaderassignedctls == true or (ctl.macrofader == nil and ctl.mod == nil)) then
            SetParam3(strip,page,c,ctl,nv)
            SetCtlDirty(c)
            --[[if setdirty then
              SetCtlDirty(c)
            end]]
            if ctl.macrofader --[[and (settings_morphfaderassignedctls == true)]] then
              SetFader(ctl.macrofader, nv)
            end
          end
        end


      end

    elseif sstype_select > 1 then

      local snaptbl = snapshots[strip][page][sstype_select].snapshot[ss_select]
      local snaps = snapshots[strip][page][sstype_select]

      local capmem
      if morph_data[data_id].mem == nil then
        capmem = true
        --DBG('*******************CAPMEM')
        morph_data[data_id].mem = {}
      end

      local stage = morph_data[data_id].stage
      if stage == nil then stage = 1 end

      if snaptbl then
        local gtrack = GetTrack(strips[strip].track.tracknum)

        if p == 1 and snaptbl.modset then
          for m = 1, #modulators do
            local mm = modulators[m]
            for t = 1, #mm.targets do
              if mm.targets[t].targettype == 1 then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = nil
              end
            end
          end
          modulators = table.deepcopy(snaptbl.moddata)
          for m = 1, #modulators do
            local mm = modulators[m]
            for t = 1, #mm.targets do
              if mm.targets[t].targettype == 1 then
                strips[mm.targets[t].strip][mm.targets[t].page].controls[mm.targets[t].ctl].mod = m
              end
            end
          end
          lupd.update_lfoedit = true
          lupd.update_sidebar = true
        end

        mfchk = {}
        if gather == true then
          lupd.update_ctls = true
          if #snaptbl.data > 0 then
            for ss = 1, #snaptbl.data do
              local c = snaptbl.data[ss].ctl
              local ctl = strips[strip][page].controls[c]

              --if gather == true then

                morph_data[data_id].data[ss] = {}
                if settings_enablednu == true and ctl.dnu == true then
                  morph_data[data_id].data[ss].val = GetParamValue_Ctl(c) or 0 --tonumber(ctl.val)
                else
                  morph_data[data_id].data[ss].val = tonumber(ctl.val)
                end
                if capmem == true then
                --DBG('CAPMEM'..morph_data[data_id].data[ss].val)
                  morph_data[data_id].mem[ss] = morph_data[data_id].data[ss].val
                end
                --ctl.dirty = true
                --lupd.update_ctls = true
              --end
            end
          end
        end

        if #snaptbl.data > 0 then
          for ss = 1, #snaptbl.data do
            local c = snaptbl.data[ss].ctl
            local ctl = strips[strip][page].controls[c]

            local mfs = snaptbl.data[ss].mfset
            if mfs and gather == true then
              local mf = snaptbl.data[ss].mf
              if mf and ctl.macrofader ~= mf then
                local f = snaptbl.data[ss].mfdata

                if ctl.macrofader and not mfchk[ctl.macrofader] then
                  faders[ctl.macrofader] = {}
                end

                ctl.macrofader = mf
                mfchk[mf] = true
                faders[mf] = {targettype = 4,
                              strip = f.strip,
                              page = f.page,
                              ctl = f.ctl,
                              c_id = f.c_id}

              elseif mf == nil then
                if ctl.macrofader and not mfchk[ctl.macrofader] then
                  faders[ctl.macrofader] = {}
                end

                ctl.macrofader = nil
              end
            end

            if snaps.ctls[ss].stage == morph_data[data_id].stage then
              if snaps.ctls[ss].morph == true then
--DBG('p')
                local nv
                if snaps.ctls[ss].mem ~= true then
                  nv = morph_data[data_id].data[ss].val + ((snaptbl.data[ss].val - morph_data[data_id].data[ss].val)*p)
                else
                  nv = morph_data[data_id].data[ss].val + ((morph_data[data_id].mem[ss] - morph_data[data_id].data[ss].val)*p)
                end

                if c and ctl.ctllock ~= true and nv and tostring(nv) ~= tostring(ctl.val) and (settings_morphfaderassignedctls == true or (ctl.macrofader == nil and ctl.mod == nil)) then
                  SetParam3(strip,page,c,ctl,nv)
                  SetCtlDirty(c)
                  if ctl.macrofader and (settings_morphfaderassignedctls == true) then
                    SetFader(ctl.macrofader, nv)
                  end
                end

              elseif gather == true then
                local nv
                if snaps.ctls[ss].mem ~= true then
                  nv = snaptbl.data[ss].val
                else
                  nv = morph_data[data_id].mem[ss]
                end
                if c and ctl.ctllock ~= true and nv and tostring(nv) ~= tostring(ctl.val) and (settings_morphfaderassignedctls == true or (ctl.macrofader == nil and ctl.mod == nil)) then
                  SetParam3(strip,page,c,ctl,nv)
                  SetCtlDirty(c)

                  if ctl.macrofader and (settings_morphfaderassignedctls == true) then
                    SetFader(ctl.macrofader, nv)
                  end
                end

              end
            end

          end

          --[[if p >= 1 then
            if stage < (snaps.stages or 1) then

              local nstage = stage+1

              if snaps.deltype == 1 and snaps.delay[nstage] ~= 0 then
DBG('o')
                local fnd = -1
                if stageidx then
                  fnd = stageidx
                else
                  for md = 1, #snapstage_data do
                    if snapstage_data[md] then
                      if snapstage_data[md].sstype_sel == sstype_select and
                         snapstage_data[md].strip == strip and
                         snapstage_data[md].page == page then
                        fnd = md
                        break
                      end
                    end
                  end
                end

                local mdcnt = fnd

                if fnd == -1 then
DBG('y')
                  mdcnt = #snapstage_data+1
                  local t = reaper.time_precise()
                  local trigtime = morph_data[data_id].end_time
DBG(t.. '  '..trigtime)
                  local retain = true
                  --[ [if morph_data[data_id].morph_loop == 2 or morph_data[data_id].morph_loop == 3 then
                    retain = true --morph_data[data_id].data
                  end]
                  snapstage_data[mdcnt] = {active = true,
                                            strip = strip,
                                            page = page,
                                            sstype_sel = sstype_select,
                                            ss_sel = ss_select,
                                            trigtime = trigtime,
                                            nomorph = nomorph,
                                            stage = nstage,
                                            retain = retain}

                end
              end
            end
          end ]]
        end


      end
    end
    lupd.update_snapmorph = true
  end

  function Snapshots_INIT()

    if snapshots == nil then
      snapshots = {}
    end
    for s = 1, #strips do --reaper.CountTracks(0)+1 do
      if snapshots[s] == nil then
        snapshots[s] = {}
      end

      for p = 1, lvar.maxpage do
        if snapshots[s][p] == nil then
          snapshots[s][p] = {}
        end
        if snapshots[s][p][1] == nil then
          snapshots[s][p][1] = {morph_time = 0,
                                morph_sync = false,
                                morph_syncv = 15,
                                morph_scale = 1}
        end
      end
    end
  end

  function Snapshots_sst_INIT()

    local snapshots = {}

    snapshots[1] = {morph_time = 0,
                    morph_sync = false,
                    morph_syncv = 15,
                    morph_scale = 1}
    return snapshots
  end

  --[[function Snapshots_INIT2(s, p) --dynamic mode only

    if snapshots == nil then
      snapshots = {}
    end
    if snapshots[s] == nil then
      snapshots[s] = {}
    end

    if snapshots[s][p] == nil then
      snapshots[s][p] = {}
    end
    if snapshots[s][p][1] == nil then
      snapshots[s][p][1] = {}
    end
    snapshots[s][p][1].morph_time = 0
    snapshots[s][p][1].morph_sync = false
    snapshots[s][p][1].morph_syncv = 15
    snapshots[s][p][1].morph_scale = 1
  end]]

  function Snapshots_CREATE(strip, page, sstype, ss_ovr, donotupdatestripfile)

    local snaps
    local oss_select = ss_select
    if strips and strips[strip] and strips[strip][page] and #strips[strip][page].controls > 0 then

      if snapshots == nil then
        snapshots = {}
      end
      for s = 1, reaper.CountTracks(0)+1 do
        if snapshots[s] == nil then
          snapshots[s] = {}
          for p = 1, lvar.maxpage do
            snapshots[s][p] = {}
            snapshots[s][p][1] = {morph_time = 0,
                                  morph_sync = false,
                                  morph_syncv = 15,
                                  morph_scale = 1,
                                  morph_loop = 1}
          end
        end
      end
      if snapshots[strip][page] == nil then
        snapshots[strip][page] = {}
      end

      snaps = snapshots[strip][page][sstype]
      
      if snaps == nil then
        if sstype == 1 then
          snaps = {morph_time = 0,
                  morph_sync = false,
                  morph_syncv = 15,
                  morph_scale = 1,
                  morph_loop = 1}
        else
          snaps = {subsetname = 'SUBSET '..sstype-1,
                    morph_time = 0,
                    morph_sync = false,
                    morph_syncv = 15,
                    morph_scale = 1,
                    morph_loop = 1,
                    stages = 1,
                    snapshot = {}, ctls = {},
                    subid = GenID()}
          snaps.delay = {}
          snaps.mtime = {}
          snaps.deltype = {}
          for i = 1, lvar.snapstages do
            snaps.delay[i] = 0
            snaps.mtime[i] = 15
            snaps.deltype[i] = 0
          end

          lvar.snapsubsets_table[sstype] = 'SUBSET '..sstype-1
        end
      end

      if snaps.ignorevals ~= true then
        if settings_enablednu == true then
          UpdateControlValues3(nil, ctls_dnu, ctls_orr, true)
        end

        if sstype == 1 then

          if ss_ovr then
            snappos = ss_ovr
            if snaps[snappos] then
              snaps[snappos].data = {}
              snaps[snappos].modset = nil
              snaps[snappos].moddata = nil
            else
              return false
            end
          else
            snappos = #snaps + 1
            snaps[snappos] = {name = 'Snapshot '..snappos,
                              data = {}}
          end

          local offflag = false
          local sscnt = 1
          for c = 1, #strips[strip][page].controls do
            local ctl = strips[strip][page].controls[c]
            local sflag = false
            if ctl.noss ~= true then
              if ctl.ctlcat == ctlcats.fxparam or
                 ctl.ctlcat == ctlcats.trackparam or
                 ctl.ctlcat == ctlcats.tracksend or
                 ctl.ctlcat == ctlcats.fxoffline or
                 ctl.ctlcat == ctlcats.midictl or
                 ctl.ctlcat == ctlcats.takeswitcher or
                 ctl.ctlcat == ctlcats.rs5k or
                 ctl.ctlcat == ctlcats.fxmulti then
                if ctl.ctltype ~= 5 then
                  local track = GetTrack(nz(ctl.tracknum,strips[strip].track.tracknum))
                  local cc = ctl.ctlcat
                  local fxnum = ctl.fxnum
                  local param = ctl.param
                  local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,c)
                  local dval = DenormalizeValue(min,max,ctl.val)
                  snaps[snappos].data[sscnt] = {c_id = ctl.c_id,
                                                ctl = c,
                                                val = ctl.val,
                                                dval = dval}
                  if cc == ctlcats.fxoffline or cc == ctlcats.fxmulti then
                    offflag = true
                  end

                  if snaps.capturefaders == true then
                    snaps[snappos].data[sscnt].mfset = true
                    local mf = ctl.macrofader
                    if mf then
                      if faders[mf] and (faders[mf].targettype == 4 or
                                         faders[mf].targettype == 7) then
                        local f = {targettype = faders[mf].targettype,
                                   strip = faders[mf].strip,
                                   page = faders[mf].page,
                                   ctl = faders[mf].ctl,
                                   c_id = faders[mf].c_id}
                        snaps[snappos].data[sscnt].mf = mf
                        snaps[snappos].data[sscnt].mfdata = f

                      end
                    end
                  end

                  sscnt = sscnt + 1
                  sflag = true
                end
              end
            end

            if snaps.capturemods == true then
              snaps[snappos].modset = true
              snaps[snappos].moddata = table.deepcopy(modulators)
            end
          end

          if offflag == true then
            --place offline buttons at top of list otherwise snapshots not recalled correctly first click

            --### NEEDS TO BE MOVED TO CleanSortSS function

            local tmp = {}
            for sspos = 1, #snaps[snappos].data do
              if strips[strip][page].controls[snaps[snappos].data[sspos].ctl].ctlcat == ctlcats.fxmulti and
                 strips[strip][page].controls[snaps[snappos].data[sspos].ctl].addfx then
                table.insert(tmp, snaps[snappos].data[sspos])
              end
            end
            for sspos = 1, #snaps[snappos].data do
              if strips[strip][page].controls[snaps[snappos].data[sspos].ctl].ctlcat == ctlcats.fxmulti and
                 not strips[strip][page].controls[snaps[snappos].data[sspos].ctl].addfx then
                table.insert(tmp, snaps[snappos].data[sspos])
              end
            end
            for sspos = 1, #snaps[snappos].data do
              if strips[strip][page].controls[snaps[snappos].data[sspos].ctl].ctlcat == ctlcats.fxoffline then
                table.insert(tmp, snaps[snappos].data[sspos])
              end
            end
            for sspos = 1, #snaps[snappos].data do
              if strips[strip][page].controls[snaps[snappos].data[sspos].ctl].ctlcat ~= ctlcats.fxoffline and
                 strips[strip][page].controls[snaps[snappos].data[sspos].ctl].ctlcat ~= ctlcats.fxmulti then
                table.insert(tmp, snaps[snappos].data[sspos])
              end
            end
            snaps[snappos].data = tmp
          end
          ss_select = snappos

        elseif sstype > 1 then

          local sctls = #snaps.ctls
          if sctls > 0 or snaps.capturemods == true then

            if ss_ovr then
              snappos = ss_ovr
              if snaps.snapshot[snappos] then
                snaps.snapshot[snappos].data = {}
              else
                return false
              end
            else
              snappos = #snaps.snapshot + 1
              snaps.snapshot[snappos] = {name = 'Snapshot '..snappos,
                                         data = {}}
            end
          end

          if sctls > 0 then
            local ctlsdone = {}
            local offflag = false
            local sscnt = 1
            for cctl = 1, sctls do
              local c = snaps.ctls[cctl].ctl
              local ctl = strips[strip][page].controls[c]
              if nz(snaps.ctls[cctl].delete,false) == false then
                if ctl.ctlcat == ctlcats.fxparam or
                   ctl.ctlcat == ctlcats.trackparam or
                   ctl.ctlcat == ctlcats.tracksend or
                   ctl.ctlcat == ctlcats.fxoffline or
                   ctl.ctlcat == ctlcats.midictl or
                   ctl.ctlcat == ctlcats.takeswitcher or
                   ctl.ctlcat == ctlcats.rs5k or
                   ctl.ctlcat == ctlcats.fxmulti or 
                   ctl.ctlcat == ctlcats.switcher_pagesel then
                  if ctl.ctltype ~= 5 then
                    local track = GetTrack(nz(ctl.tracknum,strips[strip].track.tracknum))
                    local cc = ctl.ctlcat
                    local fxnum = ctl.fxnum
                    local param = ctl.param
                    local min, max = GetParamMinMax(cc,track,nz(fxnum,-1),param,true,c)
                    local dval = DenormalizeValue(min,max,ctl.val)
                    snaps.snapshot[snappos].data[sscnt] = {c_id = ctl.c_id,
                                                            ctl = c,
                                                            id = snaps.ctls[cctl].id,
                                                            val = ctl.val,
                                                            dval = dval}
                    if cc == ctlcats.fxoffline or cc == ctlcats.fxmulti then
                      offflag = true
                    end

                    if snaps.capturefaders == true and not ctlsdone[c] then
                      snaps.snapshot[snappos].data[sscnt].mfset = true
                      local mf = ctl.macrofader
                      if mf then
                        if faders[mf] and (faders[mf].targettype == 4 or
                                           faders[mf].targettype == 7) then
                          local f = {targettype = faders[mf].targettype,
                                     strip = faders[mf].strip,
                                     page = faders[mf].page,
                                     ctl = faders[mf].ctl,
                                     c_id = faders[mf].c_id}
                          snaps.snapshot[snappos].data[sscnt].mf = mf
                          snaps.snapshot[snappos].data[sscnt].mfdata = f

                        end
                      end
                    end

                    sscnt = sscnt + 1
                  end
                end
              end
              ctlsdone[c] = true
            end

            --[[if offflag == true then
              --place offline buttons at top of list otherwise snapshots not recalled correctly first click
              local tmp = {}
              --local sscnt = 1
              for sspos = 1, #snaps.snapshot[snappos].data do
                if strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].ctlcat == ctlcats.fxmulti and
                   strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].addfx then
                  table.insert(tmp, snaps.snapshot[snappos].data[sspos])
                end
              end
              for sspos = 1, #snaps.snapshot[snappos].data do
                if strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].ctlcat == ctlcats.fxmulti and
                   not strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].addfx then
                  table.insert(tmp, snaps.snapshot[snappos].data[sspos])
                end
              end
              for sspos = 1, #snaps.snapshot[snappos].data do
                if strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].ctlcat == ctlcats.fxoffline then
                  table.insert(tmp, snaps.snapshot[snappos].data[sspos])
                end
              end
              for sspos = 1, #snaps.snapshot[snappos].data do
                if strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].ctlcat ~= ctlcats.fxoffline and
                   strips[strip][page].controls[snaps.snapshot[snappos].data[sspos].ctl].ctlcat ~= ctlcats.fxmulti then
                  table.insert(tmp, snaps.snapshot[snappos].data[sspos])
                end
              end
              snaps.snapshot[snappos].data = tmp
            end]]
            ss_select = snappos
          end

          if snaps.capturemods == true then
            snaps.snapshot[snappos].modset = true
            snaps.snapshot[snappos].moddata = table.deepcopy(modulators)
          end

        end
      else
        --mods fader only

        if snaps.capturemods ~= true and snaps.capturefaders ~= true then
          return
        end

        local snappos
        local ssobj
        if ss_ovr then
          snappos = ss_ovr
          if sstype == 1 then
            ssobj = snaps[snappos]
          else
            ssobj = snaps.snapshot[snappos]
          end

          if ssobj then
            ssobj.data = {}
            ssobj.modset = nil
            ssobj.moddata = nil
            ssobj.fadset = nil
            ssobj.faddata = nil
          else
            return false
          end
        else
          if sstype == 1 then
            snappos = #snaps + 1
          else
            snappos = #snaps.snapshot + 1
          end

          if sstype == 1 then
            ssobj = {name = 'Snapshot '..snappos,
                     data = {}}
          else
            ssobj = {name = 'Snapshot '..snappos,
                     data = {}}
          end
        end

        if snaps.capturemods == true then
          ssobj.modset = true
          ssobj.moddata = table.deepcopy(modulators)
        end
        if snaps.capturefaders == true then
          ssobj.fadset = true
          ssobj.faddata = table.deepcopy(faders)
        end

        if ssobj then
          if sstype == 1 then
            snaps[snappos] = ssobj
          else
            snaps.snapshot[snappos] = ssobj
          end
        end
        ss_select = snappos
      end

      snaps.selected = ss_select

      g_savedirty = true
    end

    if snaps then
      snapshots[strip][page][sstype] = snaps
      if settings_savesnapafterselected == true and oss_select then
        Snapshot_Move(ss_select,oss_select+1)
      end
    end
    if snaps and settings_followsnapshot then
      if ss_select and (ss_select < ssoffset+1 or ss_select > ssoffset+SS_butt_cnt) then
        if sstype_select == 1 then
          ssoffset = math.max(math.min(ss_select-math.floor(SS_butt_cnt/2),#snaps-SS_butt_cnt),0)
        else
          ssoffset = math.max(math.min(ss_select-math.floor(SS_butt_cnt/2),#snaps.snapshot-SS_butt_cnt),0)
        end
        lupd.update_snaps = true
      end
    end
    
    if lvar.livemode == 2 and lvar.dm_autoupdatesnaps and donotupdatestripfile ~= true then
      if sstype == 1 then
      
      else
        if snaps.ctls and #snaps.ctls > 0 then
          local c = snaps.ctls[1].ctl
          local ctl = strips[strip][page].controls[c]
          if ctl then
            local switchid = Switcher_GetTopLevelSwitcher(ctl.switcher)
            if switchid then
              DM_SaveSnapsToStrip(switchid)
              DM_RefreshPage(true)
            end
          end
        end
      end
    end
    
  end

  function RandomOpts_FindParent(cid)
    local strip = tracks[track_select].strip
    if strips[strip] then
      for c = 1, #strips[strip][page].controls do
        local ctl = strips[strip][page].controls[c]
        if ctl.c_id == cid then
          return c
        end
      end
    end
  end

  function RandomOpts_RefreshCtlNos(strip, page, random)
    if random then
      local strip = strip or tracks[track_select].strip
      local ctls = {}
      local sst = random.sst
      if snapshots[strip] and snapshots[strip][page][sst] then
        local snapctls = snapshots[strip][page][sst].ctls
        randomopts_ctls = {}
        if snapctls and #snapctls > 0 then
          for sc = 1, #snapctls do
            ctls[sc] = {c_id = snapctls[sc].c_id,
                        ctl = snapctls[sc].ctl,
                        min = 0,
                        max = 1,
                        linkgrp = nil,
                        rprob = 1,
                        bias = 0.5,
                        amount = nil,
                        snap = nil,
                        inverted = false,
                        wild = 0}
            for rs = 1, #random.ctls do
              if tostring(random.ctls[rs].c_id) == tostring(ctls[sc].c_id) then
                ctls[sc] = random.ctls[rs]
                ctls[sc].ctl = snapctls[sc].ctl
                break
              end
            end
            randomopts_ctls[ctls[sc].ctl] = sc
          end
        end
        random.ctls = ctls
        randomopts_select = random
        randopts_selectctl = random.parent
      end
    end

  end

  function RandomOpts_ParamMenu(x,y)

    local mstr = ''

    RandomOpts_RefreshCtlNos(tracks[track_select].strip, page, randomopts_select)

    local strip = tracks[track_select].strip
    local rosctls = randomopts_select.ctls
    if #rosctls > 0 then

      for i = 1, #rosctls do
        local ctl = strips[strip][page].controls[rosctls[i].ctl]
        local name
        if ctl.ctlcat == ctlcats.fxparam then
          local fxnum = string.format('%i',ctl.fxnum)
          local fxname = CropFXName(ctl.fxname)
          name = 'FX '..fxnum..' : '..fxname..' - '.. nz(ctl.ctlname_override,'')..' ('.. ctl.param_info.paramname ..')'
        elseif ctl.ctlcat == ctlcats.trackparam or ctl.ctlcat == ctlcats.tracksend then
          local trn = ctl.tracknum or tracks[track_select].tracknum
          local trtxt = 'TR '..trn+1 ..' : '
          if trn == -1 then
            trtxt = 'TR MASTER : '
          end
          name = trtxt..nz(ctl.ctlname_override,'') ..' ('.. ctl.param_info.paramname ..')'
        else
          name = nz(ctl.ctlname_override,'') ..' ('.. ctl.param_info.paramname ..')'
        end
        if mstr ~= '' then
          mstr = mstr .. '|'
        end
        mstr = mstr .. name

      end

    end

    gfx.x = x
    gfx.y = y
    local res = gfx.showmenu(mstr)
    if res > 0 then
      randomopts_select.param = res
      lupd.update_randomopts = true
    end

  end

  function RandomOpts_LG_INIT()

    local p = randomopts_select.param
    local lg = randomopts_select.ctls[p].linkgrp
    if randomopts_select.linkgrps[lg] == nil then

      randomopts_select.linkgrps[lg] = {type = 1,
                                        X = 1/128}

    end

  end

  function RandomOpts_INIT(c)

    local strip = tracks[track_select].strip
    local ctl = strips[strip][page].controls[c]
    if ctl and ctl.ctlcat == ctlcats.snapshotrand then

      local ros = ctl.random
      if not ros then
        local sst = ctl.param
        local snapctls = snapshots[strip][page][sst].ctls

        ros = {parent = c,
               parent_cid = ctl.c_id,
               sst = ctl.param,
               ctls = {},
               linkgrps = {},
               snapshotsonly = false,
               useadv = false}
        local ctls = {}
        randomopts_ctls = {}
        if snapctls and #snapctls > 0 then
          for sc = 1, #snapctls do
            ctls[sc] = {c_id = snapctls[sc].c_id,
                        ctl = snapctls[sc].ctl,
                        min = 0,
                        max = 1,
                        linkgrp = nil,
                        rprob = 1,
                        bias = 0.5,
                        amount = nil,
                        snap = nil,
                        inverted = false,
                        wild = 0}
            randomopts_ctls[snapctls[sc].ctl] = sc
          end
          ros.ctls = ctls
        end

      else
        if #ros.ctls > 0 then
          randomopts_ctls = {}
          for sc = 1, #ros.ctls do
            randomopts_ctls[ros.ctls[sc].ctl] = sc
          end
        else
          randomopts_ctls = nil
        end
        if ros.parent ~= c then
          ros.parent = c
        end
      end
      randomopts_select = ros
      ctl.random = randomopts_select
    end

  end

  ------------------------------------------------------------

  function EnableLatch(c)

    if strips[tracks[track_select].strip][page].controls[c].ctlcat == ctlcats.fxparam then
      local trn = nz(strips[tracks[track_select].strip][page].controls[c].tracknum, strips[tracks[track_select].strip].track.tracknum)
      local track = GetTrack(trn)
      local env = reaper.GetFXEnvelope(track,strips[tracks[track_select].strip][page].controls[c].fxnum,strips[tracks[track_select].strip][page].controls[c].param, false)
      if env then
        local retval, envchunk = reaper.GetEnvelopeStateChunk(env,'',true)
        local s, e = string.find(envchunk,'ACT 1')
        if s and e then
          nchunk = string.sub(envchunk,1,s-1) .. 'ACT 0' .. string.sub(envchunk,e+1)
          reaper.SetEnvelopeStateChunk(env, nchunk, true)
        end
      end
    end

  end

  ------------------------------------------------------------
  -- STRIP SETS
  ------------------------------------------------------------

  function SaveSet(fn)

    if fn and string.len(fn)>0 then

      local savedata = {version = lvar.VERSION,
                        trackdata = {},
                        stripdata = {},
                        snapdata = {},
                        switchers = {}}
      for t = 0, reaper.CountTracks(0)-1 do

        local tr = GetTrack(t)
        local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
        savedata.trackdata[t] = {track = t,
                                 guid = GetTrackGUID(tr),
                                 chunkdata = chunk}
      end
      savedata.stripdata = strips
      savedata.snapdata = snapshots
      savedata.switchers = switchers

      --Pickle doesn't like {} and -1#INF in strings (much) - remove before pickling
      if savedata.stripdata and #savedata.stripdata > 0 then
        for s = 1, #savedata.stripdata do
          for p = 1, lvar.maxpage do
            if #savedata.stripdata[s][p].controls > 0 then
              for c = 1, #savedata.stripdata[s][p].controls do
                if savedata.stripdata[s][p].controls[c].ctlcat == ctlcats.pkmeter then
                  savedata.stripdata[s][p].controls[c].val = -150
                end
              end
            end
          end
        end
      end

      --[[for i = 1, #savedata.strip.controls do
        savedata.strip.controls[i].fxguid = convertguid(savedata.strip.controls[i].fxguid)
      end]]

      local save_path=paths.sets_path
      local fn=save_path..fn..".stripset"

      local DELETE=true
      local file

      if reaper.file_exists(fn) then

      end

      if DELETE then
        file=io.open(fn,"w")
        local pickled_table=pickle(savedata)
        file:write(pickled_table)
        file:close()
      end

      --reinstate {} after pickling
      --[[for i = 1, #savedata.strip.controls do
        if savedata.strip.controls[i].fxguid then
          savedata.strip.controls[i].fxguid = '{'..savestrip.strip.controls[i].fxguid..'}'
        end
      end]]

      OpenMsgBox(1,'Strip set saved.',1)

    end

  end

  function SaveSet2(fn, trlst, trcnt2, verbose)

    if verbose == nil then verbose = true end

    if fn and string.len(fn)>0 then

      CleanData()

      UpdateCtlTrackGUIDs()

      local save_path=paths.sets_path
      local fn=save_path..fn..".stripset"
      local file
      file=io.open(fn,"w")
      file:write('[STRIPSET_VERSION]3\n')

      local trcnt = reaper.CountTracks(0)
      if trlst then
        file:write('[TRACKS]'..trcnt2..'\n')
        file:write('[SUBSET]'..1 ..'\n')
        local lst = ''
        for a,b in pairs(trlst) do
          lst = lst..','..a
        end
        file:write('[TRLST]'..string.sub(lst,2)..'\n')
      else
        file:write('[TRACKS]'..trcnt..'\n')
      end
      local bpm, _ = reaper.GetProjectTimeSignature2(0)
      file:write('[BPM]'..bpm..'\n')

      local savestrip = {}
      local switchlst = {}
      local switchidx = {}

      for t = -1, trcnt-1 do

        if not trlst or trlst[t] then

          if verbose then
            GUI_DrawMsgX(obj, gui, 'Saving Track Data...', t+1, trcnt)
          end

          strip = tracks[t].strip

          local tr = GetTrack(t)
          local i, j
          local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
          local trackdata = {track = t,
                             guid = GetTrackGUID(tr),
                             chunkdata = chunk}
          --check tracknums

          if strip ~= -1 then
            for p = 1, lvar.maxpage do
              Snapshot_DeleteOrphanedSubsets(strip, p)
              for j = 1, #strips[strip][p].controls do
                local ctl = strips[strip][p].controls[j]
                if ctl.tracknum and ctl.tracknum == strips[strip].track.tracknum then
                  ctl.tracknum = nil
                end
                if trlst and ctl.ctlcat == ctlcats.switcher and not switchidx[ctl.switcherid] then
                  local sidx = #switchlst+1
                  switchlst[sidx] = switchers[ctl.switcherid]
                  switchidx[ctl.switcherid] = sidx
                end
              end
            end
          end

          --local switchtab = {}
          --local saveswitchers = {}
          --local switchcnt = 1

          if strip ~= -1 then
            for p = 1, lvar.maxpage do
              for j = 1, #strips[strip][p].controls do
                local ctl = strips[strip][p].controls[j]
                if ctl.ctlcat == ctlcats.pkmeter then
                  ctl.val = -150
                end

                --[[if ctl.ctlcat == ctlcats.switcher then
                  switchtab[ctl.switcherid] = switchcnt
                  saveswitchers[switchcnt] = switchers[ctl.switcherid]
                  switchcnt = switchcnt + 1
                end]]
              end
            end
          end

          --[[savestrip.switchers = saveswitchers
          savestrip.switchconvtab = switchtab]]
          --savestrip.trackdata = {}
          --savestrip.trackdata[t] = trackdata
          local pickleddata = pickle(trackdata)

          file:write('[TRACK]'..t..'\n')
          file:write('[DATA]\n'..pickleddata..'\n[\\DATA]\n')
          file:write('[STRIPDATA]'.. strip ..'\n')
          local t = SaveStripData_FN(strip,nil,nil,file)
          file:write('[\\STRIPDATA]\n')

          if snapshots and snapshots[strip] then
            file:write('[SNAPSHOTDATA]\n')
            SaveSnapshotData_FN(strip,nil,nil,file)
            file:write('[\\SNAPSHOTDATA]\n')
          end
          file:write('[\\TRACK]\n')

          --faders
          --modulators

        end

      end

      if not trlst then
        local switchdata = pickle(switchers)
        file:write('[SWITCHDATA]\n'..switchdata..'\n[\\SWITCHDATA]\n')
      else
        local switchdata = pickle(switchlst)
        local switchdataidx = pickle(switchidx)
        file:write('[SWITCHDATA]\n'..switchdata..'\n[\\SWITCHDATA]\n')
        file:write('[SWITCHDATAIDX]\n'..switchdataidx..'\n[\\SWITCHDATAIDX]\n')
      end

      file:close()

      if verbose then
        OpenMsgBox(1,'Strip set saved.',1)
      end

    else
      return nil
    end

  end

  function LoadSet(merge)

    local retval, fn = reaper.GetUserFileNameForRead(paths.sets_path..'*', 'Load Strip Set', '.stripset')
    if retval then

      local loaddata = nil
      if reaper.file_exists(fn) then
        if merge == nil then merge = false end
        lsmerge = merge
        return fn

      else
        OpenMsgBox(1,'File not found.',1)
      end

    end

  end

  function GetTimebase()

    if reaper.GetToggleCommandState(reaper.NamedCommandLookup('SWS_AWTBASETIME')) == 1 then
      return 0
    elseif reaper.GetToggleCommandState(reaper.NamedCommandLookup('_SWS_AWTBASEBEATPOS')) == 1 then
      return 1
    elseif reaper.GetToggleCommandState(reaper.NamedCommandLookup('_SWS_AWTBASEBEATALL')) == 1 then
      return 2
    else
      return -1
    end

  end

  function SetTimebase(tb)

    local id
    if tb == 0 then
      id = '_SWS_AWTBASETIME'
    elseif tb == 1 then
      id = '_SWS_AWTBASEBEATPOS'
    elseif tb == 2 then
      id = '_SWS_AWTBASEBEATALL'
    end
    if id then
      reaper.Main_OnCommand(reaper.NamedCommandLookup(id),0)
    end
  end

  function splitnum(s,sep)
     local sep, fields = sep or ":", {}
     local pattern = s.format("([^%s]+)", sep)
     s:gsub(pattern, function(c) fields[#fields+1] = tonumber(c) end)
     return fields
  end

  function LoadSet2(fn, merge, preserve_unknown_guids)

    if merge == nil then merge = false end

    local match = string.match
    local find = string.find

    --GUI_DrawMsgX(obj, gui, 'Loading Data...')
    Progress('Loading Set Data', 0)

    local file
    file=io.open(fn,"r")
    local content=file:read("*a")
    file:close()

    local loaddata = {}
    --local msg, msg2

    local header = match(content,'(.-)%[TRACK%]')
    --DBG(header)

    local version, trcnt = match(header or '','%[STRIPSET_VERSION%](%d+)\n%[TRACKS%](%d+)\n')
    local pbpm = match(header or '','%[BPM%](%d+.%d+)\n')

    version = tonumber(version)

    local subset, trlst
    local stripc = 0

    if version and version == 2 or version == 3 then

      loaddata.version = version
      loaddata.trackdata = {}
      loaddata.stripdata = {}
      loaddata.snapdata = {}
      loaddata.switchers = {}

      local ts, te
      if match(header or '','%[SUBSET%]') then
        subset = true
        trlst = splitnum(match(header or '','%[TRLST%](.-)\n'),',')
        table.sort(trlst)
        --for i = 1, #trlst do
        --  DBG(trlst[i])
        --end
        ts = 1
        te = trcnt
      else
        ts = -1
        te = trcnt-1
      end

      local tidx
      for tt = ts, te do

        if subset then
          t = trlst[tt]
          tidx = tt-ts+1
        else
          t = tt
          tidx = tt
        end

        --GUI_DrawMsgX(obj, gui, 'Loading Track Data...', t+1, trcnt)
        Progress('Loading Track Data', 0.1)

        local trdata
        if t == -1 then
          --trdata = match(content,'%[TRACK%]%'..t..'\n(.-)%[\\TRACK%]')
          local s, e = find(content,'%[TRACK%]%'..t..'\n.-%[\\TRACK%]')
          trdata = string.sub(content,s,e)
          content = string.sub(content,e)
        else
          --trdata = match(content,'%[TRACK%]'..t..'\n(.-)%[\\TRACK%]')
          local s, e = find(content,'%[TRACK%]'..t..'\n.-%[\\TRACK%]')
          trdata = string.sub(content,s,e)
          content = string.sub(content,e)
        end
        if trdata then

          --local tt = reaper.time_precise()
          local data = match(trdata,'%[DATA%]\n(.-)%[\\DATA%]')
          local strip
          local stripx, sdata = match(trdata,'%[STRIPDATA%](%d+)\n(.-)%[\\STRIPDATA%]')
          local ssdata = match(trdata,'%[SNAPSHOTDATA%]\n(.-)%[\\SNAPSHOTDATA%]')
          --DBG('Find Data'..t+1 ..': '..round(reaper.time_precise()-tt,6))

          --load data
          --local tt = reaper.time_precise()
          local ddata = {}
          if sdata then
            local lines = splitln(sdata)
            if lines and #lines > 0 then
              for ln = 1, #lines do
                local idx, val = match(lines[ln],'%[(.-)%](.*)')
                if idx then
                  val = string.gsub(val, '[\r]', '') --Remove \r for Mac use
                  ddata[idx] = val
                end
              end
            end
          end
          if ssdata then
            local lines = splitln(ssdata)
            if lines and #lines > 0 then
              for ln = 1, #lines do
                local idx, val = match(lines[ln],'%[(.-)%](.*)')
                if idx then
                  ddata[idx] = val
                end
              end
            end
          end
          --DBG('Track Data'..t+1 ..': '..round(reaper.time_precise()-tt,6))

          --local tt = reaper.time_precise()
          loaddata.trackdata[tidx] = unpickle(data)
          --DBG('Unpickle'..': '..round(reaper.time_precise()-tt,6))

          if stripx then
            --DBG('aaa')
            stripc = stripc + 1
            strip = tonumber(stripc)
            --DBG(strip..'  '..tostring(stripx))

            local pfx = 'strip_s'..stripx..'_'
            local pfx2 = 'snap_s'..stripx..'_'

            loaddata.stripdata[strip] = {{}}
            loaddata.snapdata[strip] = {}

            loaddata.stripdata[strip].page = tonumber(zn(ddata[pfx..'page'],1))
            loaddata.stripdata[strip].track = {
                                             name = ddata[pfx..'track_name'],
                                             guid = ddata[pfx..'track_guid'],
                                             tracknum = tonumber(ddata[pfx..'track_num']),
                                             strip = tonumber(ddata[pfx..'track_strip']),
                                             }

            for p = 1, lvar.maxpage do
              local key = pfx..'p'..p..'_'
              local key2 = pfx2..'p'..p..'_'

              loaddata.stripdata[strip][p] = LoadStripDataX(key,ddata)
              loaddata.snapdata[strip][p] = LoadSnapDataX(key2,ddata)

            end
          end
        else
          DBG('Error reading track data: track '..t)
        end
      end

      local swdata = match(content,'%[SWITCHDATA%]\n(.-)%[\\SWITCHDATA%]')
      local swdataidx = match(content,'%[SWITCHDATAIDX%]\n(.-)%[\\SWITCHDATAIDX%]')

      loaddata.switchers = unpickle(swdata)
      if subset and swdataidx then
        loaddata.switchersidx = unpickle(swdataidx)
      end

    else

      loaddata = unpickle(content)
      stripc = #loaddata.stripdata

    end

    if loaddata == nil then return end
    Progress('Inserting Tracks', 0.2)

    guids = {}

    --INIT()
    local t_offset = reaper.CountTracks(0)
    local tstart = 0
    local t_offtab = {}

    if subset then
      tstart = 1
      t_offset = t_offset - 1
      for i = 1, #trlst do
        t_offtab[trlst[i]] = i
      end
    elseif version then
      t_offset = t_offset + 1
      tstart = -1
    end

    for i = tstart, #loaddata.trackdata do
      Progress('Processing Track Data', 0.2 + 0.1*((i-tstart)/math.max(#loaddata.trackdata-tstart,1)))
      loaddata.trackdata[i].chunkdata = string.gsub(loaddata.trackdata[i].chunkdata,
                                                    '({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                                                    function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end return guids[d] end)
      if subset then
        loaddata.trackdata[i].chunkdata = ReplaceRCVs(loaddata.trackdata[i].chunkdata, t_offset, t_offtab)
      else
        loaddata.trackdata[i].chunkdata = ReplaceRCVs(loaddata.trackdata[i].chunkdata, t_offset)
      end
    end

    local obpm, tb
    if pbpm then
      tb = GetTimebase()
      if tb ~= 0 then
        SetTimebase(0)
      end
      obpm, _ = reaper.GetProjectTimeSignature2(0)
      reaper.SetCurrentBPM(0, pbpm, false)
    end

    local ft = reaper.CountTracks(0)
    local lt = ft + #loaddata.trackdata-1
    for i = tstart, #loaddata.trackdata do

      reaper.InsertTrackAtIndex(t_offset+i+1, false)

    end

    for i = tstart, #loaddata.trackdata do

      Progress('Merging Track Data', 0.3 + 0.2*((i-tstart)/math.max(#loaddata.trackdata-tstart,1)))

      local tr = GetTrack(t_offset+i)
      --[[local condition_chunk = string.gsub(loaddata.trackdata[i].chunkdata, "<PROGRAMENV.->\n", "")
      if condition_chunk ~= loaddata.trackdata[i].chunkdata then
        SetTrackChunk(tr, condition_chunk, false)
      end]]

      SetTrackChunk(tr, loaddata.trackdata[i].chunkdata, false)
      if i == -1 or loaddata.trackdata[i].track == -1 then
        reaper.GetSetMediaTrackInfo_String(tr, "P_NAME", 'SET MASTER', true)
        reaper.SetOnlyTrackSelected(tr)
        --if reaper.ActionExists()
        reaper.Main_OnCommand(reaper.NamedCommandLookup('_S&M_FOLDERON'),0)
      end
    end

    if pbpm and obpm then
      reaper.SetCurrentBPM(0, obpm, false)
      if tb ~= 0 and tb ~= -1 then
        SetTimebase(tb)
      end
    end

    local cids = {}
    local grids = {}
    local ngrids = {}
    local swids = {}

    --update tracknums and guids, and cids


    for s = 1, #loaddata.stripdata do
      if loaddata.stripdata and loaddata.stripdata[s] then
        Progress('Processing Strip Data', 0.5 + 0.4*(s/math.max(#loaddata.stripdata,1)))
        --GUI_DrawMsgX(obj, gui, 'Parsing Strip Data...', s, #loaddata.stripdata)

        loaddata.stripdata[s].track.tracknum = loaddata.stripdata[s].track.tracknum + t_offset
        loaddata.stripdata[s].track.guid = guids[loaddata.stripdata[s].track.guid]

        for p = 1, lvar.maxpage do

          if loaddata.stripdata[s][p] then

            loaddata.stripdata[s][p].pop = nil

            if #loaddata.stripdata[s][p].controls > 0 then

              for c = 1, #loaddata.stripdata[s][p].controls do

                local ctl = loaddata.stripdata[s][p].controls[c]
                if ctl.tracknum then
                  if preserve_unknown_guids then
                    if guids[ctl.trackguid] then
                      ctl.tracknum = ctl.tracknum + t_offset
                      ctl.trackguid = guids[ctl.trackguid]
                    end
                  else
                    ctl.tracknum = ctl.tracknum + t_offset
                    ctl.trackguid = guids[ctl.trackguid]
                  end
                end
                if ctl.fxguid then
                  if preserve_unknown_guids then
                    if guids[ctl.fxguid] then
                      ctl.fxguid = guids[ctl.fxguid]
                    end
                  else
                    ctl.fxguid = guids[ctl.fxguid]
                  end
                end
                if ctl.param_info.paramdesttrnum then
                  if preserve_unknown_guids then
                    if guids[ctl.param_info.paramdestguid] then
                      ctl.param_info.paramdesttrnum = ctl.param_info.paramdesttrnum + t_offset
                      ctl.param_info.paramdestguid = guids[ctl.param_info.paramdestguid]
                    end
                  else
                    ctl.param_info.paramdesttrnum = ctl.param_info.paramdesttrnum + t_offset
                    ctl.param_info.paramdestguid = guids[ctl.param_info.paramdestguid]
                  end
                end
                if merge then
                  if cids[ctl.c_id] == nil then
                    cids[ctl.c_id] = GenID()
                    ctl.c_id = cids[ctl.c_id]
                  end
                end

                if ctl.ctlcat == ctlcats.fxmulti then
                  local addfx = ctl.addfx
                  if addfx and #addfx > 0 then
                    local afxcnt = #addfx
                    local ntab = {}
                    for afx = 1, #addfx do

                      if guids[addfx[afx].guid] then
                        ncnt = #ntab + 1
                        ntab[ncnt] = {}
                        ntab[ncnt].guid = guids[addfx[afx].guid]
                        ntab[ncnt].fxnum = addfx[afx].fxnum
                        ntab[ncnt].trn = addfx[afx].trn + t_offset
                        ntab[ncnt].trguid = guids[addfx[afx].trguid]
                      end
                    end
                    ctl.addfx = ntab
                  end
                end

                --compatibility
                if ctl.font == nil then ctl.font = fontname_def end
                if ctl.xydata == nil then ctl.xydata = {snapa = 1, snapb = 1, snapc = 1, snapd = 1, x = 0.5, y = 0.5} end
                if ctl.textoffx == nil then ctl.textoffx = 0 end
                if ctl.textoffvalx == nil then ctl.textoffvalx = 0 end
                if ctl.textcolv == nil then ctl.textcolv = ctl.textcol end
                if ctl.textsizev == nil then ctl.textsizev = ctl.textsize end
                if ctl.knobsens == nil then
                  ctl.knobsens = {norm = tonumber(settings_defknobsens.norm),
                                  fine = tonumber(settings_defknobsens.fine),
                                  wheel = tonumber(settings_defknobsens.wheel),
                                  wheelfine = tonumber(settings_defknobsens.wheelfine),
                                  m_norm = tonumber(settings_defknobsens.m_norm),
                                  m_fine = tonumber(settings_defknobsens.m_fine),
                                  m_wheel = tonumber(settings_defknobsens.m_wheel),
                                  m_wheelfine = tonumber(settings_defknobsens.m_wheelfine)}
                end

                if ctl.grpid then
                  if grids[ctl.grpid] then
                    ctl.grpid = grids[ctl.grpid]
                  else
                    local grpid = GenID()
                    ngrids[grpid] = 1
                    grids[ctl.grpid] = grpid
                    ctl.grpid = grpid
                  end
                end

                ctl.macrofader = nil
                ctl.switchfader = nil
                ctl.mod = nil

              end

              if merge then
                for c = 1, #loaddata.stripdata[s][p].controls do
                  local ctl = loaddata.stripdata[s][p].controls[c]
                  if ctl.random then

                    ctl.random.parent_cid = cids[ctl.random.parent_cid]
                    if #ctl.random.ctls > 0 then
                      for rc = 1, #ctl.random.ctls do

                        ctl.random.ctls[rc].c_id = cids[ctl.random.ctls[rc].c_id]

                      end
                    end

                  end
                end
              end
            end
            if #loaddata.stripdata[s][p].graphics > 0 then
              for c = 1, #loaddata.stripdata[s][p].graphics do
                local ctl = loaddata.stripdata[s][p].graphics[c]

                if ctl.bright == nil then ctl.bright = 0.5 end
                if ctl.contr == nil then ctl.contr = 0.5 end
                if ctl.rmult == nil then ctl.rmult = 0.5 end
                if ctl.gmult == nil then ctl.gmult = 0.5 end
                if ctl.bmult == nil then ctl.bmult = 0.5 end
                if ctl.alpha == nil then ctl.alpha = 1 end

                if ctl.stretchmode == nil then ctl.stretchmode = 1 end
                if ctl.edgesz == nil then ctl.edgesz = 8 end

                if ctl.grpid then
                  if grids[ctl.grpid] then
                    ctl.grpid = grids[ctl.grpid]
                  else
                    local grpid = GenID()
                    ngrids[grpid] = 1
                    grids[ctl.grpid] = grpid
                    ctl.grpid = grpid
                  end
                end
              end
            end
          end

        end
      end

    end

    if merge then
      if #loaddata.snapdata > 0 then
        for s = 1, #loaddata.snapdata do

          --GUI_DrawMsgX(obj, gui, 'Merging Snapshot Data...', s, #loaddata.snapdata)
          if loaddata.snapdata[s] then
            for p = 1, lvar.maxpage do

              if loaddata.snapdata[s][p] and #loaddata.snapdata[s][p] > 0 then
                for sst = 1, #loaddata.snapdata[s][p] do

                  if sst == 1 then
                    if loaddata.snapdata[s][p][sst] and #loaddata.snapdata[s][p][sst] > 0 then

                      for ss = 1, #loaddata.snapdata[s][p][sst] do
                        if loaddata.snapdata[s][p][sst][ss].data and #loaddata.snapdata[s][p][sst][ss].data > 0 then
                          for d = 1, #loaddata.snapdata[s][p][sst][ss].data do
                            if cids[loaddata.snapdata[s][p][sst][ss].data[d].c_id] then
                              loaddata.snapdata[s][p][sst][ss].data[d].c_id = cids[loaddata.snapdata[s][p][sst][ss].data[d].c_id]
                            end
                          end
                        end
                      end
                    end
                  else
                    if loaddata.snapdata[s][p][sst].ctls and #loaddata.snapdata[s][p][sst].ctls > 0 then
                      for ctl = 1, #loaddata.snapdata[s][p][sst].ctls do
                        if cids[loaddata.snapdata[s][p][sst].ctls[ctl].c_id] then
                          loaddata.snapdata[s][p][sst].ctls[ctl].c_id = cids[loaddata.snapdata[s][p][sst].ctls[ctl].c_id]
                        end
                      end
                    end

                    if loaddata.snapdata[s][p][sst].snapshot and #loaddata.snapdata[s][p][sst].snapshot > 0 then
                      for ss = 1, #loaddata.snapdata[s][p][sst].snapshot do
                        if loaddata.snapdata[s][p][sst].snapshot[ss].data and #loaddata.snapdata[s][p][sst].snapshot[ss].data > 0 then
                          for d = 1, #loaddata.snapdata[s][p][sst].snapshot[ss].data do
                            if cids[loaddata.snapdata[s][p][sst].snapshot[ss].data[d].c_id] then
                              loaddata.snapdata[s][p][sst].snapshot[ss].data[d].c_id = cids[loaddata.snapdata[s][p][sst].snapshot[ss].data[d].c_id]
                            end
                          end
                        end
                      end
                    end
                  end
                end
              end
            end
          end
        end
      end
    end

    local swstart = #switchers+1
    local nsflag = false

    for s = 1, #loaddata.stripdata do

      if loaddata.stripdata and loaddata.stripdata[s] then

        --GUI_DrawMsgX(obj, gui, 'Merging Switcher Data...', s, #loaddata.stripdata)

        for p = 1, lvar.maxpage do

          if loaddata.stripdata[s][p] then
            if #loaddata.stripdata[s][p].controls > 0 then

              for c = 1, #loaddata.stripdata[s][p].controls do
                local ctl = loaddata.stripdata[s][p].controls[c]
                if ctl.ctlcat == ctlcats.switcher then
                  --local stab = GetSwitcherTable(ctls[c].switcherid)
                  local stab
                  if subset then
                    stab = loaddata.switchers[loaddata.switchersidx[ctl.switcherid]]
                  else
                    stab = loaddata.switchers[ctl.switcherid]
                  end
                  ns = #switchers+1
                  nsflag = true

                  switchers[ns] = stab
                  swids[ctl.switcherid] = ns
                end
                --Take switchers
                if ctl.ctlcat == ctlcats.takeswitcher then

                  if ctl.iteminfo then

                    if preserve_unknown_guids then
                      if guids[ctl.iteminfo.guid] then
                        ctl.iteminfo.guid = guids[ctl.iteminfo.guid]
                      end
                    else
                      ctl.iteminfo.guid = guids[ctl.iteminfo.guid]
                    end

                    if preserve_unknown_guids then
                      if guids[ctl.iteminfo.trackguid] then
                        ctl.iteminfo.trackguid = guids[ctl.iteminfo.trackguid]
                      end
                    else
                      ctl.iteminfo.trackguid = guids[ctl.iteminfo.trackguid]
                    end

                    if preserve_unknown_guids then
                      if guids[ctl.iteminfo.utilguid] then
                        ctl.iteminfo.utilguid = guids[ctl.iteminfo.utilguid]
                      end
                    else
                      ctl.iteminfo.utilguid = guids[ctl.iteminfo.utilguid]
                    end
                  end

                end

              end
            end
          end
        end
      end
    end

    local extids = {}

    if nsflag then

      for s = swstart, #switchers do
        if switchers[s].parent and swids[switchers[s].parent.switcherid] then
          switchers[s].parent.switcherid = swids[switchers[s].parent.switcherid]
          switchers[s].parent.grpid = grids[switchers[s].parent.grpid]
        else
          switchers[s].parent = nil
        end
        if switchers[s].grpids and #switchers[s].grpids > 0 then
          for g = 1, #switchers[s].grpids do
            --if not g_cids[switchers[s].grpids[g].id] then
              if grids[switchers[s].grpids[g].id] then
                --DBG('grids ogrid: '..switchers[s].grpids[g].id..'  new: '..grids[switchers[s].grpids[g].id])
                switchers[s].grpids[g].id = grids[switchers[s].grpids[g].id]
              elseif not ngrids[switchers[s].grpids[g].id] then
                local ogid = switchers[s].grpids[g].id
                local grpid = GenID()
                switchers[s].grpids[g].id = grpid
                ngrids[grpid] = 1
                grids[ogid] = switchers[s].grpids[g].id
                --DBG('grids ogrid: '..ogid..'  new: '..switchers[s].grpids[g].id)
              end
            --end
          end
        end
        if switchers[s].current and grids[switchers[s].current] then
          switchers[s].current = grids[switchers[s].current]
        else
          if switchers[s].grpids and switchers[s].grpids[1] then
            switchers[s].current = switchers[s].grpids[1].id
          else
            switchers[s].current = -1
          end
        end
        if switchers[s].extendid then
          if not extids[switchers[s].extendid] then
            extids[switchers[s].extendid] = GenID()
          end
          switchers[s].extendid = extids[switchers[s].extendid]
        end
        if switchers[s].fxguids then
          for f = 1, #switchers[s].fxguids do
            switchers[s].fxguids[f] = guids[switchers[s].fxguids[f]]
          end
        end
      end
    end

    for s = 1, #loaddata.stripdata do

      if loaddata.stripdata and loaddata.stripdata[s] then

        --GUI_DrawMsgX(obj, gui, 'Merging Switcher Data...', s, #loaddata.stripdata)

        for p = 1, lvar.maxpage do

          if loaddata.stripdata[s][p] then
            if #loaddata.stripdata[s][p].controls > 0 then

              for c = 1, #loaddata.stripdata[s][p].controls do

                local ctl = loaddata.stripdata[s][p].controls[c]
                if ctl.switcherid then
                  if swids[ctl.switcherid] then
                    ctl.switcherid = swids[ctl.switcherid]
                  else

                  end
                  if ctl.ctlcat == ctlcats.switcher_pagesel and grids[ctl.param] then
                    --DBG('pagesel - '..ctl.param .. '  '..grids[ctl.param])
                    ctl.param = grids[ctl.param]
                  elseif ctl.ctlcat == ctlcats.switcher_pagesel then
                    --DBG('pagesel - grp id not found: '..ctl.param..'  '..tostring(ctl.paramidx))
                  end
                end
                if ctl.switcher then
                  if swids[ctl.switcher] then
                    ctl.switcher = swids[ctl.switcher]
                  else
                    ctl.switcher = nil
                  end
                end
              end
            end
            if #loaddata.stripdata[s][p].graphics > 0 then

              for c = 1, #loaddata.stripdata[s][p].graphics do
                local ctl = loaddata.stripdata[s][p].graphics[c]
                if ctl.switcher then
                  if swids[ctl.switcher] then
                    ctl.switcher = swids[ctl.switcher]
                  else
                    ctl.switcher = nil
                  end
                end
              end
            end
          end
        end
      end
    end

    local fidx = lvar.ctlfiles_idx
    local gridx = lvar.gfxfiles_idx

    image_count_add = image_count

    if #loaddata.stripdata > 0 then
      for s = 1, #loaddata.stripdata do

        Progress('Loading GFX Files', 0.9 + 0.05*(s/math.max(#loaddata.stripdata,1)))
        --GUI_DrawMsgX(obj, gui, 'Loading Graphics Images...', s, #loaddata.stripdata)
        for p = 1, lvar.maxpage do
          if #loaddata.stripdata[s][p].graphics > 0 then
            for i = 1, #loaddata.stripdata[s][p].graphics do

              local fnd = false
              local j = gridx[loaddata.stripdata[s][p].graphics[i].fn]
              if j then
              --for j = 0, #graphics_files do
                if nz(loaddata.stripdata[s][p].graphics[i].gfxtype,lvar.gfxtype.img) == lvar.gfxtype.img then
                  local iidx = LoadGraphics(loaddata.stripdata[s][p].graphics[i].fn)
                  if iidx then
                    if iidx ~= 1020 and iidx > image_count_add then
                      image_count_add = iidx
                    end
                    loaddata.stripdata[s][p].graphics[i].imageidx = iidx
                  end
                  --break

                end
              end
              --if not fnd then

              --end
            end
          end
        end
      end

      --DBG('IMG CNT ADD: '..image_count_add)
      for s = 1, #loaddata.stripdata do

        Progress('Loading Control Files', 0.95 + 0.05*(s/math.max(#loaddata.stripdata,1)))
        --GUI_DrawMsgX(obj, gui, 'Loading Control Images...', s, #loaddata.stripdata)

        for p = 1, lvar.maxpage do

          if #loaddata.stripdata[s][p].controls > 0 then
            for i = 1, #loaddata.stripdata[s][p].controls do
              local fnd = false
              local j = fidx[loaddata.stripdata[s][p].controls[i].ctl_info.fn]
              if j then
              --for j = 0, #ctl_files do
                if ctl_files[j].fn == loaddata.stripdata[s][p].controls[i].ctl_info.fn then
                  if ctl_files[j].imageidx ~= nil then
                    --DBG('IDX: '..ctl_files[j].imageidx..'  '..ctl_files[j].fn)
                    fnd = true
                    loaddata.stripdata[s][p].controls[i].ctl_info.imageidx = ctl_files[j].imageidx
                    loaddata.stripdata[s][p].controls[i].knob_select = j
                  else
                    fnd = true
                    image_count_add = F_limit(image_count_add + 1,0,image_max)
                    --DBG('ADD IDX: '..image_count_add..'  '..ctl_files[j].fn)
                    gfx.loadimg(image_count_add, paths.controls_path..loaddata.stripdata[s][p].controls[i].ctl_info.fn)
                    ctl_files[j].imageidx = image_count_add
                    loaddata.stripdata[s][p].controls[i].ctl_info.imageidx = image_count_add
                    loaddata.stripdata[s][p].controls[i].knob_select = j
                  end

                end
              else
                --DBG('not found: '..loaddata.stripdata[s][p].controls[i].ctl_info.fn)
              end
              --if not fnd then
              --end
            end
          end
        end
      end

    end
    image_count = image_count_add

    if strips == nil then
      strips = {}
    end

    --snapshots = {}
    if merge then
      Snapshots_INIT()
    end

    LoadCompatibility(loaddata.version,loaddata.stripdata)

    for s = 1, #loaddata.stripdata do
      if loaddata.stripdata and loaddata.stripdata[s] then
        local sc = #strips + 1
        strips[sc] = loaddata.stripdata[s]
        snapshots[sc] = loaddata.snapdata[s]

        for p = 1, lvar.maxpage do
          StoreSnapshotControlIdxs(sc,p)
          IndexExtIdentifiers(sc, p)
        end
      end
    end

    PopulateTracks()

    return ft, lt
    --[[if msg then
      OpenMsgBox(1, msg, 1, msg2)
    end]]

  end

  function ReplaceRCVs(chunk, t_offset, t_offtab)

    if t_offtab then
      local ch = string.gsub(chunk,'AUXRECV (%d-) ',function(d) return 'AUXRECV '..string.format('%i',t_offset+(t_offtab[tonumber(d)] or -10000))..' ' end)
      return ch
    else
      local ch = string.gsub(chunk,'AUXRECV (%d-) ',function(d) return 'AUXRECV '..string.format('%i',t_offset+d)..' ' end)
      return ch
    end
  end

  function Strip_SetPlugDef(stripfile, stripfol, batch)

    local stripdata = LoadStrip(stripfile)
    if stripdata then
      if #stripdata.fx == 1 then
        local fxc = stripdata.fx[1].fxchunk
        local fxident = GetPlugIdentifierFromChunk(fxc)
        if fxident then
          if batch then
            DBG(fxident)
          end
          if plugdefstrips_idx and plugdefstrips_idx[fxident] then
            local idx = plugdefstrips_idx[fxident]
            plugdefstrips[idx] = {plug = fxident, stripfile = strip_files[stripfile].fn, stripfol = strip_folders[stripfol].fn}
            OpenMsgBox(1,'Default strip for plugin '..fxident..' updated.',1)
          else
            if not plugdefstrips then
              plugdefstrips = {}
              plugdefstrips_idx = {}
            end
            local idx = #plugdefstrips+1
            plugdefstrips[idx] = {plug = fxident, stripfile = strip_files[stripfile].fn, stripfol = strip_folders[stripfol].fn}
            plugdefstrips_idx[fxident] = idx
            OpenMsgBox(1,'Default strip for plugin '..fxident..' set.',1)
          end
  
          if not batch then
            Save_PlugDefs()
          end
        end
        --DBG(fxident)
      else
        OpenMsgBox(1,'A default plugin strip must contain ONE fx plugin',1)
      end
    else
      DBG('Error loading: '..strip_files[strip_select].fn)
    end
    lupd.update_surface = true

  end

  function Strip_SetPlugDef2(stripfile, stripfol)

    lvar.defplugtmp = {sfil = stripfile, sfol = stripfol}
    local fxname2 = ''
    local ret, trn, itm, fxn = reaper.GetFocusedFX()
    if fxn then

      local tr = GetTrack(trn)
      if tr then
        local ret, fxname = reaper.TrackFX_GetFXName(tr, fxn, '')

        if fxname then

          fxname2 = fxname

        end
      end
    end

    OpenEB(999,'Please enter FX name:',fxname2)

  end

  function Strip_SetPlugDef2X(fxident)

    local stripfile, stripfol = lvar.defplugtmp.sfil, lvar.defplugtmp.sfol
    lvar.defplugtmp = nil

    local stripdata = LoadStrip(stripfile)
    if #stripdata.fx == 1 then
      if fxident and fxident ~= '' then
        fxident = string.lower(fxident)
        if plugdefstrips_idx and plugdefstrips_idx[fxident] then
          local idx = plugdefstrips_idx[fxident]
          plugdefstrips[idx] = {plug = fxident, stripfile = strip_files[stripfile].fn, stripfol = strip_folders[stripfol].fn}
          OpenMsgBox(1,'Default strip for plugin '..fxident..' updated.',1)
        else
          if not plugdefstrips then
            plugdefstrips = {}
            plugdefstrips_idx = {}
          end
          local idx = #plugdefstrips+1
          plugdefstrips[idx] = {plug = fxident, stripfile = strip_files[stripfile].fn, stripfol = strip_folders[stripfol].fn}
          plugdefstrips_idx[fxident] = idx
          OpenMsgBox(1,'Default strip for plugin '..fxident..' set.',1)
        end

        Save_PlugDefs()
      end

    else
      OpenMsgBox(1,'A default plugin strip must contain ONE fx plugin',1)
    end
    lupd.update_surface = true

  end

  function Save_PlugDefs()

    if plugdefstrips and #plugdefstrips > 0 then
      --create backup
      local ffn = paths.strips_path..'PluginDefaults.lbx'
      local rfn = paths.strips_path..'PluginDefaults.lbxbak'
      copyfile(ffn, rfn)

      local file = io.open(paths.strips_path..'PluginDefaults.lbx','w')
      if file then

        file:write('[count]'..#plugdefstrips..'\n')
        for i = 1, #plugdefstrips do
          file:write('['..i..'_plug]'..plugdefstrips[i].plug..'\n')
          file:write('['..i..'_file]'..plugdefstrips[i].stripfile..'\n')
          file:write('['..i..'_fol]'..plugdefstrips[i].stripfol..'\n')
        end
        file:close()
      end

    end

  end

  function Load_PlugDefs()

    plugdefstrips = {}
    plugdefstrips_idx = {}

    local file = io.open(paths.strips_path..'PluginDefaults.lbx','r')
    if file then

      local content = file:read('*a')
      local data = {}
      local cnt = 0
      local lines = splitln(content)
      if lines and #lines > 0 then
        for ln = 1, #lines do
          local idx, val = string.match(lines[ln],'%[(.-)%](.*)')
          if idx then
            data[idx] = val
          end
        end
      end
      file:close()

      local p = 0
      local cnt = data['count']

      local save

      for i = 1, cnt do
        if data[i..'_plug'] then

          local plug = string.lower(data[i..'_plug'])
          local fol = data[i..'_fol']
          local fil = data[i..'_file']
          local fnd

          local fn = paths.strips_path..fol..'/'..fil
          if not reaper.file_exists(fn) then
            --search
            local f = 0
            local sd = reaper.EnumerateSubdirectories(paths.strips_path, f)
            while sd do
              local ff = 0
              local sf = reaper.EnumerateFiles(paths.strips_path..sd, ff)
              while sf do
                if sf == fil then
                  fol = sd
                  fnd = true
                  save = true
                  break
                end
                ff=ff+1
                sf = reaper.EnumerateFiles(paths.strips_path..sd, ff)
              end

              if fnd then
                break
              end
              f=f+1
              sd = reaper.EnumerateSubdirectories(paths.strips_path, f)
            end
          else
            fnd = true
          end

          if fnd then
            p=p+1
            plugdefstrips[p] = {}
            plugdefstrips[p].plug = plug
            plugdefstrips[p].stripfile = fil
            plugdefstrips[p].stripfol = fol

            --DBG(p..'  '..plug..'  '..fil..'  '..fol)

            if plugdefstrips[p].plug then
              plugdefstrips_idx[plugdefstrips[p].plug] = p
            end
          else
            save = true
          end
        end
      end

      if save then
        Save_PlugDefs()
      end
    end

  end

  function InsertDefaultStrip()
    if settings_insertdefaultoneverytrack then
      if tracks[track_select] and (strips[tracks[track_select].strip] == nil or (strips[tracks[track_select].strip][page].controls and #strips[tracks[track_select].strip][page].controls == 0)) then
        if settings_insertdefaultoneverypage or page == 1 then
          local ls = false
          if track_select == -1 then
            if strip_default_mast then
              stripfol_select = strip_default_mast.stripfol_select
              strip_select = strip_default_mast.strip_select
              ls = true
            end
          elseif track_select == LBX_GTRACK then
            if strip_default_glob then
              stripfol_select = strip_default_glob.stripfol_select
              strip_select = strip_default_glob.strip_select
              ls = true
            end
          else
            if strip_default then
              stripfol_select = strip_default.stripfol_select
              strip_select = strip_default.strip_select
              ls = true
            end
          end
          if ls then
            PopulateStrips(lvar.sortcontrols)
            loadstrip = LoadStrip(strip_select)
            if loadstrip then
              if gui == nil then
                GetGUI_vars()
              end
              GenStripPreview(gui, loadstrip.strip, loadstrip.switchers, loadstrip.switchconvtab)
              local _, strip = Strip_AddStrip(loadstrip,0,0)
              --image_count = image_count_add
              loadstrip = nil
              reaper.MarkProjectDirty(0)
              --SaveSingleStrip(strip)
            end
          end
        end
      end
    end
  end

  function ClearTrackStrip(tr_select, force)

    if tracks[tr_select] then

      local res
      if force ~= true then
        res = reaper.MB("Delete track's strip data?",'Delete Strip Data',4)
      end
      if res == 6 or force == true then
        tracks[tr_select].strip = -1
        CleanData()
      end
    end

  end

  function CleanData()

    local striptbl = {}
    local snaptbl = {}
    local xxytbl = {}
    --DBG('clean in '..#strips)
    for t = -1, reaper.CountTracks(0)-1 do
      if tracks[t].strip then
        if strips[tracks[t].strip] then

          table.insert(striptbl, strips[tracks[t].strip])
          table.insert(snaptbl, snapshots[tracks[t].strip])
          tblpos = #striptbl
          if xxy then
            xxytbl[tblpos] = xxy[tracks[t].strip]
          end

          striptbl[tblpos].track.strip = tblpos
          tracks[t].strip = tblpos

        end
      end
    end
    strips = striptbl
    snapshots = snaptbl
    --DBG('clean out '..#strips)
    if xxy then
      xxy = xxytbl
    end

    CheckDataTables(true,true)

  end


  ------------------------------------------------------------

  function GaugeSelect_INIT()

    local gs = {type = 1,
                x_offs = 0,
                y_offs = 0,
                radius = 50,
                arclen = 0.7,
                rotation = 0,
                ticks = 2,
                tick_size = 4,
                tick_offs = 1,
                val_freq = 1,
                col_tick = '192 192 192',
                col_arc = '192 192 192',
                col_val = '192 192 192',
                show_arc = true,
                show_tick = true,
                tick_shape = 1,
                show_val = true,
                val = 0,
                dval = '',
                vals = {},
                val_dp = 0,
                font = fontname_def,
                fontsz = -5,
                nudge = 0,
                spread = nil,
                mapptof = nil,
                numonly = false,
                abbrev = false}
    return gs

  end

  function INIT_Modulators(mods)

    if mods == nil then
      mods = {}
    end
    for i = 1, modulator_cnt do

      if mods[i] == nil then
        mods[i] = {active = false,
                   steps = 16,
                   div = 4,
                   stepsmult = 4,
                   interpolate = false,
                   syncv = 20,
                   sync = true,
                   offset = 0.5,
                   min = 0,
                   max = 1,
                   mode = 1,
                   data = {},
                   targets = {},
                   }
        for d = 1, mods[i].steps do
          mods[i].data[d] = 0.5
        end
      end

    end
    if #mods > modulator_cnt then
      for i = modulator_cnt+1, #mods do
        mods[i] = nil
      end
    end

    return mods

  end

  function INIT(keepprojid)

    DBGOut('')
    DBGOut('** DATA INITIALIZATION ***')
    LASTPROJECTID = PROJECTID

    if keepprojid then
      DBGOut('KEEP PROJECT ID: '..PROJECTID)
    else
      PROJECTID = math.ceil((math.abs(math.sin( -1 + (os.clock() % 2)))) * 0xFFFFFFFF)
      DBGOut('NEW PROJECT ID: '..PROJECTID)
    end
    lastprojdirty = reaper.IsProjectDirty(0)
    last_proj_change_count = -1
    projnamechange = false
    lastprojname = GetProjectName()

    g_cids = {}
    g_edstrips = {}
    g_savedirty = false

    lvar.ocids = {}

    toffY = true

    mode = 0
    mode0_submode = 0
    submode = 2
    fxmode = 0
    snaplrn_mode = false
    butt_h = 20
    fx_h = 160
    snaph = 300
    fsnaph = 300

    ogrid = settings_gridsize
    sb_size = 3

    cbi_filter = -1
    cbi_offset = 0
    P_butt_cnt = 0
    F_butt_cnt = 0
    G_butt_cnt = 0
    S_butt_cnt = 0
    FD_butt_cnt = 0
    MD_butt_cnt = 0
    SF_butt_cnt = 0
    SS_butt_cnt = 0
    FSS_butt_cnt = 0
    SM_butt_cnt = 17
    tlist_offset = 0
    sflist_offset = 0
    mdlist_offset = 0
    fdlist_offset = 0
    cyclist_offset = 0
    trctltypelist_offset = 0
    trctlslist_offset = 0
    plist_offset = 0
    flist_offset = 0
    slist_offset = 0
    smlist_offset = 0
    xxylist_offset = 0
    ssoffset = 0
    fssoffset = 0
    al_offset = 0
    sbsflist_offset = 0

    afxdialogS_offset = 0
    afxdialogT_offset = 0

    strips = {}
    switchers = {}
    snapshots = nil
    xxy = nil
    xxy_gravity = 1.5
    modulators = INIT_Modulators()
    modbaridx = {}
    modbaredit = {}

    surface_offset = {x = 0, y = 0}

    max_cycle = 256

    image_count = 1
    knob_select = 0
    ksel_size = 50
    ksel_loaded = false
    page = 1
    gpage = false
    navigate = true

    gfx_select = 0
    gfxfol_select = 0
    track_select = -1
    trackedit_select = -1
    trackfx_select = 0
    trackfxparam_select = 0
    ctl_select = nil
    scale_select = 1
    textcol_select = '205 205 205'
    textcolv_select = '205 205 205'
    ctltype_select = 1
    textoff_select = 45
    textoffval_select = 0
    textoff_selectx = 0
    textoffval_selectx = 0
    textsize_select = 0
    textsizev_select = 0
    defval_select = 0
    enabledefval_select = true
    strip_select = 0
    stripfol_select = 0
    maxdp_select = -1
    cycle_select = {statecnt = 0,val = 0,mapptof = false, invert = false, draggable = false,spread = false,nil}
    minov_select = nil
    maxov_select = nil
    dvaloff_select = 0
    trctltype_select = 0
    trctl_select = 1
    gfx_font_select = {idx = 1,
                         name = fontname_def,
                         size = fontsize_def,
                         bold = false,
                         italic = false,
                         underline = false,
                         vertical = false,
                         shadow = true,
                         shadow_x = 1,
                         shadow_y = 1,
                         shadow_a = 0.6}
    gfx_shadow_select = false

    gfx_textcol_select = '255 255 255'
    gfx_text_select = ''
    knob_scalemode_select = 1
    scalemode_select = 8
    framemode_select = 1
    sstype_select = 1
    fsstype_select = 1
    horiz_select = false
    mapptof_select = false
    draggable_select = false
    spread_select = false
    al_select = 0
    gauge_select = GaugeSelect_INIT()
    ctlfont_select = fontname_def
    bypass_bgdraw_c_select = false
    bypass_bgdraw_n_select = false
    bypass_bgdraw_v_select = false
    clickthrough_select = false

    gfxbright_select = 0.5
    gfxcontr_select = 0.5
    gfxr_select = 0.5
    gfxg_select = 0.5
    gfxb_select = 0.5
    gfxa_select = 1
    gfxstretchmode_select = 1
    gfxedgesz_select = 8
    mod_select = 1

    plist_w = 180
    oplist_w = 180

    time_nextupdate = 0
    time_nextupdate_pkmeter = 0
    time_checksend = 0
    time_sendupdate = 0

    show_ctlbrowser = false
    show_ctloptions = false
    show_lbloptions = false
    show_gfxoptions = false
    show_editbar = true
    show_settings = false
    show_cycleoptions = false
    show_paramlearn = false
    show_snapshots = false
    show_fsnapshots = false
    show_actionchooser = false
    show_xxy = false
    show_gaugeedit = false
    show_trackfxorder = false
    show_midiout = false
    show_bitmap = false
    show_dd = false
    show_lfoedit = false
    show_modass = false
    show_eqcontrol = false
    show_pinmatrix = false

    show_paramname = true
    show_paramval = true

    xxypath = {points = {}}
    xxypath_select = 1
    xxymode = 0
    xxyrecord = false
    xxypath_edit = true
    xxypath_tres = 400

    macro_lrn_mode = false
    macro_edit_mode = false
    eq_edit = false

    ctl_page = 0
    cycle_editmode = false

    pinmatrix_zoom = 1

    last_gfx_w = 0
    last_gfx_h = 0

    octlval = -1
    otrkcnt = -1
    ofxcnt = -1
    checktr = 0

    otrkcnt = reaper.CountTracks(0)

    PopulateTracks()
    PopulateGFX(DBG_mode, lvar.sortcontrols)
    PopulateControls(DBG_mode, lvar.sortcontrols)
    PopulateStripFolders(lvar.sortcontrols)
    PopulateStrips(lvar.sortcontrols)
    PopulateMediaItemInfo()
    PopulateTrackSendsInfo()
    PopulateTrackFX()
    PopulateTrackFXParams()

    faders = Faders_INIT(force, faders)

    EB_Open = 0
    EB_Enter = false

    MS_Open = 0
    MB_Enter = false

    lupd.update_gfx = true
    lupd.update_surface = true
    lupd.update_ctls = true
    lupd.update_sidebar = true
    lupd.update_topbar = true
    lupd.update_ctlopts = true
    lupd.update_actcho = false
    lupd.update_xxy = false
    force_gfx_update = true

    rcmrefreshtimercount = 0

    Snapshots_INIT()
    snapshot_fader = nil
    capture_fader = nil
    morph_data = {}
    snapstage_data = {}

    mouse = {}

    SetSurfaceSize()

  end

  function MenuSkins(mx, my)

    skin_folders = {}

    local i = 0
    local sf = reaper.EnumerateSubdirectories(paths.skins_path,i)
    while sf ~= nil do
      if reaper.file_exists(paths.skins_path..sf..'/skincols.lbx') then
        skin_folders[#skin_folders+1] = {fn = sf}
      end
      i=i+1
      sf = reaper.EnumerateSubdirectories(paths.skins_path,i)
    end
    local mstr = ''
    for s = 1, #skin_folders do
      if mstr ~= '' then
        mstr = mstr..'|'
      end
      mstr = mstr..skin_folders[s].fn
    end
    gfx.x = mx
    gfx.y = my
    local res = gfx.showmenu(mstr)
    if res > 0 then

      skin_select = skin_folders[res].fn..'/'
      SetSkinCols(gui)
      local ret
      skin, ret = LoadSkin()

      obj = GetObjects()
      --gfx.setimgdim(1003,-1,-1)
      --gfx.setimgdim(1005,-1,-1)
      --gfx.setimgdim(1006,-1,-1)
      --gfx.setimgdim(1007,-1,-1)
      --gfx.setimgdim(1011,-1,-1)
      Img_SetDim(1003,obj.sections[160].w, obj.sections[160].h)
      Img_SetDim(1005,obj.sections[180].w, obj.sections[180].h)
      Img_SetDim(1006,obj.sections[221].w, obj.sections[221].h)
      Img_SetDim(1007,obj.sections[220].w, obj.sections[220].h)
      Img_SetDim(1011,obj.sections[45].w, obj.sections[45].h)
      --resize_display = true
      lupd.update_gfx = true

    end

  end

  function LoadSkinCols(gui)

    local fn=paths.skins_path..skin_select..'skincols.lbx'
    file=io.open(fn,"r")
    if file then
      content=file:read("*a")
      file:close()

      if content then
        local data = {}
        local lines = splitln(content)
        if lines and #lines > 0 then
          for ln = 1, #lines do
            local idx, val = string.match(lines[ln],'%[(.-)%](.*)')
            if idx then
              data[idx] = val
            end
          end
        end

        gui.skol.sb_txt_on = data['sb_txt_on'] or gui.skol.sb_txt_on
        gui.skol.sb_txt_off = data['sb_txt_off'] or gui.skol.sb_txt_off
        gui.skol.lst_bg = data['lst_bg'] or gui.skol.lst_bg
        gui.skol.lst_txt = data['lst_txt'] or gui.skol.lst_txt
        gui.skol.lst_txtalt1 = data['lst_txtalt1'] or gui.skol.lst_txtalt1
        gui.skol.lst_txthl = data['lst_txthl'] or gui.skol.lst_txthl
        gui.skol.lst_barhl = data['lst_barhl'] or gui.skol.lst_barhl
        gui.skol.buttG_txt = data['buttG_txt'] or gui.skol.buttG_txt
        gui.skol.butt1_txt = data['butt1_txt'] or gui.skol.butt1_txt
        gui.skol.butt1_txt_off = data['butt1_txt_off'] or gui.skol.butt1_txt_off
        gui.skol.butt2_txt = data['butt2_txt'] or gui.skol.butt2_txt
        gui.skol.butt3_txt = data['butt3_txt'] or gui.skol.butt3_txt
        gui.skol.butt4_txt = data['butt4_txt'] or gui.skol.butt4_txt
        gui.skol.butt8_txt = data['butt8_txt'] or gui.skol.butt8_txt
        gui.skol.butt9_txt = data['butt9_txt'] or gui.skol.butt9_txt
        gui.skol.butt10_txt = data['butt10_txt'] or gui.skol.butt10_txt

        gui.skol.faderhighcol = data['faderhighcol'] or gui.skol.faderhighcol
        gui.skol.faderselcol = data['faderselcol'] or gui.skol.faderselcol

        gui.skol.modhighcol = data['modhighcol'] or gui.skol.modhighcol
        gui.skol.modselcol = data['modselcol'] or gui.skol.modselcol
        gui.skol.pnl_txt = data['pnl_txt'] or gui.skol.pnl_txt
        gui.skol.pnl_tittxt = data['pnl_tittxt'] or gui.skol.pnl_tittxt

        gui.skol.ss_bg = data['ss_bg'] or gui.skol.ss_bg
        gui.skol.ss_txt = data['ss_txt'] or gui.skol.ss_txt

        gui.skol.modbase_r = data['modbar_base_r'] or gui.skol.modbase_r
        gui.skol.modbase_g = data['modbar_base_g'] or gui.skol.modbase_g
        gui.skol.modbase_b = data['modbar_base_b'] or gui.skol.modbase_b
        gui.skol.modmult_r = data['modbar_mult_r'] or gui.skol.modmult_r
        gui.skol.modmult_g = data['modbar_mult_g'] or gui.skol.modmult_g
        gui.skol.modmult_b = data['modbar_mult_b'] or gui.skol.modmult_b
        gui.skol.mod_hl = data['modbar_hl'] or gui.skol.mod_hl
        gui.skol.mod_hl_t = tonumber(data['modbar_hl_trans']) or gui.skol.mod_hl_t
        gui.skol.mod_stepind = data['modbar_stepind'] or gui.skol.mod_stepind
        gui.skol.mod_bg = data['modbar_bg'] or gui.skol.mod_bg
        gui.skol.mod_barlines = data['modbar_barlines'] or gui.skol.mod_barlines
        gui.skol.mod_baroutline = data['modbar_outline'] or gui.skol.mod_baroutline

        gui.skol.track_strip = data['track_strip'] or gui.skol.track_strip
        gui.skol.track_nostrip = data['track_nostrip'] or gui.skol.track_nostrip
        gui.skol.track_special = data['track_special'] or gui.skol.track_special

        gui.skol.fx_byp = data['fx_bypassed'] or gui.skol.fx_byp

        gui.winsz.ctlopts = data['guisz_ctlopts_w'] or gui.winsz.ctlopts
        gui.winsz.snaps = data['guisz_snapwin_w'] or gui.winsz.snaps
        gui.winsz.pnltit = tonumber(data['guisz_pnltitbar']) or gui.winsz.pnltit

        gui.fontsz.lst = data['fontsize_lst'] or gui.fontsz.lst
        gui.fontsz.sb = data['fontsize_sb'] or gui.fontsz.sb
        gui.fontsz.settings = data['fontsize_settings'] or gui.fontsz.settings
        gui.fontsz.pnltit = data['fontsize_pnltit'] or gui.fontsz.pnltit
        gui.fontsz.butt = data['fontsize_butt'] or gui.fontsz.butt

        gui.skol.pnltit_shad = data['pnltit_shad'] or gui.skol.pnltit_shad
        gui.skol.sb_shad = data['sb_shad'] or gui.skol.sb_shad
        gui.skol.butt_shad = data['butt_shad'] or gui.skol.butt_shad

        gui.fontnm.lst = data['font_lst'] or gui.fontnm.lst
        gui.fontnm.pnltit = data['font_pnltit'] or gui.fontnm.pnltit
        gui.fontnm.sb = data['font_sb'] or gui.fontnm.sb
        gui.fontnm.butt = data['font_butt'] or gui.fontnm.butt

        gui.fontflag.lst = data['fontflag_lst'] or gui.fontflag.lst
        gui.fontflag.pnltit = data['fontflag_pnltit'] or gui.fontflag.pnltit
        gui.fontflag.sb = data['fontflag_sb'] or gui.fontflag.sb
        gui.fontflag.butt = data['fontflag_butt'] or gui.fontflag.butt

      end
    end
  end

  function SaveSkinCols(gui)

    local ffn=paths.skins_path..skin_select..'skincols.lbx'
    file=io.open(ffn,"w")
    file:write('[sb_txt_on]'..gui.skol.sb_txt_on..'\n')
    file:write('[sb_txt_off]'..gui.skol.sb_txt_off..'\n')
    file:write('[lst_bg]'..gui.skol.lst_bg..'\n')
    file:write('[lst_txt]'..gui.skol.lst_txt..'\n')
    file:write('[lst_txtalt1]'..gui.skol.lst_txtalt1..'\n')
    file:write('[lst_txthl]'..gui.skol.lst_txthl..'\n')
    file:write('[lst_barhl]'..gui.skol.lst_barhl..'\n')
    file:write('[buttG_txt]'..gui.skol.buttG_txt..'\n')
    file:write('[butt1_txt]'..gui.skol.butt1_txt..'\n')
    file:write('[butt1_txt_off]'..gui.skol.butt1_txt_off..'\n')
    file:write('[butt2_txt]'..gui.skol.butt2_txt..'\n')
    file:write('[butt3_txt]'..gui.skol.butt3_txt..'\n')
    file:write('[butt4_txt]'..gui.skol.butt4_txt..'\n')
    file:write('[butt8_txt]'..gui.skol.butt8_txt..'\n')
    file:write('[butt9_txt]'..gui.skol.butt9_txt..'\n')
    file:write('[butt10_txt]'..gui.skol.butt10_txt..'\n')
    file:write('[faderhighcol]'..gui.skol.faderhighcol..'\n')
    file:write('[faderselcol]'..gui.skol.faderselcol..'\n')
    file:write('[modhighcol]'..gui.skol.modhighcol..'\n')
    file:write('[modselcol]'..gui.skol.modselcol..'\n')
    file:write('[pnl_txt]'..gui.skol.pnl_txt..'\n')
    file:write('[pnl_tittxt]'..gui.skol.pnl_tittxt..'\n')
    file:close()

  end

  function SetSkinCols(gui)

    gui.skol = {}
    gui.skol.sb_txt_on = gui.color.black
    gui.skol.sb_txt_off = gui.color.white
    gui.skol.lst_bg = gui.color.cbobg
    gui.skol.lst_txt = gui.color.white
    gui.skol.lst_txtalt1 = gui.color.red
    gui.skol.lst_txthl = gui.color.black
    gui.skol.lst_barhl = gui.color.white
    gui.skol.buttG_txt = gui.color.white
    gui.skol.butt1_txt = gui.color.black
    gui.skol.butt1_txt_off = gui.color.white
    gui.skol.butt2_txt = gui.color.black
    gui.skol.butt3_txt = gui.color.white
    gui.skol.butt4_txt = gui.color.black
    gui.skol.butt8_txt = gui.color.white
    gui.skol.butt9_txt = gui.color.black
    gui.skol.butt10_txt = gui.color.black

    gui.skol.ss_bg = gui.color.cbobg
    gui.skol.ss_txt = gui.color.white

    gui.skol.faderhighcol = faderhighcol --'160 64 255'
    gui.skol.faderselcol = faderselcol --'255 160 255'

    gui.skol.modhighcol = modhighcol --'64 160 255'
    gui.skol.modselcol = modselcol --'160 255 255'
    gui.skol.modbase_r = 0
    gui.skol.modbase_g = 0
    gui.skol.modbase_b = 0.4
    gui.skol.modmult_r = 0.25
    gui.skol.modmult_g = 0.25
    gui.skol.modmult_b = 0.6
    gui.skol.mod_hl = gui.color.white
    gui.skol.mod_hl_t = 1
    gui.skol.mod_bg = gui.color.black
    gui.skol.mod_barlines = barcol
    gui.skol.mod_baroutline = gui.color.white

    gui.skol.pnl_txt = gui.color.white
    gui.skol.pnl_tittxt = gui.color.black

    gui.skol.track_strip = '0 192 0'
    gui.skol.track_nostrip = gui.color.white
    gui.skol.track_special = '255 192 60'

    gui.skol.fx_byp = '192 0 0'

    gui.winsz = {}
    gui.winsz.ctlopts = 160
    gui.winsz.snaps = 160
    gui.winsz.pnltit = 23

    gui.fontsz = {}
    gui.fontsz.lst = 0
    gui.fontsz.sb = 0
    gui.fontsz.settings = 0
    gui.fontsz.pnltit = 0
    gui.fontsz.butt = 0

    gui.fontnm = {}
    gui.fontnm.lst = 'Calibri'
    gui.fontnm.pnltit = 'Calibri'
    gui.fontnm.sb = 'Calibri'
    gui.fontnm.butt = 'Calibri'

    gui.fontflag = {}
    gui.fontflag.lst = 0
    gui.fontflag.pnltit = 0
    gui.fontflag.sb = 0
    gui.fontflag.butt = 0

    gui.skol.pnltit_shad = ''
    gui.skol.sb_shad = ''
    gui.skol.butt_shad = ''

    LoadSkinCols(gui)
    --SaveSkinCols(gui)
  end

  ------------------------------------------------------------

  function frameScale(m, v)

    if m == 1 then
      return v
    elseif m == 2 then
      return outCirc(v)
    else
      return v
    end

  end

  function ctlScale(m, v)

    local mm = lvar.scalemode_table[m]
    return v^mm

  end

  function ctlScaleInv(m, v)

    local mm = 1/lvar.scalemode_table[m]
    return (v or 0)^mm

  end

  function macScale(m, v)
    if m == 1 then
      return v
    else
      local func = lvar.easings[tonumber(m)]
      if func then
        return func(v)
      else
        return v
      end
    end
  end

  function macScaleInv(m, v)
    if m == 1 then
      return v
    else
      local func = lvar.easingsInv[tonumber(m)]
      if func then
        return func(v)
      else
        return v
      end
    end
  end

  --[[function macScale(m, v)
    if m == 1 then
      return v
    elseif m == 2 then
      return inSine(v)
    elseif m == 3 then
      return outSine(v)
    elseif m == 4 then
      return inOutSine(v)
    elseif m == 5 then
      return inCubic(v)
    elseif m == 6 then
      return outCubic(v)
    elseif m == 7 then
      return inOutCubic(v)
    elseif m == 8 then
      return inQuart(v)
    elseif m == 9 then
      return outQuart(v)
    elseif m == 10 then
      return inOutQuart(v)
    elseif m == 11 then
      return 1
    else
      return v
    end
  end]]

  function easeRet1(v)
    return 1
  end
  
  --[[function macScaleInv(m, v)
    if m == 1 then
      return v
    elseif m == 2 then
      return inSineInv(v)
    elseif m == 3 then
      return outSineInv(v)
    elseif m == 4 then
      return inOutSineInv(v)
    elseif m == 5 then
      return inCubicInv(v)
    elseif m == 6 then
      return outCubicInv(v)
    elseif m == 7 then
      return inOutCubicInv(v)
    elseif m == 8 then
      return inQuartInv(v)
    elseif m == 9 then
      return outQuartInv(v)
    elseif m == 10 then
      return inOutQuartInv(v)
    elseif m == 11 then
      return 1
    else
      return v
    end
  end]]

  --b=0 c=1 d=1
  function inSine(t)
    return 1 - math.cos((t * pi) / 2)
  end

  function inSineInv(t)
    return (math.acos(1-t) / pi) * 2
  end

  --[[function old_inSine(t)
    if t < 0 then
      return -(-1 * math.cos(-t * (pi / 2)) + 1)
    else
      return -1 * math.cos(t * (pi / 2)) + 1
    end
  end]]

  function outSine(t)
    return 1 * math.sin(t * (pi / 2))
  end

  function outSineInv(t)
    return math.asin(t) / (pi / 2)
  end

  function inOutSine(t)
    return -1/2 * (math.cos(pi * t) - 1)
  end

  function inOutSineInv(t)
    return math.acos(t * -2 + 1) / pi
  end

  --[[function inOutSine(t)
    if t < 0 then
      return 1/2 * (math.cos(pi * t) - 1)
    else
      return -1/2 * (math.cos(pi * t) - 1)
    end
  end]]

  function inCubic(t)
    return t^3
  end

  function inCubicInv(t)
    return t^(1/3)
  end

  function outCubic(t)
    return 1- (1-t)^3
  end

  function outCubicInv(t)
    return 1-((1-t)^(1/3))
  end
  
  --[[function inOutCubic(t)
    t = t * 2
    if t < 1 then
      return 1/2 * t * t * t
    else
      t = t - 2
      return 1/2 * (t * t * t + 2)
    end
  end]]
  
  --[[function inOutCubic(t)
    if t < 0.5 then
      return 4 * (t * t * t)
    else
      t=t*2
      t = t - 2
      return 1/2 * (t * t * t + 2)
    end
  end

  function inOutCubicInv(t)
    if t < 0.5 then
      return ((t)^(1/3))/4
    else
      --1/2 * ((t*2-2)^3 + 2)
      return (((((t/2+2)^(1/3)))+2)/2) ----????
      --return 1/2 * (t * t * t + 2)
    end
  end]]
  
  function inOutCubic(t)
    if t < 0.5 then
      return 4 * (t * t * t)
    else
      return 1 - (-2 * t + 2)^3 / 2
    end
  end
  
  function inOutCubicInv(t)
    if t < 0.5 then
      return ((t/4)^(1/3))
    else
      return (((1-t)*2)^(1/3)-2)/-2 
    end
  end
  
--[[  function old_inOutCubic(t)
    if t < 0 then
      DBG('P')
      t = -t * 2
      if t < 1 then
        return -(1/2 * t * t * t)
      else
        t = t - 2
        return -(1/2 * (t * t * t + 2))
      end
    else
      t = t * 2
      if t < 1 then
        DBG('X')
        return 1/2 * t * t * t
      else
        DBG(t)
        t = t - 2
        return 1/2 * (t * t * t + 2)
      end
    end
  end]]

  function inQuart(t)

    --[[if t < 0 then
      return -(t^4)
    else]]
      return t^4
    --end
  end

  function inQuartInv(t)
    return t^(1/4)
  end
  
  function outQuart(t)
    --[[if t < 0 then
      t = -t - 1
      return -(-1 * (t^4 - 1))
    else]]
      return 1 - (1 - t)^4
      --t = t - 1
      --return -1 * (t^4 - 1)
    --end
  end

  function outQuartInv(t)
    return 1 - (1-t)^(1/4)
  end
  
  function inOutQuart(t)
  
    if t < 0.5 then
      return 8 * t * t * t * t
    else
      return 1 - ((-2 * t + 2)^4) / 2
    end
    --[[if t < 0 then
      t = -t * 2
      if t < 1 then
        return -(1/2 * t^4)
      else
        t = t - 2
        return -(-1/2 * (t^4 - 2))
      end
    else
         t = t * 2
      if t < 1 then
        return 1/2 * t^4
      else
        t = t - 2
        return -1/2 * (t^4 - 2)
      end
    end]]
  end

  function inOutQuartInv(t)

    if t < 0.5 then
      return ((t/8)^(1/4))
    else
      --t = 1 - ((-2 * t + 2)^4) / 2
      --t
      return -(((((-2*t)+2)^(1/4))-2)/2)
    end
    
  end
  
  function inQuint(t)
    return t^5
  end

  function inQuintInv(v)
    return v^0.2
  end

  function testfunc(txt1)
    DBG(txt1)
    return 'return'..txt1
  end

  function tablelength(T)
    local count = 0
    for _ in pairs(T) do count = count + 1 end
    return count
  end

  function testfx()

    --DBG('    <FXCHAIN\n      SHOW 0\n      LASTSEL 0\n      DOCKED 0\n')
    for i = 0, reaper.CountTracks(0)-1 do

      local str = GetTrack(i)
      --local dtr = GetTrack(dsttrn)

      local chunk = GetTrackChunk(str, settings_usetrackchunkfix)
      local fnd, fxc, s, e = testchunkfxextract(chunk,1)

    end

  end

  function testfxinsert()

    local str = GetTrack(0)
    local chunk = GetTrackChunk(str, settings_usetrackchunkfix)
    local fnd, fxc, s, e = GetFXChunkFromTrackChunk(chunk,2)
    local trn = 0
    local str = GetTrack(trn)
    local chunk = GetTrackChunk(str, settings_usetrackchunkfix)
    local nchunk, nfxguid, ofxguid = Chunk_InsertFXChunkAtEndOfFXChain(trn, chunk,fxc)
    
    local chunks = GetFXChunks(0)
    for i = 1, #chunks do
      DBG('------------'..i)
      DBG(chunks[i].chunk)
    end
    
    local _, Rchunk = RemoveFXChunkFromTrackChunk(chunk,7)
    DBG(nchunk)
    --DBG(nchunk)
    --DBG(fxc)
    --DBG('guid='..nfxguid..'  '..ofxguid)

    --DBG(tostring(SetTrackChunk(str,nchunk, false)))

  end

  function DeleteFX(trn, fxnum)

    if reaper.APIExists('TrackFX_Delete') == true then
      local tr = GetTrack(trn)
      reaper.TrackFX_Delete(tr, fxnum-1)
    else
      local tr = GetTrack(trn)
     -- local fxcnt = reaper.TrackFX_GetCount(tr)
      local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
      local _, nchunk, _ = RemoveFXChunkFromTrackChunk(chunk, fxnum)
      if nchunk then
        SetTrackChunk(tr, nchunk, false)
      end
    end
  end

  function MoveFXChunk(srcfxnum, dstfxnum)

    if reaper.APIExists('TrackFX_CopyToTrack') == true then
      local trn = tracks[track_select].tracknum
      local tr = GetTrack(trn)
      reaper.TrackFX_CopyToTrack(tr,srcfxnum-1,tr,dstfxnum-1,true)
    else
      local writechunk = false
      local trn = tracks[track_select].tracknum
      local tr = GetTrack(trn)
      local fxcnt = reaper.TrackFX_GetCount(tr)
      local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)

      local nchunk = MoveFXChunk2(chunk, trn, srcfxnum, dstfxnum, fxcnt)
      if nchunk then
        SetTrackChunk(tr, nchunk, false)
      end
    end
  end

  function MoveFXChunkX(srcfxnum, dstfxnum, trn)

    if reaper.APIExists('TrackFX_CopyToTrack') == true then
      if trn == -3 then
        tr = reaper.GetSelectedTrack2(0,0,true)
        trn = reaper.GetMediaTrackInfo_Value(tr,'IP_TRACKNUMBER')-1
      else
        tr = GetTrack(trn)
      end
      if tr then
        reaper.TrackFX_CopyToTrack(tr,srcfxnum-1,tr,dstfxnum-1,true)
      end
    else
      local writechunk = false
      local tr
      if trn == -3 then
        tr = reaper.GetSelectedTrack2(0,0,true)
        trn = reaper.GetMediaTrackInfo_Value(tr,'IP_TRACKNUMBER')-1
      else
        tr = GetTrack(trn)
      end
      if tr then
        local fxcnt = reaper.TrackFX_GetCount(tr)
        local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
        local nchunk = MoveFXChunk2(chunk, trn, srcfxnum, dstfxnum, fxcnt)
        if nchunk then
          SetTrackChunk(tr, nchunk, false)
        end
      end
    end
  end

  function MoveFXChunk2(chunk, trn, srcfxnum, dstfxnum, fxcnt)

    local _, nchunk, movechunk = RemoveFXChunkFromTrackChunk(chunk, srcfxnum)

    if nchunk then
      if dstfxnum == fxcnt then
        --insert at end
        nchunk = Chunk_InsertFXChunkAtEndOfFXChain(trn, nchunk, movechunk, true)
        if nchunk then
          writechunk = true
        end
      else

        local fnd, _, s, e = GetFXChunkFromTrackChunk(nchunk, dstfxnum)
        if fnd then
          nchunk = string.sub(nchunk,0,s-1)..movechunk..string.sub(nchunk,s)
          writechunk = true
        end
      end
    end

    if writechunk then
      return nchunk
    end

  end

  function InsertFXChunk(chunk, trn, inschunk, dstfxnum, fxcnt, keepid)

    guids = {}
    local ofxid, nfxid = nil, nil
    local rchunk = nil
    local rchunk2 = nil

    if keepid == nil then
      --prepare insert chunk
      if inschunk then
        inschunk = string.gsub(inschunk,
                                'FXID ({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                                function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end return 'FXID '..guids[d] end)
      end

      --should be just one
      for i, v in pairs(guids) do
        ofxid = i
        nfxid = v
      end
    end

    local nchunk
    if chunk then
      if dstfxnum == fxcnt then
        --insert at end
        nchunk = Chunk_InsertFXChunkAtEndOfFXChain(trn, chunk, inschunk, true)
        if nchunk then
          writechunk = true
        end
      else

        local fnd, _, s, e = GetFXChunkFromTrackChunk(chunk, dstfxnum)
        if fnd then
          nchunk = string.sub(chunk,0,s-1)..inschunk..'\n'..string.sub(chunk,s)
          writechunk = true
        end
      end
    end

    if writechunk then
      return nchunk, nfxid, ofxid
    end

  end


  --returns success, fxchunk, start loc, end loc
  function GetFXChunkFromTrackChunk(trchunk, fxn)

    local s,e, fnd, fxchunk = 0,0,nil
    for i = 1,fxn do
      --s, e = string.find(trchunk,'(BYPASS.-WAK %d %d)',s)
      s, e = string.find(trchunk,'(BYPASS.-WAK.-)\n',s)
      if s and e then
        if i == fxn then 
          fnd = true 
          fxchunk = string.sub(trchunk,s,e-1)
          --string.gsub(fxchunk, '[\r]', '')
          break 
        end
        s=e+1
      else
        fxchunk = nil
        fnd = nil
        break
      end
    end
    return fnd, fxchunk, s, e

  end

  function GetFXChunks(tracknum)

    local tr = GetTrack(tracknum)
    local fxn = reaper.TrackFX_GetCount(tr)
    local fxtbl = {}
    local guididx = {}
    local chunk = GetTrackChunk(tr, settings_usetrackchunkfix)
    local s,e, fnd = 0,0,nil
    local trchunk_beg, trchunk_end
    for i = 1,fxn do
      --s, e = string.find(chunk,'(BYPASS.-WAK %d %d)',s)
      s, e = string.find(chunk,'(BYPASS.-WAK.-)\n',s)
      if i==1 then
        trchunk_beg = string.sub(chunk,0,s-2)
      elseif i == fxn then
        trchunk_end = string.sub(chunk,e)
      end
      if s and e then
        fxtbl[i] = {chunk = string.sub(chunk,s,e)}
        fxtbl[i].guid = string.match(fxtbl[i].chunk, 'FXID ({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})')
        guididx[fxtbl[i].guid] = i
        s=e+1
      else
        break
      end
    end
    return fxtbl, guididx, trchunk_beg, trchunk_end

  end

  function RemoveFXChunkFromTrackChunk(trchunk, fxn)

    local s,e, fnd, fxchunk = 0,0,nil
    local nchunk
    for i = 1,fxn do
      --s, e = string.find(trchunk,'(BYPASS.-WAK %d %d)',s)
      s, e = string.find(trchunk,'(BYPASS.-WAK.-)\n',s)
      if s and e then
        fxchunk = string.sub(trchunk,s,e)

        if i == fxn then
          fnd = true
          nchunk = string.sub(trchunk,0,s-2)..string.sub(trchunk,e)
          break
        end
        s=e+1
      else
        fxchunk = nil
        fndn = nil
        break
      end
    end
    return fnd, nchunk, fxchunk

  end

  function SetFXOffline(strip, page, ctl, trn, v)

    local trn = nz(strips[strip][page].controls[ctl].tracknum, trn)
    local fxn = strips[strip][page].controls[ctl].fxnum
    local str = GetTrack(trn)
    local chunk = GetTrackChunk(str, settings_usetrackchunkfix)

    local s,e, fnd = 0,0,nil
    for i = 0,fxn do
      s, e = string.find(chunk,'BYPASS %d %d %d',s)
      if s and e then
        if i == fxn then
          local byp = string.sub(chunk,s,e)
          if v == 1 then
            byp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' 1 '..f end)
          else
            byp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' 0 '..f end)
          end
          local nchunk = string.sub(chunk,0,s-1)..byp..string.sub(chunk,e+1)
          SetTrackChunk(str,nchunk, false)
          fnd = true
          break
        end
        s=e+1
      else
        break
      end
    end
    return fnd, fxchunk, s, e

  end

  function SetFXOffline2(strip, page, ctl, track, v)

    if reaper.APIExists('TrackFX_SetOffline') == true then
      local fxn = strips[strip][page].controls[ctl].fxnum
      local offl = false
      if v == 1 then offl = true end
      reaper.TrackFX_SetOffline(track,fxn,offl)
    else
      local fxn = strips[strip][page].controls[ctl].fxnum
      local str = track
      local chunk = GetTrackChunk(str, settings_usetrackchunkfix)

      local s,e, fnd = 0,0,nil
      for i = 0,fxn do
        s, e = string.find(chunk,'BYPASS %d %d %d',s)
        if s and e then
          if i == fxn then
            local byp = string.sub(chunk,s,e)
            if v == 1 then
              byp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' 1 '..f end)
            else
              byp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' 0 '..f end)
            end
            local nchunk = string.sub(chunk,0,s-1)..byp..string.sub(chunk,e+1)
            SetTrackChunk(str,nchunk, false)
            fnd = true
            break
          end
          s=e+1
        else
          break
        end
      end
      return fnd, fxchunk, s, e
    end

  end

  function ToggleFXBypass(strip, page, c, trn, forceval)

    local ctl = strips[strip][page].controls[c]
    trn = ctl.tracknum or trn
    local track = GetTrack(trn)
    if track then
      local pn = reaper.TrackFX_GetNumParams(track,ctl.fxnum)
      local v = reaper.TrackFX_GetParam(track,ctl.fxnum,pn-lvar.pn_byp)
      local val = 1-v
      --if forceval then
        val = forceval or val
      --end
      reaper.TrackFX_SetParam(track,ctl.fxnum,pn-lvar.pn_byp,val)
      if strip == tracks[track_select].strip then
        SetCtlDirty(c)
      end
    end
  end

  function ToggleFXBypass2(trn, fxnum, forceval)
    local track = GetTrack(trn)
    if track then
      local pn = reaper.TrackFX_GetNumParams(track,fxnum)
      local v = reaper.TrackFX_GetParam(track,fxnum,pn-lvar.pn_byp)
      local val = 1-v
      val = forceval or val
      reaper.TrackFX_SetParam(track,fxnum,pn-lvar.pn_byp,val)
    end
  end

  function ToggleFXWet(strip, page, c, trn, notoggle, val)

    local ctl = strips[strip][page].controls[c]
    trn = ctl.tracknum or trn
    local track = GetTrack(trn)
    if track then
      local pn = reaper.TrackFX_GetNumParams(track,ctl.fxnum)
      local nv
      if val then
        nv = val
      else
        local v = reaper.TrackFX_GetParam(track,ctl.fxnum,pn-lvar.pn_wet)
        if v > 0 then
          v = 1
        end
        nv = v
        if not notoggle then
          nv = 1-nv
        end
      end

      reaper.TrackFX_SetParam(track,ctl.fxnum,pn-lvar.pn_wet,nv)
      if strip == tracks[track_select].strip then
        SetCtlDirty(c)
      end
    end
  end

  function ToggleFXOffline(strip, page, ctl, trn, forceval)
    local trn = nz(strips[strip][page].controls[ctl].tracknum, trn)
    local fxn = strips[strip][page].controls[ctl].fxnum
    local str = GetTrack(trn)

    if reaper.APIExists('TrackFX_SetOffline') == true then
      --local fxn = strips[strip][page].controls[ctl].fxnum
      local offl = not reaper.TrackFX_GetOffline(str,fxn)
      reaper.TrackFX_SetOffline(str,fxn,offl)
    else
      local chunk = GetTrackChunk(str, settings_usetrackchunkfix)

      --local chlines = {}
      --local s,e=0,0

      local s,e, fnd = 0,0,nil
      for i = 0,fxn do
        s, e = string.find(chunk,'BYPASS %d %d %d',s)
        if s and e then
          if i == fxn then
            local byp = string.sub(chunk,s,e)
            local nbyp
            if forceval then
              nbyp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' '..forceval..' '..f end)
            else
              nbyp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) if e == '0' then return d..' 1 '..f else return d..' 0 '..f end end)
            end
            if nbyp ~= byp then
              local nchunk = string.sub(chunk,0,s-1)..nbyp..string.sub(chunk,e+1)
              SetTrackChunk(str,nchunk, false)
            end
            --fnd = true
            break
          end
          s=e+1
        else
          break
        end
      end
      --return fnd, fxchunk, s, e
    end
  end

  function SetFXOffline3(trn, fxn, offline, bypass, donotsetchunk, chunk)
    local str = GetTrack(trn)

    if reaper.APIExists('TrackFX_SetOffline') == true then
      --local strip = tracks[track_select].strip
      --local fxn = strips[strip][page].controls[trackfxparam_select].fxnum
      --DBG(strips[strip][page].controls[trackfxparam_select].param_info.paramname)
      local offl = false
      if offline == 1 then
        offl = true
      end
      reaper.TrackFX_SetOffline(str,fxn,offl)
      if bypass then
        SetFXBypass(trn, fxn, bypass)
      end
    else
      local chunk = chunk or GetTrackChunk(str, settings_usetrackchunkfix)
      local retchunk = chunk

      local s,e, fnd = 0,0,nil
      for i = 0,fxn do
        s, e = string.find(chunk,'BYPASS %d %d %d',s)
        if s and e then
          if i == fxn then
            local byp = string.sub(chunk,s,e)
            local nbyp
            if offline then
              nbyp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) return d..' '..offline..' '..f end)
            else
              nbyp = string.gsub(byp,'(%d) (%d) (%d)', function(d,e,f) if e == '0' then return d..' 1 '..f else return d..' 0 '..f end end)
            end
            if bypass then
              nbyp = string.gsub(nbyp,'(%d) (%d) (%d)', function(d,e,f) return bypass..' '..e..' '..f end)
            end
            if nbyp ~= byp then
              local nchunk = string.sub(chunk,0,s-1)..nbyp..string.sub(chunk,e+1)
              if donotsetchunk == true then
                retchunk = nchunk
              else
                SetTrackChunk(str,nchunk, false)
              end
            end
            break
          end
          s=e+1
        else
          break
        end
      end
      return retchunk
    end
  end

  function SetFXBypass(trn, fxn, forceval)
    local tr = GetTrack(trn)
    if tr then
      local pn = reaper.TrackFX_GetNumParams(tr, fxn) 
      reaper.TrackFX_SetParam(tr, fxn, pn-lvar.pn_byp, forceval)
    end
  end

  function SetFXWet(trn, fxn, forceval)
    local tr = GetTrack(trn)
    if tr then
      local pn = reaper.TrackFX_GetNumParams(tr, fxn)
      reaper.TrackFX_SetParam(tr, fxn, pn-lvar.pn_wet, forceval)
    end
  end

  function testchunkcopy(srctrn, dsttrn)

    local str = GetTrack(srctrn)
    --local dtr = GetTrack(dsttrn)

    local chunk = GetTrackChunk(str, settings_usetrackchunkfix)
    --[[DBG('')
    DBG('SOURCE')
    DBG('')]]
    --DBG(chunk)

    local ch, s, e = Chunk_GetFXChainSection(chunk)
    --[[local guids = {}
    local ch = string.gsub(chunk,'({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                           function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end DBG(d..'  '..guids[d]) return guids[d] end)
    DBG('')
    DBG('RESULT')
    DBG('')
    DBG(ch)
    DBG('')
    DBG('Total guids swapped = '..tablelength(guids))]]

    --DBG(string.match(chunk,'{.-}'))
    --DBG(string.match(chunk,'{%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x}'))

    --reaper.SetTrackStateChunk(dtr, chunk, false)

    --[[local ret, chunk = reaper.GetTrackStateChunk(dtr,'',false)
    DBG('ret: '..tostring(ret))
    DBG('DEST')
    DBG('')
    DBG(chunk)
    DBG('')
    DBG('')
    DBG(reaper.genGuid(''))
    DBG(reaper.genGuid(''))
    local guid = reaper.genGuid('')

    local p = {}
    p[guid] = reaper.genGuid('')
    DBG(guid..'  p[guid]='..p[guid])
    ]]

  end

  function Chunk_GetFXChainSection(chunk)

    -- If FXChain - return section
    -- If none - return char after MAIN SEND \n

    local s1 = string.find(chunk, '<FXCHAIN.-\n')
    if s1 then
      local s = s1
      local indent, op, cl = 1
      while indent > 0 do
        op = string.find(chunk, '\n<', s+1, true)
        cl = string.find(chunk, '\n>\n', s+1, true) + 1
        if op == nil and cl == nil then break end
        if op ~= nil then
          op = op + 1
          if op <= cl then
            indent = indent + 1
            s = op
          else
            indent = indent - 1
            s = cl
          end
        else
          indent = indent - 1
          s = cl
        end
      end

      local retch = string.sub(chunk,s1,cl)
      return retch, s1, cl
    else
      local s1, e1 = string.find(chunk, 'MAINSEND.-\n')
      return nil, s1, e1
    end
  end

  --returns new track chunk, new fxguid, old fxguid
  function Chunk_InsertFXChunkAtEndOfFXChain(trn, trchunk, insfxchunk, keepid, quickAPImode)

    guids = {}
    local ofxid, nfxid = nil, nil
    local rchunk = nil
    local rchunk2 = nil

    if keepid == nil then
      --prepare insert chunk
      if insfxchunk then
        insfxchunk = string.gsub(insfxchunk,
                                'FXID ({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                                function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end return 'FXID '..guids[d] end)
      end

      --should be just one
      for i, v in pairs(guids) do
        ofxid = i
        nfxid = v
      end
    end

    local quick
    if quickAPImode then
      local track = GetTrack(trn)
      if track then
        local fxid, plugtype = GetPlugIdentifierFromChunk(insfxchunk)
        if fxid then
          if plugtype == 'JS' then
            fxid = string.match(fxid, '.+%/(.*)') or fxid
          end
          local res = reaper.TrackFX_AddByName(track,fxid,false,-1)
          if res ~= -1 then
            local cnt = reaper.TrackFX_GetCount(track)
            local guid = reaper.TrackFX_GetFXGUID(track, cnt-1)
            nfxid = guid
            quick = true
          end
        end
      end
    end
    if not quick then
      --condition insfxchunk - Thanks Eugen
      --PROGRAMENV
      local insfxchunk2 = string.gsub(insfxchunk,"<PROGRAMENV.->\n","")
      
      if not trchunk then
        local track = GetTrack(trn)
        trchunk = GetTrackChunk(track, settings_usetrackchunkfix)
      end
      local chunk, chs, che = Chunk_GetFXChainSection(trchunk)
      if chunk then
        --insert before final character
        rchunk = string.sub(trchunk,0,che-1) .. insfxchunk .. string.sub(trchunk,che-1)
        if insfxchunk2 ~= insfxchunk then
          rchunk2 = string.sub(trchunk,0,che-1) .. insfxchunk2 .. string.sub(trchunk,che-1)
        end
      else
        if trn == -1 then
          --master track
          local ms, me = string.find(trchunk,'.+>')
          if me then
            --insert at very end
            rchunk = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,me)
            if insfxchunk2 ~= insfxchunk then
              rchunk2 = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,me)
            end
          end
        else
          --normal track -- insert after MAINSEND
          rchunk = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,che+1)
          if insfxchunk2 ~= insfxchunk then
            rchunk2 = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,che+1)
          end
        end
      end
    end
    return rchunk, nfxid, ofxid, rchunk2, quick

  end

  function Chunk_InsertFX(trn, trchunk, insfxchunk, keepid, pos)

    guids = {}
    local ofxid, nfxid = nil, nil
    local rchunk = nil
    local rchunk2 = nil

    if keepid == nil then
      --prepare insert chunk
      if insfxchunk then
        insfxchunk = string.gsub(insfxchunk,
                                'FXID ({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                                function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end return 'FXID '..guids[d] end)
      end

      --should be just one
      for i, v in pairs(guids) do
        ofxid = i
        nfxid = v
      end
    end

    --condition insfxchunk - Thanks Eugen
    --PROGRAMENV
    local insfxchunk2 = string.gsub(insfxchunk,"<PROGRAMENV.->\n","")

    local chunk, chs, che = Chunk_GetFXChainSection(trchunk)
    if chunk then
      --insert before final character
      rchunk = string.sub(trchunk,0,che-1) .. insfxchunk .. string.sub(trchunk,che-1)
      if insfxchunk2 ~= insfxchunk then
        rchunk2 = string.sub(trchunk,0,che-1) .. insfxchunk2 .. string.sub(trchunk,che-1)
      end
    else
      if trn == -1 then
        --master track
        local ms, me = string.find(trchunk,'.+>')
        if me then
          --insert at very end
          rchunk = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,me)
          if insfxchunk2 ~= insfxchunk then
            rchunk2 = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,me)
          end
        end
      else
        --normal track -- insert after MAINSEND
        rchunk = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,che+1)
        if insfxchunk2 ~= insfxchunk then
          rchunk2 = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,che+1)
        end
      end
    end
    return rchunk, nfxid, ofxid, rchunk2

  end

  function PCALL_SaveData(tmp, bak, noclean, fffn, epflag)
    local status = pcall(SaveData, tmp, bak, noclean, fffn, epflag)
    if not status then
      DBG('LBX STRIPPER: ERROR SAVING DATA')
    end
    return status    
  end

  function SaveProj(tmp, bak, noclean, epflag)

    local status
    if #strips > 0 then
      GUI_DrawMsgX(obj, gui, 'Saving Data...')
      if tmp == nil then
        local pn = GetProjectName()
        if pn == '' then
          reaper.Main_SaveProject(0,false)
          pn = GetProjectName()
        end

        if pn ~= '' then
          if lastprojname ~= pn then
            projnamechange = true
            lastprojname = pn
          end

          local t = reaper.time_precise()
          
          status = PCALL_SaveData(nil, bak, noclean)
          reaper.Main_SaveProject(0,false)
          infomsg = "DATA SAVED (" .. round(reaper.time_precise() - t,2)..'s)'
          projnamechange = false
        else
          infomsg = 'Save failed.  Project file must be created.'
          --DBG('Save failed.  Project file must be created.')
        end
      else
        local t = reaper.time_precise()
        status = PCALL_SaveData(tmp, bak, noclean, nil, epflag)
        infomsg = "DATA SAVED (" .. round(reaper.time_precise() - t,2)..'s)'
        --projnamechange = false
      end
      lupd.update_surface = true
      return status

    end
    return true
    
  end

  function GetProjectName()

    if reaper.APIExists('GetProjectName') == true then
      return reaper.GetProjectName(0,'')
    else
      return 'RPR_LBXProjID_'
    end

  end

  function StripperRunning(state)
    if state == true then
      reaper.SetProjExtState(0,'LBXFLAGS','LBX_RUNNING','*')
    else
      reaper.SetProjExtState(0,'LBXFLAGS','LBX_RUNNING','')
    end
  end

  function fquit()

    lvar.nosave = true
    --SaveSettings()
    --StripperRunning(false)
    gfx.quit()
    reaper.SetToggleCommandState(0, lvar.lbx_commid, 0)
    reaper.RefreshToolbar2(0, lvar.lbx_commid)
    reaper.SetExtState('LBXANALYZER','ANALYZERNAME','Off',false)

  end

  function quit()


    --[[local ffn = GetSaveFN()
    local srcffn = ffn
    ffn = ffn..'.lbxbak_'
    copyfile(srcffn, ffn)]]

    --[[local ffn=paths.resource_path..'aa.testdata'
    local file=io.open(ffn,"w")
    file:write('[strips]'..#strips..'\n')
    file:write('[snapshots]'..#snapshots..'\n')
    file:write('[tracks]'..#tracks..'\n')]]

    --reaper.SetExtState('ENUMPROJ','STATE',tostring(reaper.EnumProjects(0)), true)

    --check if current project exists
    --if not - signal to SaveProj to manually write necessary data into rpp file
    local enumproj = tostring(reaper.EnumProjects(0))
    local epflag
    if not enumproj then
      epflag = true
    end
    
    local status
    if lvar.nosave ~= true then
      status = SaveProj(true,nil,true,epflag)
      if not status then
        reaper.defer(run)
        return false
      end
    end
    SaveSettings()

    --[[file:write('[strips]'..#strips..'\n')
    file:write('[snapshots]'..#snapshots..'\n')
    file:write('[tracks]'..#tracks..'\n')
    file:close()]]
    if lvar.sk2overlay_active == 1 then
      SendSK2Data_Enable(0)
    end
    
    StripperRunning(false)

    gfx.quit()

    reaper.SetToggleCommandState(0, lvar.lbx_commid, 0)
    reaper.RefreshToolbar2(0, lvar.lbx_commid)
    reaper.SetExtState('LBXANALYZER','ANALYZERNAME','Off',false)

  end

  function Sleep(sec)

    os.sleep = function(sec)
       local timr = reaper.time_precise()
       repeat until reaper.time_precise() > timr + sec
    end

  end

  function Sleep2(sec)
    
    lvar.sleeptime = reaper.time_precise() + sec
    SleepAct()
    DBG('cont')
    
  end
  function SleepAct()
    if reaper.time_precise() < lvar.sleeptime then
      reaper.defer(SleepAct)
    end
  end

  function LoadFontList()

    local function trim1(s)
      return (s:gsub("^%s*(.-)%s*$", "%1"))
    end

    local ffn=paths.resource_path..'lbx_font_list.txt'
    if reaper.file_exists(ffn) ~= true then
      --DBG('Missing file: '..ffn)
      return 0
    end
    fontlist = {}

    data = {}
    local i = 1
    for line in io.lines(ffn) do
      line = trim1(line)
      if line ~= '' and line ~= ' ' and line ~= '----' and line ~= 'Name' then
        --DBG(i..' : '..line)
        fontlist[i] = line
        i=i+1
      end
    end

  end

  function UpdateFontList(x,y)

    if OS == 'Win64' or OS == 'Win32' then
      mstr = 'Update Fonts List||Help'
      gfx.x = x
      gfx.y = y
      local res = gfx.showmenu(mstr)
      if res then
        if res == 1 then
          
          local fp = string.gsub(paths.resource_path,"/","\\")..'lbx_font_list_tmp.txt'
          local fp2 = string.gsub(paths.resource_path,"/","\\")..'lbx_font_list.txt'
          local psfp = string.gsub(paths.resource_path,"/","\\")..'UpdateFontsScript.ps1'
          local txt = '[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")\n'..
                      '(New-Object System.Drawing.Text.InstalledFontCollection).Families | Out-File -FilePath '..fp..'\n'
                      ..'Get-Content '..fp..' | Set-Content -Encoding ascii '..fp2..'\n'
          
          file=io.open(psfp,"w")
          if file then
            file:write(txt)
          end
          file:close()
          local rs = 'powershell.exe '..psfp
          --run script
          reaper.ExecProcess(rs, 0)
          os.remove(fp)
          
          LoadFontList()
          
        elseif res == 2 then
          local txt = 'If the created script does not work - you may need to set your powershell script execution policy to Remote-Signed\n\n'..
                      'Open PowerShell as an administrator\n'..
                      'Run the command: Set-ExecutionPolicy RemoteSigned\n\n'..
                      'Press Y to confirm the policy change'
          DBG(txt)                      
        end
      end
      
    end
  end
  
  function OpenFontList(x,y,idx)
    
    if fontlist and #fontlist > 0 then
    
      local ddtab = {idx = idx, x = x, y = y, w = 100, h = 100, items = {}, wpad = 40, scroll = -1}

      for i = 1, #fontlist do
        ddtab.items[i] = fontlist[i]
      end

      OpenDropDown(idx, ddtab, true)
    end
    
  end

  function ChooseFontMenu(x,y)

    if fontlist and #fontlist > 0 then

      local fl = ''
      for i = 1, #fontlist do
        if fl ~= '' then
          fl = fl .. '|'
        end
        fl = fl..fontlist[i]
      end

      if x and y then
        gfx.x = x
        gfx.y = y
      end
      res = OpenMenu(fl)
      if res then
        return fontlist[res]
      end
    end

  end

  function PopMIDIOutputs()

    local midiouts = {}
    local midioutsidx = {}
    local moutnum = reaper.GetNumMIDIOutputs()
    local mcnt = 3

    midiouts[0] = {outnum = 0,
                   foutnum = 0,
                   mchan = 1,
                   name = '--- [None] ---'}

    midiouts[1] = {outnum = 0,
                    foutnum = 0,
                    mchan = 1,
                    name = 'Virtual Midi Keyboard'}
    midioutsidx['Virtual Midi Keyboard'] = 0

    midiouts[2] = {outnum = 0,
                    foutnum = 0,
                    mchan = 1,
                    name = 'Reaper Control'}
    midioutsidx['Reaper Control'] = 1

    for i = 0, moutnum do

      local retval ,moutname = reaper.GetMIDIOutputName(i,'')
      if retval == true then

        midiouts[mcnt] = {outnum = i,
                           foutnum = i+16,
                           mchan = 1,
                           name = moutname}
        midioutsidx[moutname] = i+16
        mcnt = mcnt + 1
      end

    end
    return midiouts, midioutsidx

  end

  function SendMIDIMsg(miditab, val, mu)

    --Send MIDI CC
    local hwnd
    if miditab.focus > 1 then
      if miditab.focus == 2 then
        FocusArrange()
      elseif miditab.focus == 3 then
        FocusMIDIEditor()
      elseif miditab.focus == 4 and reaper.JS_Window_Find then
        if miditab.focus_wintit then
          hwnd = reaper.JS_Window_Find(miditab.focus_wintit, miditab.focus_winexact or false)
          if hwnd then
            reaper.JS_Window_Enable(hwnd, true)
            reaper.JS_Window_SetFocus(hwnd)
            reaper.JS_Window_SetZOrder(hwnd, 'TOPMOST', hwnd)
          end
        end
      end
    end
    if miditab.onmu ~= true or mu == true then
      if (val and midioutsidx[miditab.output]) then

        if miditab.updategfx == true then
          if mu then

            local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
            ctl.val = 0
            ctl.dirty = true
            lupd.update_ctls = true
          end
          touch_trigger = false
          lvar.delayfunction.touch_timer = reaper.time_precise()+0.2
          lvar.delayfunction.midimsg = true
          midimsgto = reaper.time_precise() + 0.1
          lupd = GUI_draw(obj, gui)
          gfx.update()
        end

        local vald = math.floor((miditab.vmax - miditab.vmin)*val) + miditab.vmin
        if miditab.msgtype <= 4 then
--[[DBG(midioutsidx[miditab.output])
DBG(lvar.midimsgval_table[miditab.msgtype]..string.format('%x',miditab.mchan-1))
DBG(miditab.msg3)
DBG(vald) ]]
--DBG('sendmidi')

          reaper.StuffMIDIMessage(midioutsidx[miditab.output],
                                  lvar.midimsgval_table[miditab.msgtype]..string.format('%x',miditab.mchan-1),
                                  miditab.msg3, --CC num
                                  F_limit(vald,0,127)) -- CC val
        elseif miditab.msgtype == 5 or miditab.msgtype == 6 then
--DBG('sendmidi')

          reaper.StuffMIDIMessage(midioutsidx[miditab.output],
                                  lvar.midimsgval_table[miditab.msgtype]..string.format('%x',miditab.mchan-1),
                                  F_limit(vald,0,miditab.vmax),
                                  0) -- CC val
        elseif miditab.msgtype == 6 then
--DBG('sendmidi')

          reaper.StuffMIDIMessage(midioutsidx[miditab.output],
                                  lvar.midimsgval_table[miditab.msgtype]..string.format('%x',miditab.mchan-1),
                                  miditab.msg3, --CC num
                                  F_limit(vald,0,127)) -- CC val
        elseif miditab.msgtype == 7 then
--DBG('sendmidi')

          local v1 = math.floor(vald / 128)
          local v2 = vald % 128
          reaper.StuffMIDIMessage(midioutsidx[miditab.output],
                                  lvar.midimsgval_table[miditab.msgtype]..string.format('%x',miditab.mchan-1),
                                  v2,
                                  v1)
        end

        if miditab.osc then
          local msg = string.gsub(miditab.osc, '%[val%]', vald)

          reaper.OscLocalMessageToHost(msg)
        end

        lvar.delayfunction.midimsg = true
        midimsgto = reaper.time_precise() + 0.1

      elseif miditab.osc then
        local vald = 0
        if val then
          vald = math.floor((miditab.vmax - miditab.vmin)*val) + miditab.vmin
        end

        if miditab.osc then
          local msg = string.gsub(miditab.osc, '%[val%]', vald)

          reaper.OscLocalMessageToHost(msg)
        end

        lvar.delayfunction.midimsg = true
        midimsgto = reaper.time_precise() + 0.1
      end
    else
      mu_mmsg = {midiout = miditab, val = val}
      mididelay = reaper.time_precise() +0.05
      midi1st = true

      if miditab.updategfx == true then
        --local ctl = strips[tracks[track_select].strip][page].controls[trackfxparam_select]
        --ctl.val = 1
        --ctl.dirty = true
        lupd = GUI_draw(obj, gui)
        gfx.update()
      end

    end

  end

  function FocusArrange()
    reaper.Main_OnCommand(reaper.NamedCommandLookup('_BR_FOCUS_ARRANGE_WND'),0)
  end
  function FocusMIDIEditor()
    reaper.Main_OnCommand(reaper.NamedCommandLookup('_SN_FOCUS_MIDI_EDITOR'),0)
  end

  function LoadScanBoot(fn)

    local file
    file=io.open(fn,"r")
    if file then
      content=file:read("*a")
      file:close()

      neb_scanboot_tab = {}
      neb_scanboot_fn = {}

      if content then
        for progid, filen in string.gmatch(content, "<SEQUENCE> (.-) </SEQUENCE>.-<FILENAME> (.-) </FILENAME>") do
          neb_scanboot_tab[progid+200] = filen
          neb_scanboot_fn[filen] = tonumber(progid+200)
        end
      end
    end

  end

  function RCM_Neb_UpdateAllProgIDs()

    if strips and #strips > 0 then
      local str = ''
      for s = 1, #strips do
        for p = 1, lvar.maxpage do

          if strips[s] and strips[s][p] then
            str = str .. RCM_Neb_UpdateProgIDs(strips[s][p].controls, false) ..'\n'
          end

        end
      end

      DBG(str)
    end

  end

  function RCM_Neb_UpdateProgIDs(ctls, verbose)

    if neb_scanboot_fn and ctls then

      local upd = 0
      local fail = 0

      for i = 1, #ctls do
        local ctl = ctls[i]
        if ctl.ctlcat == ctlcats.rcm_switch then

          if ctl.rcmdata and #ctl.rcmdata > 0 then

            for j = 1, #ctl.rcmdata do

              if ctl.rcmdata[j].nebfn and neb_scanboot_fn[ctl.rcmdata[j].nebfn] then

                local nprog = neb_scanboot_fn[ctl.rcmdata[j].nebfn]
                if nprog then

                  local msb = F_limit(tonumber(math.floor(math.floor(nprog/100) / 128)),0,127)
                  local lsb = F_limit(tonumber(math.floor(nprog/100) % 128),0,127)
                  local prog = F_limit(tonumber(nprog % 100),0,127)

                  ctl.rcmdata[j].msb = msb
                  ctl.rcmdata[j].lsb = lsb
                  ctl.rcmdata[j].prog = prog

                  upd = upd + 1
                end

              else
                if ctl.rcmdata[j].nebfn then
                  fail = fail + 1
                end
              end

            end

          end

        end
      end

      local str = 'Neb IDs updated: '..upd..'\n\nNeb IDs not updated: '..fail
      if nz(verbose,true) == true then
        OpenMsgBox(1, str, 1)
      end
      return str
    end

  end

  function tablecopytest()

    local rt = reaper.time_precise()
    local t = {}
    for i = 1, 32 do
      t = table.deepcopy(modulators[1])
    end
    local ft = reaper.time_precise()
    DBG(string.format("%0f",ft-rt))

    --[[for i = 1, #t.data do

      DBG(t.data[i])

    end
    for i = 1, #t.targets do
      DBG(t.targets[i].ctl)
    end]]

  end

  function CP4_SetUp()
    lvar.CP4Funcs[ctlcats.navictl] = {click = CP4_NaviCtl,
                                      draw = CP4_Draw_NaviCtl}
    lvar.CP4Funcs[ctlcats.action] = {click = CP4_Action,
                                      draw = CP4_Draw_Action}
    lvar.CP4Funcs[ctlcats.infoctl] = {click = CP4_InfoCtl,
                                      draw = CP4_Draw_InfoCtl}
  end

  function CheckReqs()

    local app = '5.974'
    local sws = '2.10.0.1'
    local js = '0.961'
    local err
    
    local imageappdev = '6.13+dev0809a'
    local deltaappdev = '6.36+dev0924'
    
    --DBG(reaper.GetAppVersion())
    local appstr = (string.match(reaper.GetAppVersion(),'(.+)[/]') or reaper.GetAppVersion())
    if appstr < app then
      DBG('Stripper version '..lvar.scriptver..' requires Reaper version '..app..' or later')
      err = true
    end

    if appstr >= imageappdev then
      lvar.largeimages = true
      lvar.maxdim = 8192
    end

    if appstr < deltaappdev then
      --if pre delta version - adjust byp/wet parameter offset values
      lvar.offline_paramcnt = 2
      lvar.pn_byp = 2
      lvar.pn_wet = 1
      lvar.pn_delta = 0
    end

    if reaper.APIExists('CF_GetSWSVersion') then
      local buf = reaper.CF_GetSWSVersion('')
      --DBGByte(string.gsub(reaper.CF_GetSWSVersion(''),'%.',''))
      local buf2 = string.gsub(buf,'%.','')
      if (tonumber(buf2) or -1) < tonumber(string.gsub(sws,'%.','')) then
        DBG('Stripper version '..lvar.scriptver..' requires SWS version '..sws..' or later')
        err = true
      else
        DBGOut('SWS OK')
      end
    else
      DBG('Stripper version '..lvar.scriptver..' requires SWS version '..sws..' or later')
      err = true
    end

    if reaper.APIExists('JS_ReaScriptAPI_Version') then
      local ver = reaper.JS_ReaScriptAPI_Version()
      --DBG(ver)
      if ver < tonumber(js) then
        DBG('Stripper version '..lvar.scriptver..' requires JS_ReascriptAPI version '..js..' or later')
        err = true
      else
        DBGOut('JS API OK')
      end
    else
      DBG('Stripper version '..lvar.scriptver..' requires JS_ReascriptAPI version '..js..' or later')
      err = true
    end

    if err then
      DBG('Running incorrect versions may result in crashes when performing certain functions, or functions not working.')
    end
  end

  function SetPaths()
  
    local altrespath = GES('lbx_alternative_resources_path',true)
    
    paths.resource_path = altrespath or reaper.GetResourcePath().."/Scripts/LBX/LBXCS_resources/"
    paths.controls_path = paths.resource_path.."controls/"
    paths.graphics_path = paths.resource_path.."graphics/"
    paths.actiondump_path = paths.resource_path.."actiondumps/"
    paths.icon_path = paths.resource_path.."icons/"
    paths.strips_path = paths.resource_path.."strips/"
    paths.templates_folder = "LBX_TEMPLATES"
    paths.dmstrip_folder = "LBX_DMSTRIPS"
    paths.ttstrip_folder = "LBX_TTSTRIPS"
    paths.sets_path = paths.resource_path.."sets/"
    paths.projsave_path = paths.resource_path.."projsave/"
    paths.paths_path = paths.resource_path.."paths/"
    paths.eqbands_path = paths.resource_path.."eqbands/"
    paths.eq_path = paths.resource_path.."eq/"
    paths.skins_path = paths.resource_path.."skins/"
    paths.share_path = paths.resource_path.."share/"
    paths.mod_path = paths.resource_path.."modpresets/"
    paths.update_path = paths.resource_path.."updater/"
  
    file_settings = paths.resource_path..'settings.txt'
    file_bgimage = paths.resource_path..'bg.jpg'
    
    lvar.tranimg =  paths.resource_path..'transparent_4096.png'
    
    
  end

  function CheckOversizeImage()
  
    lvar.enablelargegui = tobool(nz(GES('enablelargegui',true),lvar.enablelargegui))

    if (not lvar.largeimages and not reaper.file_exists(lvar.tranimg)) or not lvar.enablelargegui then
      lvar.maxdim = 2048
      force_resize = true
      lvar.missingTI = true
    end
  
  end
  
  function guivis(idx)
    
    local full_screen = snap_edit_mode or macro_edit_mode or show_pinmatrix or show_eqcontrol
    local lrn_mode = snaplrn_mode or macro_lrn_mode
    
    if idx == 43 then
      if plist_w > 0 then 
        return true 
      end
    elseif idx == 100000 then --topbar
      if topbarheight > 0 and hide_topbar == false then 
        return true 
      end
    elseif idx == 100001 and not full_screen and not lrn_mode then --MMOV
      if lvar.mmov_show then
        return true
      end
    elseif idx == 100002 then --dropdown
      if show_dd then
        return true
      end
    
    elseif idx == 4999 and not full_screen and not lrn_mode  then --trbtns
      if lvar.trbtns_show then
        return true
      end
    elseif idx == 5024 and not full_screen and not lrn_mode  then --trmix
      if lvar.trbtns_show and lvar.trmix_show then
        return true
      end

    elseif idx == 1350 and not full_screen and not lrn_mode then --SB
      if show_stripbrowser then
        return true
      end
    elseif idx == 1300 and not full_screen and not lrn_mode then --SB
      if show_samplemanager then
        return true
      end
    elseif idx == 160 and not full_screen then --Snapshots
      if show_snapshots then
        return true
      end
    elseif idx == 180 and not full_screen and not lrn_mode then --fSnapshots
      if show_fsnapshots or show_xysnapshots then
        return true
      end
    elseif idx == 1100 and not full_screen and not lrn_mode then --Modulators
      if show_lfoedit then
        return true
      end
    elseif idx == 900 and not full_screen and not lrn_mode then --TFXOrder
      if show_trackfxorder then
        return true
      end
    elseif idx == 950 then --midi out
      if show_midiout and not full_screen and not lrn_mode then
        return true
      end
    elseif idx == 1120 and not full_screen and not lrn_mode then --mutate
      if show_mutate then
        return true
      end
    elseif idx == 1130 and not full_screen and not lrn_mode then --random
      if show_randomopts then
        return true
      end

    elseif idx == 5050 and not full_screen and not lrn_mode then --template chooser
      if lvar.show_templatechooser then
        return true
      end
      
    elseif idx == 4000 and not full_screen and not lrn_mode then --addstripdialog
      if lvar.show_addstripdialog then
        return true
      end
      
    elseif idx == 70 and not full_screen and not lrn_mode then --Settings
      if show_settings then
        return true
      end
    
    elseif idx == 1125 then --mod assign
      if show_modass then
        return true
      end

    elseif idx == 300 then --snap edit
      if snap_edit_mode or macro_edit_mode or show_eqcontrol then
        return true
      end

    elseif idx == 1200 then --pinmatrix
      if show_pinmatrix then
        return true
      end
    end

  --EM local show_cycleoptions   
  --EM local show_paramlearn
  --local show_snapshots
  --* local show_fsnapshots
  --EM local show_actionchooser
  --* local show_xxy
  --EM local show_gaugeedit
  --local show_trackfxorder
  --local show_midiout
  --local show_dd
  --local show_lfoedit
  --** local show_eqcontrol
  --** local show_pinmatrix

    return false
  end
  
  function SetGUIBitmap()
    Img_SetDim(guibitmap, gfx1.main_w, gfx1.main_h)
  end
    
  function RedrawGUIBitmap2()
  --DBG('X')
    lvar.redrawguibitmap = false
    local t = reaper.time_precise()
    
    local tab
    if mode == 0 then      
      --if lvar.livemode == 2 then
        --bottom to top --add wheel functions
        tab = {}
        tab[#tab+1] = {obj = 10, visible = true, func0 = A_Click_M0_StripSurface, wheel0 = A_Click_M0_StripSurface} 
        tab[#tab+1] = {obj = 43, visible = guivis(43), funcRun = A_Click_M0_Sidebar, wheel0 = A_Wheel_M0_Sidebar} --sidebar
        tab[#tab+1] = {obj = 100000, visible = guivis(100000), funcRun = A_Click_M0_TopBar} --topbar
        if lvar.livemode == 2 then
          tab[#tab+1] = {obj = 4999, visible = guivis(4999), func0 = A_Click_M0_TrBtns, wheel0 = A_Wheel_M0_TrBtns} --trbtns
          tab[#tab+1] = {obj = 5024, visible = guivis(5024), func0 = A_Click_M0_TrMix, wheel0 = A_Wheel_M0_TrMix} --trmix
        end
        if settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        if settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, func0_lrn = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if settings_sbdock and not lvar.stripbrowser.fullscreen then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 180, visible = guivis(180), func0 = A_Click_M0_fSnapshot, wheel0 = A_Wheel_M0_fSnapshot} --fsnaps
        if not settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if not settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        tab[#tab+1] = {obj = 1120, visible = guivis(1120), func0 = A_Click_M0_Mutate} --mutate
        tab[#tab+1] = {obj = 1130, visible = guivis(1130), func0 = A_Click_M0_Random} --random
        tab[#tab+1] = {obj = 1300, visible = guivis(1300), func0 = A_Click_M0_SampleManager, wheel0 = A_Wheel_M0_SampleManager} --sample win        
        if not settings_sbdock or lvar.stripbrowser.fullscreen then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 950, visible = guivis(950), funcRun = A_Click_M0_MidiOut} --midiout
        tab[#tab+1] = {obj = 4000, visible = guivis(4000), wheel0 = A_Wheel_M0_AddStripDialog} --addstripdialog
        
        tab[#tab+1] = {obj = 900, visible = guivis(900), funcRun = A_Click_M0_TFXOrder} --tfxorder
        tab[#tab+1] = {obj = 5050, visible = guivis(5050), wheel0 = A_Wheel_M0_TemplateChooser} --template chooser

        tab[#tab+1] = {obj = 70, visible = guivis(70), funcRun = A_Click_M0_Settings} --70 = settings                
                
        tab[#tab+1] = {obj = 1125, visible = guivis(1125), wheel0 = A_Wheel_M0_ModAss} --modass

        tab[#tab+1] = {obj = 300, visible = guivis(300), func0 = A_Click_M0_Fullscreen1, wheel0 = A_Wheel_M0_Fullscreen1} --snap edit / macro edit                
        tab[#tab+1] = {obj = 1200, visible = guivis(1200), func0 = A_Click_M0_Fullscreen2, wheel0 = A_Wheel_M0_Fullscreen2} --pinmap                
                
        tab[#tab+1] = {obj = 100002, visible = guivis(100002), funcRun = A_Click_M0_Dropdown} --Dropdown
        
                
      --[[elseif lvar.livemode == 1 then
        tab = {}
        tab[#tab+1] = {obj = 10, visible = true, func0 = A_Click_M0_StripSurface, wheel0 = A_Wheel_M0_StripSurface} 
        tab[#tab+1] = {obj = 43, visible = guivis(43), funcRun = A_Click_M0_Sidebar, wheel0 = A_Wheel_M0_Sidebar} --sidebar
        tab[#tab+1] = {obj = 100000, visible = guivis(100000), funcRun = A_Click_M0_TopBar} --topbar
        if settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        if settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if settings_sbdock then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 180, visible = guivis(180), func0 = A_Click_M0_fSnapshot, wheel0 = A_Wheel_M0_fSnapshot} --fsnaps
        if not settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if not settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        tab[#tab+1] = {obj = 1120, visible = guivis(1120), func0 = A_Click_M0_Mutate} --mutate
        tab[#tab+1] = {obj = 1130, visible = guivis(1130), func0 = A_Click_M0_Random} --random
        tab[#tab+1] = {obj = 1300, visible = guivis(1300), func0 = A_Click_M0_SampleManager, wheel0 = A_Wheel_M0_SampleManager} --sample win        
        if not settings_sbdock then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 950, visible = guivis(950), funcRun = A_Click_M0_MidiOut} --midiout
        tab[#tab+1] = {obj = 4000, visible = guivis(4000), wheel0 = A_Wheel_M0_AddStripDialog} --addstripdialog
        
        tab[#tab+1] = {obj = 900, visible = guivis(900), funcRun = A_Click_M0_TFXOrder} --tfxorder
        tab[#tab+1] = {obj = 5050, visible = guivis(5050), wheel0 = A_Wheel_M0_TemplateChooser} --template chooser

        tab[#tab+1] = {obj = 70, visible = guivis(70), funcRun = A_Click_M0_Settings} --70 = settings        

        tab[#tab+1] = {obj = 300, visible = guivis(300), func0 = A_Click_M0_Fullscreen1} --snap edit

        tab[#tab+1] = {obj = 100002, visible = guivis(100002), funcRun = A_Click_M0_Dropdown} --Dropdown


      elseif lvar.livemode == 0 then
        tab = {}
        tab[#tab+1] = {obj = 10, visible = true, func0 = A_Click_M0_StripSurface, wheel0 = A_Wheel_M0_StripSurface} 
        tab[#tab+1] = {obj = 43, visible = guivis(43), funcRun = A_Click_M0_Sidebar, wheel0 = A_Wheel_M0_Sidebar} --sidebar
        tab[#tab+1] = {obj = 100000, visible = guivis(100000), funcRun = A_Click_M0_TopBar} --topbar
        if settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        if settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if settings_sbdock then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 180, visible = guivis(180), func0 = A_Click_M0_fSnapshot, wheel0 = A_Wheel_M0_fSnapshot} --fsnaps
        if not settings_ssdock then
          tab[#tab+1] = {obj = 160, visible = guivis(160), func0 = A_Click_M0_Snapshot, wheel0 = A_Wheel_M0_Snapshot} --snapshot
        end
        if not settings_moddock then
          tab[#tab+1] = {obj = 1100, visible = guivis(1100), func0 = A_Click_M0_Modulators} --modulators
        end
        tab[#tab+1] = {obj = 1120, visible = guivis(1120), func0 = A_Click_M0_Mutate} --mutate
        tab[#tab+1] = {obj = 1130, visible = guivis(1130), func0 = A_Click_M0_Random} --random
        tab[#tab+1] = {obj = 1300, visible = guivis(1300), func0 = A_Click_M0_SampleManager, wheel0 = A_Wheel_M0_SampleManager} --sample win        
        if not settings_sbdock then
          tab[#tab+1] = {obj = 1350, visible = guivis(1350), func0 = A_Click_M0_StripBrowser, wheel0 = A_Wheel_M0_StripBrowser} --Strip browser
        end
        tab[#tab+1] = {obj = 950, visible = guivis(950), funcRun = A_Click_M0_MidiOut} --midiout
        tab[#tab+1] = {obj = 4000, visible = guivis(4000), wheel0 = A_Wheel_M0_AddStripDialog} --addstripdialog
        
        tab[#tab+1] = {obj = 900, visible = guivis(900), funcRun = A_Click_M0_TFXOrder} --tfxorder
        tab[#tab+1] = {obj = 5050, visible = guivis(5050), wheel0 = A_Wheel_M0_TemplateChooser} --template chooser

        tab[#tab+1] = {obj = 70, visible = guivis(70), funcRun = A_Click_M0_Settings} --70 = settings        
        tab[#tab+1] = {obj = 100002, visible = guivis(100002), funcRun = A_Click_M0_Dropdown} --Dropdown


      end]]
    end
    
    gfx.dest = guibitmap
    SetGUIBitmap()
    
    if tab then
      --DBG('CREATING GUI BMP & IDX TABLE')
      tab.idx = {}
      for i = 1, #tab do
  
        if tab[i].visible then
          tab.idx[tab[i].obj] = i
          --DBG('adding idx: '..tab[i].obj)
          
          local objn = tab[i].obj
          if objn < 100000 then
          
            
            local o = obj.sections[objn]
            local r = objn & 255
            local g = (objn >> 8) & 255
            local b = (objn >> 16) & 255
            gfx.r, gfx.g, gfx.b = r/255,g/255,b/255
            gfx.a = 1
            gfx.rect(o.x,o.y,o.w,o.h,1)
            --DBG(objn..'  '..r..'  '..g..'  '..b)
            
          else
            local o
            if objn == 100000 then
              o = {x = plist_w, y = 0, w = gfx1.main_w - plist_w, h = topbarheight}
              
            elseif objn == 100001 then
              local sz = 2*lvar.mmov_pad + lvar.mmov_vsize
              if lvar.mixmodedir == 0 then
                o = {x = obj.sections[10].x, y = obj.sections[10].y, w = sz, h = obj.sections[10].h}              
              else
                o = {x = obj.sections[10].x, y = obj.sections[10].y, w = obj.sections[10].w, h = sz}
              end
  
            elseif objn == 100002 then
              o = {x = ddlist.x, y = ddlist.y, w = ddlist.w, h = ddlist.h}
            
            end
    
            if o then
              local r = objn & 255
              local g = (objn >> 8) & 255
              local b = (objn >> 16) & 255
              gfx.r, gfx.g, gfx.b = r/255,g/255,b/255
              gfx.a = 1
              gfx.rect(o.x,o.y,o.w,o.h,1)
            end
          end
        end
            
      end
    end
    
    local full_screen = snap_edit_mode or macro_edit_mode or show_pinmatrix or show_eqcontrol
    if xPnl and not full_screen and mode == 0 then
    
      for i = 1, #xPnlIdx do
        if xPnlIdx[i].visible == true then
          local objn = lvar.xPnlOffset + i
          local o = xPnlIdx[i]
          local r = objn & 255
          local g = (objn >> 8) & 255
          local b = (objn >> 16) & 255
          gfx.r, gfx.g, gfx.b = r/255,g/255,b/255
          gfx.a = 1
          if o.clickthrough then
            if o.clickthrough == 1 then
              local thh = math.ceil(gui.winsz.pnltit*pnl_scale)
              gfx.rect(o.x,o.y,o.w,thh,1)
            elseif o.clickthrough == 2 then
              --draw nothing - cannot be clicked on at all
            end
          else
            gfx.rect(o.x,o.y,o.w,o.h,1)
          end
        end
      end
    
    end
        
    lvar.guibmp = tab
  
    --DBG(reaper.time_precise()-t)
  end
  
  ------------------------------------------------------------

  math.randomseed(os.clock())

  ZeroProjectFlags()
  StripperRunning(true)
  Sleep()

  for f = 0,4 do
    fact[f] = cfact(f)
  end

  --font_folder = "C:/Windows/Fonts/"

  SetPaths()

  LoadFontList()
  Load_PlugDefs()
  --copyfile('C:/Users/HMSStudio/AppData/Roaming/REAPER/Scripts/LBX/LBXCS_resources/controls/__default.png', 'C:/Users/HMSStudio/AppData/Roaming/REAPER/Scripts/LBX/LBXCS_resources/controls/cpcpcpcpcpc.png')

  reaper.RecursiveCreateDirectory(paths.sets_path,1)
  reaper.RecursiveCreateDirectory(paths.icon_path,1)
  reaper.RecursiveCreateDirectory(paths.actiondump_path,1)
  reaper.RecursiveCreateDirectory(paths.projsave_path,1)
  reaper.RecursiveCreateDirectory(paths.paths_path,1)
  reaper.RecursiveCreateDirectory(paths.eqbands_path,1)
  reaper.RecursiveCreateDirectory(paths.eq_path,1)
  reaper.RecursiveCreateDirectory(paths.share_path,1)
  reaper.RecursiveCreateDirectory(paths.mod_path,1)

  reaper.RecursiveCreateDirectory(paths.strips_path..'/'..paths.templates_folder,1)
  reaper.RecursiveCreateDirectory(paths.strips_path..'/'..paths.dmstrip_folder,1)
  reaper.RecursiveCreateDirectory(paths.strips_path..'/'..paths.ttstrip_folder,1)

  midiouts, midioutsidx = PopMIDIOutputs()

  LBX_CTL_TRNAME='__LBX_CTL'
  LBX_GTRACK_NAME = '__GLOBAL'
  LBX_GTRACK = nil

  REMSCRIPT='LBX_SK2_REMOTE'
  
  lvar.EXTMSG, lvar.EXTMSGKEY = 'LBXStripper_ExternalControl', 'ExtMsgStream'
  
  lvar.lbx_commid = ({reaper.get_action_context()})[4]
  reaper.SetToggleCommandState(0, lvar.lbx_commid, 1)
  reaper.RefreshToolbar2(0, lvar.lbx_commid)

  CheckReqs()

  settings_savedatainprojectfolder = true
  settings_followselectedtrack = false
  settings_autocentrectls = false
  settings_disablesendchecks = false
  settings_gridsize = 16
  settings_showgrid = true
  osg = settings_showgrid
  settings_saveallfxinststrip = true
  settings_updatefreq = 0.05
  settings_updatefreq_pkmeter = 0.05
  settings_showbars = false
  settings_mousewheelknob = true
  settings_locksurface = false
  settings_ExtendedAPI = reaper.APIExists('BR_GetMediaTrackSendInfo_Track')
  settings_swapctrlclick = false
  settings_insertdefaultoneverytrack = false
  settings_insertdefaultoneverypage = false
  settings_hideofflinelabel = true
  settings_showparamnamelabelwhenoffline = true
  settings_snaplistbgcol = '0 0 0'
  settings_defknobsens = {norm = 2,
                          fine = 0.1,
                          wheel = 0.05,
                          wheelfine = 0.003,
                          m_norm = 1,
                          m_fine = 1,
                          m_wheel = 1,
                          m_wheelfine = 1}
  settings_usectlbitmap = true
  settings_macroeditmonitor = false
  hide_topbar = false
  settings_hideeditbaronnewproject = false
  settings_locksurfaceonnewproject = false
  setting_reddotindicator = false
  settings_showminimaltopbar = true
  settings_createbackuponmanualsave = true
  settings_UCV = 1
  settings_touchmode = false
  settings_touchFB = false
  settings_trackchangemidi = false
  settings_savefaderboxassinsnapshots = false
  settings_savemodsinsnapshots = false
  settings_showfaderassignments = false
  settings_stripautosnap = false
  settings_disablekeysonlockedsurface = false
  settings_deletefxwithstrip = true
  settings_morphfaderassignedctls = true
  settings_followsnapshot = true
  settings_disablefaderautomationineditmode = true
  settings_alwaysrunmods = false
  settings_usetrackchunkfix = true
  settings_showmorphpop = false
  settings_groupsel = false
  settings_savesnapafterselected = false
  settings_drawbglabelsontop = true
  settings_pagescrolldir = 1
  settings_ssdock = false
  settings_moddock = false
  settings_sbdock = true
  settings_dragmode = false
  settings_runstartbat = false
  settings_lockpinmatrix = false
  settings_backupduringsave = true
  settings_hideplugnotfound = false
  settings_enablednu = true

  lvar.easings = {}
  lvar.easings[2] = inSine
  lvar.easings[3] = outSine
  lvar.easings[4] = inOutSine
  lvar.easings[5] = inCubic
  lvar.easings[6] = outCubic
  lvar.easings[7] = inOutCubic
  lvar.easings[8] = inQuart
  lvar.easings[9] = outQuart
  lvar.easings[10] = inOutQuart
  lvar.easings[11] = easeRet1  
  lvar.easingsInv = {}
  lvar.easingsInv[2] = inSineInv
  lvar.easingsInv[3] = outSineInv
  lvar.easingsInv[4] = inOutSineInv
  lvar.easingsInv[5] = inCubicInv
  lvar.easingsInv[6] = outCubicInv
  lvar.easingsInv[7] = inOutCubicInv
  lvar.easingsInv[8] = inQuartInv
  lvar.easingsInv[9] = outQuartInv
  lvar.easingsInv[10] = inOutQuartInv
  lvar.easingsInv[11] = easeRet1

  hideunusedtracks = false
  logflag = false

  tb_butt_h = 20
  fontscale = 8
  tb_fontscale = 0
  lst_fontscale = 0

  settingswin_off = 0
  
  takeswitch_max = 512

  autosnap_rowheight = 410
  autosnap_itemgap = 20
  autosnap_itemgapmax = 20
  stripgallery_view = 0
  gallery_itemgap = 20

  show_striplayout = false
  striplayout_mtime = 0.1

  modulator_cnt = 32

  textoptlink_select = true

  show_midioutind = true

  save_subfolder = ''

  backalpha = 1
  backalpha2 = 0
  backcol = '16 16 16'
  backcol2 = backcol

  faderhighcol = '160 64 255'
  faderselcol = '255 160 255'

  modhighcol = '64 160 255'
  modselcol = '160 255 255'

  modwin = {minw = 536, minh = 180}
  smwin = {w = 500, h = 500}
  sbwin = {w = 180, h = 1000}

  barcol = '64 0 0'

  eq_scale = true
  eq_single = false

  strip_favs = {}
  strip_favs_n = {}
  strip_search = {}
  peak_info = {}

  dockstate = 0

  EQC_min = 20
  EQC_max = 24000

  fontname_def = 'Calibri'
  fontsize_def  = 18

  def_fx_h = 160
  def_gx_h = 160
  def_sf_h = 140
  fx_h = def_fx_h
  gx_h = def_gx_h
  sf_h = def_sf_h

  CheckOversizeImage()
  
  lvar.updateravailable, lvar.git, lvar.gitclone = CheckUpdater()
  SetDefKP()
  --SaveDefKP()

  SettingsInfoSetup()
  SetUp_UCV_Functions()

  local surfn = paths.icon_path..'canvas.png'
  if reaper.file_exists(surfn) then
    gfx.loadimg(strip_image,surfn)
    local w,h = gfx.getimgdim(strip_image)
    surface_size = {w = w, h = h, limit = true}
  else
    surface_size = {w = lvar.maxdim, h = lvar.maxdim, limit = true}
  end

  gfx.loadimg(0,paths.controls_path.."__default.png") -- default control
  --gfx.loadimg(1010,paths.controls_path.."__default.png")

  --def_knob = 0
  gfx.loadimg(1021,paths.icon_path.."bin.png")

  defctls = {}

  --[[ttest = {}
  ttest[1] = {ctl = 3}
  ttest[2] = {ctl = 1}
  ttest[3] = {ctl = 5}
  ttest = table_slowsort_gen(ttest,'ctl')
  for i = 1, #ttest do
    DBG(ttest[i].ctl)
  end]]
--DBG(GetPlugNameFromChunk3('<JS "Tube Input" ""\n'))
--DBG(GetPlugNameFromChunk3('JS Tunca_LBX/TubeInput sdf\n'))
  --Table_Test()

  gfx.loadimg(1020,paths.controls_path.."LBX_Invisible.png") --update to missing png
  def_knob = LoadControl(1019, '__default.knb')
  def_knobsm = LoadControl(1018, 'SimpleFlat_48.knb')
  def_snapshot = LoadControl(1017, '__Snapshot.knb')
  def_xy = LoadControl(1016, '__XY.knb')
  def_xytarget = LoadControl(1015, '__XYTarget.knb')
  def_eqcknobf = LoadControl(1013, 'SimpleFlat_64.knb')
  def_eqcknobg = LoadControl(1014, 'SimpleFlat2_64.knb')
  def_box = LoadControl(1012, 'SimpleBox_9632.knb')
  def_switch = LoadControl(997, 'Switcher.knb')
  ctl_bitmap = ctlbitmap_image
  ctl_bitmap2 = 994

  --testact()
  CP4_SetUp()

  DBGOut(OS)
  LoadScreenSets()
  
  --[[local ssv = 0.86665
  local ss = inOutQuart(ssv)
  DBG(ss..'  '..ssv..'  '..inOutQuartInv(ss))]]
  --[[local ssv = 0.5
  local ss = inOutCubic(ssv)
  DBG(ss..'  '..old_inOutCubic(ssv))]]

  --[[DBGOut('Boolean test true: '..tostring(tobool("true")))
  DBGOut('Boolean test true: '..tostring(tobool('true')))
  DBGOut('Boolean test true: '..tostring(tobool(' true')))
  DBGOut('Boolean test nil: '..tostring(tobool(nil)))
  DBGOut('Boolean test "": '..tostring(tobool("")))
  DBGOut('Boolean test false: '..tostring(tobool("false")))
  DBGOut('Boolean test false: '..tostring(tobool('false')))]]

  --DBG(GetNewLogFN())
  --DBG(GetPlugIdentifierFromChunk('BYPASS 0 0 0\n<VST "VST: dpMeter2 (TBProAudio) (6ch)" "dpMeter2 x64.dll" 0 "" 1413632067\n'))

  --os.execute('E:\\AutoHotkey\\SRD_Home_TouchScreen.ahk')
  --TestStuff()
  --testchunkcopy(0,3)
--testfxinsert()


  if def_knob == -1 or def_knobsm == -1 or def_snapshot == -1 or def_xy == -1 or def_xytarget == -1 or def_eqcknobf == -1 or def_eqcknobg == -1 or def_box == -1 or def_switch == -1 then
    DBG("Please ensure you have the: \n\n__default\nSimpleFlat_48\nSimpleFlat_96\nSimpleFlat2_96\n__Snapshot\n__XY\n__XYTarget\nSimpleBox_9632\nSwitcher\n\nfiles in your LBXCS_resources/controls/ folder.")
    DBG("You can get these files from the LBX Stripper project on github - in the LBXCS_resources zip file")
    DBG("")
    DBG("Expected location of LBXCS_resources folder is: "..string.gsub(paths.resource_path,"\\","/"))
    reaper.atexit()
  elseif ret == false then
    reaper.atexit()
  else
    def_snapshotctl = -1

    --DBG(_G['testfunc']('testtext'))
    local setdata = LoadSettings_PreInit()
    INIT()

    gui = GetGUI_vars()
    def_graph = EQC_LoadGraph()

    LoadSettings(setdata)
    setdata = nil
    
    skin, ret = LoadSkin()

    LoadBGImage(file_bgimage)

    if reaper.JS_Mouse_LoadCursorFromFile then
      lvar.cursor_invisible = reaper.JS_Mouse_LoadCursorFromFile(paths.icon_path..'invisible.cur')
      if not lvar.cursor_invisible or not reaper.JS_Mouse_SetPosition then
        lvar.hidecursordrag = false
      end
    end

    LoadData()
    CleanData()
    --ActionCommandID_Repair()
    --GetTrackFXInfo()
    --GetStripFXInfo()
    --DBG(#switchers)

    XpnlLoadInfo()
    --InitXPnls()
    --ShowXPnl('HUD')

    if nebscanboot_file ~= nil then
      LoadScanBoot(nebscanboot_file)
    end

    lvar.ctlbrowserfavs = CB_LoadFavs()

    gfx.dock(dockstate)
  --test jsfx plug name in quotes

    if settings_runstartbat == true then
      local startbat = paths.resource_path..'\\lbxstart.bat'
      if reaper.file_exists(startbat) then
        os.execute(startbat)
      end
    end

  --reaper.SetCurrentBPM(0, 130, false)
  --local bpm, _ = reaper.GetProjectTimeSignature2(0)
  --DBG(bpm)
  --[[local content = '[TRACK]-1\nsdfsdfsdf\n[\\TRACK]\n[TRACK]0\nsdffsdfhguheargrnasff\n[\\TRACK]'
  DBG(content)
  local t = -1
  local data = string.match(content,'(%[TRACK%]'..t..'.-%[\\TRACK%])')
  DBG(data)]]

  --[[local tst = '[STRIPSET_VERSION]22\n[TRACKS]125\n[dfsgsdfgfsdfgsfhwtwt]'
  --local tst = 'dfgd\nsdfsggsh\n[dfsgsdfgfsdfgsfhwtwt]'
  local header = string.match(tst,'(.-\n.-\n)')
  local version, trcnt = string.match(header,'%[.-%](%d+)\n%[.-%](%d+)\n')
  DBG(header)
  DBG(tostring(version)..'  '..tostring(trcnt))]]
    LoadLocation()
    LoadTrackStrips()
    SK2LoadSlots()
    
    if sg_view then
      stripgallery_view = 0
      if stripgallery_view > 0 then
        obj = GetObjects()
        stlay_data = AutoSnap_GetStripLocs(true)
      end
      sg_view = nil
    end

    --ctls_dirty = {idx = {}, update = {}}

    --tablecopytest()

    run()

    reaper.atexit(quit)
  end


