changeset 33:e6650821a2c0

Debugging pass on console code.
author Nenue
date Sun, 27 Dec 2015 02:30:46 -0500
parents c6a2c2df4790
children 7441f3bce940
files Devian.lua Devian.xml Dock.lua
diffstat 3 files changed, 314 insertions(+), 306 deletions(-) [+]
line wrap: on
line diff
--- a/Devian.lua	Sat Dec 26 21:51:57 2015 -0500
+++ b/Devian.lua	Sun Dec 27 02:30:46 2015 -0500
@@ -11,33 +11,38 @@
 local WORKSPACE_ON, WORKSPACE_OFF = 1, 2
 local PLAYER_REALM = UnitName("player") .. '-' .. GetRealmName()
 local DEVIAN_FRAME = 'DevianConsole'
+local DEVIAN_DOCK_FRAME = 'DevianDockFrame'
+local MSG_NEED_DEV_MODE = 'Must be in development mode to use this function.'
 local print = _G.print
 local db
 local defaults = {
   ['global'] = {{}, {}},
   ['tags'] = {},
   ['channels'] = {[1] = {signature = 'Main', index = 1, x = 100, y = 800, height = 500, width = 600, enabled = true}},
-  primary_channel = 1,
-  current_channel = 1,
-  max_channel = 1,
-  toggle = true,
-  load_message = "Defaults loaded.",
-  font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]],
+  primary_channel = 1, -- the channel to which default output is sent
+  current_channel = 1, -- the front channel
+  max_channel = 1, -- the highest created channel id
+  enable = true, -- allow enabled consoles to appear
+  load_message = "Defaults loaded.", -- messages to be displayed after reload
+  font = [[Interface\Addons\Devian\font\SourceCodePro-Regular.ttf]], -- font info
   fontsize = 13,
   fontoutline = 'NONE',
-  headergrab = {'VERTICAL', 0, 0, 0, 0.5, 0.1, 0.1, 0.1, 0.3},
-  backalpha = 0.5,
-  backdrop = {0,0,0,0.4},
+  headergrad = {'VERTICAL', 0, 0, 0, 0.5, 0.1, 0.1, 0.1, 0.3}, -- header info
+  headerdrop = {1,1,1,1},
+  headeralpha = 1,
+  backdrop = {0,0,0,1},                                        -- background frame info
   backgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.3, 0, 0, 0, 0.5},
-  backblend = 'BLEND',
-  frontdrop = {0,0,0,1},
+  backblend = 'MOD',
+  backalpha = 0.7,
+  backborder = {0,0,1,0.75},
+  frontdrop = {0,0,0,1},                                       -- foreground frame info
   frontgrad = {'VERTICAL', 0.1, 0.1, 0.1, 0.9, 0, 0, 0, 0.9},
-  frontblend = 'BLEND',
+  frontblend = 'MOD',
   frontalpha = 1,
   frontborder = {1,0,0,1},
-  backborder = {0,0,1,0.75},
-  tagcolor = {},
-  workspace = 1,
+  tagcolor = {},   -- tag color repository
+  workspace = 1,   -- current profile
+  last_workspace = 2 -- default workspace to alternate with when just "/dvn" is issued
 }
 
 
@@ -55,6 +60,10 @@
 
   -- no args, toggle ui
   if mode == 'dock' then
+    if db.workspace == 1 then
+      D:Print('Must be in dev mode to use this.')
+      return
+    end
     if #args <= 2 then
       D:Print("Not enough arguments for dock command.")
       return
@@ -93,10 +102,19 @@
 
 
   elseif mode == 'stack' then
+    if db.workspace == 1 then
+      return D:Print(MSG_NEED_DEV_MODE)
+    end
     return D:StackFrames()
   elseif mode == 'grid' then
+    if db.workspace == 1 then
+      return D:Print(MSG_NEED_DEV_MODE)
+    end
     return D:DistributeFrames()
   elseif mode == 'tag' then -- tagging
+    if db.workspace == 1 then
+      return D:Print(MSG_NEED_DEV_MODE)
+    end
 
     if tag ~= nil and dest ~= nil then
       -- convert to ID
@@ -135,9 +153,15 @@
     else
       list_state = tonumber(mode)
       db.workspace = list_state
+      if list_state ~= 1 then
+        db.last_workspace = list_state
+      end
+
     end
   elseif mode == nil then
-    list_state = db.last_workspace and db.last_workspace or 1
+    list_state = (db.workspace == 1) and db.last_workspace or 1
+    db.workspace = list_state
+    db.load_message = "quick swapped workspace #"..list_state
   else
     return D:PrintHelp()
   end
@@ -172,7 +196,7 @@
           --print('DisableAddOn(', i, ',', value,')')
           DisableAddOn(i,value)
         end
-      else
+      elseif mode ~= 'save' then
         if type(db.unlisted) ~= 'table' then
           db.unlisted = {}
         end
@@ -183,7 +207,7 @@
   end
 
   if mode ~= 'save' then
-    db.load_message = "AddOn profile ".. list_state .." was loaded."
+    --db.load_message = "AddOn profile ".. list_state .." was loaded."
     ReloadUI()
   else
       D:Print('Profile #'.. (list_state)..' saved.')
@@ -267,6 +291,9 @@
 -- @paramsig [...]
 -- @param ... one or more space-seperated channel keys
 local function Console_Toggle(input)
+  if db.workspace == 1 then
+    return D:Print(MSG_NEED_DEV_MODE)
+  end
   local search = {}
   local n = 0
   if D:GetArgs(input,1) then
@@ -282,24 +309,22 @@
     search = D.console
   end
 
-  db.toggle = not db.toggle and true or nil
+  db.enabled = (not db.enabled) and true or nil
   for i, c in ipairs(search) do
-    print(i,c.index)
-    if db.toggle then
+    --print(i,c.index)
+    if db.enabled then
       c.enabled = true
       c:Show()
       if db.current_channel == c.index then
         c:ToFront()
       end
+      c:Save()
     else
-      c.enabled = nil
-      c.minimized = nil
-      c:Maximize()
       c:Hide()
     end
   end
 
-  if db.toggle then
+  if db.enabled then
     D:Print('toggled on?')
   else
     D:Print('toggled off?')
@@ -376,7 +401,7 @@
 -- @param Tag, signature, or numeric index of the channel to output on. Defaults to primary channel.
 -- @param ... Output contents.
 local function Message(prefix, ...)
-  if db.enabled == true then
+  if not db.enabled then
     return D.oldprint(prefix, ...)
   end
 
@@ -453,13 +478,28 @@
 -- @param i Numeric index of the channel as it manifests in db.channels
 -- @param vars Optional settings table to be used.
 local function CreateConsole(i, vars)
+  if tonumber(i) == nil or math.floor(i) ~= i then
+    error('Non-integer index value.')
+  end
+  if not vars then
+    vars = db.channels[i] and db.channels[i] or db.channels[db.primary_channel]
+  end
+  local f
+  if vars.docked then
+    f = CreateFrame('Frame','DevianDockFrame' .. i, DEVIAN_DOCK_FRAME)
+  else
+    f= CreateFrame('Frame', 'DevianChannelFrame' .. i, UIParent, DEVIAN_FRAME)
+  end
+  --@debug@
+  --print(f:GetName())
 
-  if not vars then
-    vars = db.channels[i]
+  --print('create(2)')
+  for k,v in pairs(vars) do
+    f[k] = v
+    --@debug@
+    --print(' f['..type(k)..' '..tostring(k)..'] = '..type(v)..' '..tostring(v))
   end
 
-  --print('make:', vars.signature, '(', vars.x, vars.y, ')', vars.width, 'x', vars.height)
-  local f = CreateFrame('Frame', 'DevianChannelFrame' .. tostring(i), UIParent, DEVIAN_FRAME)
   f:SetPoint('TOPLEFT', UIParent, 'TOPLEFT', vars.x, vars.y)
   f:SetSize(vars.width, vars.height)
   f:Lower()
@@ -470,139 +510,137 @@
     f.out.backdrop:SetTexture(unpack(db.backdrop))
   end
 
+
+
   f.Save = Console_Save
   f.Minimize = Console_Minimize
   f.Maximize = Console_Maximize
   f.MinMax = Console_MinMax
   f.ToFront = Console_ToFront
   f.Toggle = D.Console_Toggle
-  f.name = vars.name
-  f.index = i
-  f.signature = vars.signature
-  f.format = vars.header
-  f.x = vars.x
-  f.y = vars.y
-  f.width = vars.width
-  f.height = vars.height
-  f.docked = vars.docked
-  f.dockedTo = vars.dockedTo
-
   f:SetScript('OnMouseDown', Console_MouseDown)
   f:SetScript('OnMouseUp', Console_MouseUp)
-  if vars.enabled  then
-    f.enabled = true
-    if db.toggle then
-      f:Show()
-    end
-  end
+
   if vars.minimized then
     f:Minimize()
   else
     f:Maximize()
   end
+  if db.enabled and f.enabled then
+      f:Show()
+  end
 
   return f
 end
 
---- Updates a console "channel" entry, generating a new one if necessary.
--- Config data will be take from cinfo. If cinfo is a string, then only channel signature is set. The remaining variables are filled in from the primary channel.
--- i can be given to select a specific channel table entry to work on. Otherwise, it will just create a new channel and the frame associated with it.
--- @usage cinfo [, i]
--- @param cinfo Config variables table, or a string to be used as channel signature
--- @param i Console index. If valid, settings will be inherited from that channel.
-function D:SetChannel(cinfo, i)
-  -- try to resolve from arguments
-  local dbvars
+--- Updates console information and returns the handle of the channel object that was worked on.
+-- When key is nil or not a valid handle, a new channel is created using whatever signature can be found in cinfo.
+-- The signature can be passed as a string, or as a table entry under the key 'signature'
+-- If the signature of a new channel is also a tag, the channel will be added to that tag
+-- @param cinfo string signature of a new channel, or a table of config variables to be imposed on the channel
+-- @param key string signature or index number of channel to operate on
+-- @usage channel = D:SetChannel('new', nil) -- creates a new channel
+-- @usage channel = D:SetChannel({x = 200, y = 100}, 4) -- updates channel #4
+function D:SetChannel(cinfo, key)
   local t_info = {}
-  local channel
-  local isNew
-  if type(i) =='number' and  db.channels[i] then
-      dbvars = db.channels[i]
-  elseif type(i) == 'string' and D.sig[i] then
-    dbvars = db.channels[D.sig[i].index]
+  local channel, isNew, id, sig, t_id
+  -- obtain source data
+  if tonumber(key) ~= nil and  db.channels[key] then
+    id = tonumber(key)
+  elseif D.sigID[tostring(key)] then
+    id = D.sigID[tostring(key)]
   else
-    dbvars = db.channels[db.primary_channel]
+    id = db.primary_channel
     isNew = true
   end
+  local dbvars = db.channels[id]
+  t_id = id           -- overridden later if new
+  t_info.index = t_id --
+  --@debug@
+  --print('setchan(1) cinfo, key, id=', cinfo, key, id)--@end-debug@
 
+
+  -- obtain config info
+  if type(cinfo) == 'string' then
+    sig = cinfo
+    cinfo = {signature = sig}
+  elseif type(cinfo) ~= 'table' then -- stop here if a table wans't passed
+    error('Expecting table of string as arg1')
+  elseif cinfo.signature then -- new sig
+    sig = cinfo.signature
+  elseif isNew then -- new channel sig
+    sig = 'Ch'
+  else -- old sig
+    sig = db.channels[id].signature
+  end
+  t_info.signature = sig
   --@debug@
-  print('setchan(1)', cinfo, i, isNew)--@end-debug@
+  --print('setchan(2) sig,id,isNew=', sig, id, isNew)--@end-debug@
 
-  if type(cinfo) == 'string' and not db.sig[cinfo] then
-    t_info.signature = cinfo
-    cinfo = {}
-  elseif type(cinfo) ~= 'table' then
-    error('Expecting table of string as arg1')
+  for k,v in pairs(cinfo) do -- allow all cinfo to pass
+    t_info[k] = v
   end
 
-  --@debug@
-  print('setchan(2)', cinfo, i, isNew)--@end-debug@
-
-  --TODO: figure out why tag assignments are getting eaten
-  -- is cinfo a table or signature?
-
-
-
-  -- did we get a signature string?
-  if not (cinfo.signature or t_info.signature) then
-    t_info.signature = 'noname'
+  local blocked = {          -- ignore these vars:
+    ['docked'] = true,       -- table
+    ['dockedTo'] = true,     -- table-related
+    ['signature'] = true}    -- already determined
+  for k,v in pairs(dbvars) do
+    if not t_info[k] and not blocked[k] then -- already set or blocked?
+      t_info[k] = v
+    end
+  end
+  -- new channel overrides
+  if isNew then
+    if D.sigID[sig]then -- find a non-clashing signature
+    local result, i = sig, 1
+    while D.sigID[result] do
+      result = sig .. i
+      i = i + 1
+    end
+    t_info.signature = result
+    end
+    t_id = db.max_channel + 1
+    t_info.index = t_id
+    --@debug@
+    --print('setchan(3a) isNew, sig, t_info.signature=', isNew, sig, t_info.signature)--@end-debug@
+  else
+    --@debug@
+    --print('setchan(3b) isNew, sig, t_info.signature=', isNew, sig, t_info.signature)--@end-debug@
   end
 
-  --@debug@
-  print('setchan(3)', cinfo, i, isNew, t_info.signature)--@end-debug@
-  -- look for existing sigs
-  if D.sig[t_info.signature] then
-    local sigvar = t_info.signature
-    local j = 2
-    while D.sig[sigvar] do
-      sigvar = sigvar .. j
-      j = j + 1
+  local channel
+  if not self.console[t_id] then -- create a frame
+    if isNew then -- position the channel frame
+      t_info.x = t_info.x + 20
+      t_info.y = t_info.y - 20
+      db.channels[t_id] = t_info
+      --@debug@
+      print('setchan(4a)', 't_id, x, y=', t_id, t_info.x, t_info.y)--@end-debug@
     end
-    t_info.signature = sigvar
+    channel = CreateConsole(t_id, t_info)
+    self.console[t_id] = channel
+    self.sig[t_info.signature] = channel
+    self.sigID[t_info.signature] = t_id
+    self.IDsig[t_id] = t_info.signature
+
+  end
+  channel = self.console[t_id]
+  if channel.minimized then
+    channel:Minimize()
+  else
+    channel:Maximize()
   end
 
+  if channel.enabled and db.enabled then -- hide or show last since Min/Max mess with visibility
+    print('setchan(5a) enable')
+    channel:Show()
+  else
+    print('setchan(5a) disable')
+    channel:Hide()
+  end
   --@debug@
-  print('setchan(4)', cinfo, i, isNew, t_info.signature)--@end-debug@
-  -- can proceed to fill in from base vars here
-  for k,v in pairs(dbvars) do
-    if not t_info[k] then
-      if cinfo[k] then
-        t_info[k] = cinfo[k]
-        --@debug@
-        print('setchan(5a)', 'cinfo', k)--@end-debug@
-      elseif db.channels[self.primary_channel][k] then
-        t_info[k] = db.channels[self.primary_channel][k]
-        --@debug@
-        print('setchan(5b)', 'db', self.primary_channel, k)--@end-debug@
-      end
-    end
-  end
-
-  -- we're working with a fresh channel right?
-  if isNew then
-    i = D.num_channels + 1
-    t_info.index = i
-    t_info.x = t_info.x + 20
-    t_info.y = t_info.y - 20
-    db.channels[i] = t_info
-    --@debug@
-    print('setchan(6)', 'new index', i)--@end-debug@
-  end
-
-  -- can proceed to display something from here
-  if not self.console[i] then
-    self.console[i] = CreateConsole(i, t_info)
-    -- if it isn't already spawned, create the frame
-    --@debug@
-    print('setchan(7)', 'new console', i)--@end-debug@
-  end
-  local channel = self.console[i]
-  self.sig[t_info.signature] = channel
-  self.sigID[t_info.signature] = i
-  self.IDsig[i] = t_info.signature
-
-  --@debug@
-  print('setchan(8)', 'end', self.sig[t_info.signature], self.sigID[t_info.signature], self.IDsig[i], self.docked)--@end-debug@
+  --print('setchan(end); c:IsVisible(), c.enabled, db.enabled=', channel:IsVisible(), channel.enabled, db.enabled)--@end-debug@
   return channel
 end
 
@@ -615,7 +653,43 @@
 end
 
 function D:OnEnable()
+  print(MAJOR, MINOR)
+
+  if db.unlisted and #db.unlisted > 0 then
+    D:Print('New AddOns have been found since the last profile update: '.. table.concat(db.unlisted, ', '))
+    table.wipe(db.unlisted)
+  end
+
+  if db.workspace == 1 then
+    D:Print('Gameplay mode active (list #'..db.workspace..'). Print handling turned |cFFFFFF00OFF|r.')
+  else
+    D:Print('Development mode active (list #'..db.workspace..'). Print handling |cFF00FF00ON|r.')
+  end
+
+end
+
+function D:OnInitialize()
   -- commands
+  self:RegisterChatCommand("cleandvn", function(args)
+    DevianDB = nil
+    DevianDB = {
+      load_message = "All SavedVars wiped."
+    }
+    ReloadUI()
+    end)
+  self:RegisterChatCommand("resetdvn", function(args)
+    for k,v in pairs(DevianDB) do
+      if k ~= 'global' then
+        DevianDB[k] = nil
+      end
+    end
+
+    DevianDB.load_message = "Non-user SavedVars have been reset."
+    for k,v in pairs(defaults) do
+      DevianDB[k] = v
+    end
+    ReloadUI()
+  end)
   local cmdlist = {
     ['dvn'] = ScanAddOnList,
     ['devian'] = ScanAddOnList,
@@ -625,35 +699,7 @@
     self:RegisterChatCommand(cmd, func, true)
   end
 
-  if db.workspace == 1 then
-    D:Print('Gameplay mode active. Print handling turned |cFFFFFF00OFF|r..')
-  else
-    D:Print('Development mode active (list #'..db.workspace..'). Print handling |cFF00FF00ON|r.')
-  end
-
-end
-
-function D:OnInitialize()
-  -- emergency button
-  self:RegisterChatCommand("cleandvn", function(args)
-    DevianDB = nil
-    ReloadUI()
-    end)
-  self:RegisterChatCommand("resetdvn", function(args)
-    for k,v in pairs(DevianDB) do
-      if k ~= 'global' then
-        DevianDB[k] = nil
-      end
-    end
-
-    for k,v in pairs(defaults) do
-      DevianDB[k] = v
-    end
-    ReloadUI()
-  end)
-
-  -- savedvars
-  local cherry = false
+  -- pull defaults
   if not _G.DevianDB then
     _G.DevianDB = defaults
   end
@@ -674,7 +720,11 @@
     _G.oldprint = D.oldprint
   end
 
-  --self.raise_ct = 0
+  -- Stop here in game mode
+  if db.workspace == 1 then
+    return
+  end
+
   self.max_channel = 0
   self.num_channels = 0
   self.console = {}
@@ -702,21 +752,8 @@
     self.console[db.current_channel]:ToFront()
     -- bring the current channel to the front
   end
-
-  if db.enabled then
-    for i, c in pairs(self.console) do
-      self.console[i]:Hide()
-    end
+  setprinthandler(Message)
+  print = function(...)
+    _G.print('Dvn', ...)
   end
-
-
-  -- only do this in dev mode
-  if db.workspace > 1 then
-
-    setprinthandler(Message)
-    print = function(...)
-      _G.print('Dvn', ...)
-    end
-  end
-  print(MAJOR, MINOR)
 end
\ No newline at end of file
--- a/Devian.xml	Sat Dec 26 21:51:57 2015 -0500
+++ b/Devian.xml	Sun Dec 27 02:30:46 2015 -0500
@@ -5,11 +5,71 @@
   <Include file="Libs\AceAddon-3.0\Console-3.0.xml" />
   <!--@end-no-lib-strip@-->.
 
-  <Texture name="DevianBorder" virtual="true" setAllPoints="false">
+  <Texture virtual="true" name="DevianBorder" setAllPoints="false">
     <Color r="1" g="0" b="0" a="1" />
     <Size x="2" y="2" />
   </Texture>
 
+
+  <Texture virtual="true" name="DevianHeader" parentKey="titlebar" alphaMode="BLEND">
+    <Anchors>
+      <Anchor point="TOPLEFT" />
+      <Anchor point="TOPRIGHT" />
+    </Anchors>
+    <Size y="20" />
+    <Color r="0.3" g="0.3" b="0.3" a="1" />
+    <Gradient orientation="VERTICAL">
+      <MinColor r="0" g="0" b="0" a="0.7"/>
+      <MaxColor r="0.3" g="0.3" b="0.3" a="0.7"/>
+    </Gradient>
+  </Texture>
+
+  <ScrollingMessageFrame
+      name="DevianBuffer"
+      maxLines="500"
+      fade="false"
+      displayduration="2147483647"
+      insertMode="BOTTOM"
+      virtual="true">
+    <Anchors>
+      <Anchor point="TOPLEFT" y="-20" />
+      <Anchor point="BOTTOMRIGHT" />
+    </Anchors>
+    <FontString  font="Interface\Addons\Devian\font\SourceCodePro-Regular.ttf" wordwrap="true"
+                 justifyH="LEFT"
+                 indented="true"
+                 setAllPoints="true">
+      <FontHeight>
+        <AbsValue val="13"/>
+      </FontHeight>
+    </FontString>
+
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture name="$parentBackdrop" parentKey="backdrop" setAllPoints="true" alphaMode="BLEND">
+          <Color r="1" g="1" b="1" a="1"/>
+          <Gradient orientation="VERTICAL">
+            <MinColor r="0" g="0" b="0" a="0.7"/>
+            <MaxColor r="0" g="0" b="0" a="0.3"/>
+          </Gradient>
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <Texture name="DevianGripperRight" file="Interface\Addons\Devian\corner.blp" parentKey="grip" strata="HIGH" alphaMode="ADD">
+          <Anchors>
+            <Anchor point="BOTTOMRIGHT" x="-1" y="1" />
+          </Anchors>
+          <Size x="18" y="18" />
+          <Color r="0.4" g="0.4" b="0.4" a="1"/>
+          <Gradient orientation="VERTICAL">
+            <MaxColor r="0.9" g="0.9" b="0.9" a="1"/>
+            <MinColor r="0.4" g="0.4" b="0.4" a="1"/>
+          </Gradient>
+        </Texture>
+      </Layer>
+    </Layers>
+  </ScrollingMessageFrame>
+
   <Frame
       name="DevianConsole"
       parent="UIParent"
@@ -27,7 +87,7 @@
     </ResizeBounds>
     <Scripts>
       <OnShow>
-        self.header:SetText(self.index..' '.. self.signature)
+        self.title:SetText(self.index..' '.. self.signature)
       </OnShow>
       <OnMouseWheel>
         local up =  delta > 0
@@ -43,69 +103,9 @@
         end
       </OnMouseWheel>
     </Scripts>
-
-    <Frames>
-      <ScrollingMessageFrame
-          name="$parentScrollFrame"
-          parentkey="out"
-          maxLines="500"
-          fade="false"
-          displayduration="2147483647"
-          insertMode="BOTTOM">
-        <Anchors>
-          <Anchor point="TOPLEFT" y="-20" />
-          <Anchor point="BOTTOMRIGHT" />
-        </Anchors>
-        <FontString  font="Interface\Addons\Devian\font\SourceCodePro-Regular.ttf" wordwrap="true"
-                    justifyH="LEFT"
-                    indented="true"
-                    setAllPoints="true">
-          <FontHeight>
-            <AbsValue val="13"/>
-          </FontHeight>
-        </FontString>
-
-        <Layers>
-          <Layer level="BACKGROUND">
-            <Texture name="$parentbg" parentKey="backdrop" setAllPoints="true" alphaMode="BLEND">
-              <Color r="1" g="1" b="1" a="1"/>
-              <Gradient orientation="VERTICAL">
-                <MinColor r="0" g="0" b="0" a="0.7"/>
-                <MaxColor r="0" g="0" b="0" a="0.3"/>
-              </Gradient>
-            </Texture>
-          </Layer>
-          <Layer level="OVERLAY">
-            <Texture name="DevianGripperRight" file="Interface\Addons\Devian\corner.blp" parentKey="grip" strata="HIGH" alphaMode="ADD">
-              <Anchors>
-                <Anchor point="BOTTOMRIGHT" x="-1" y="1" />
-              </Anchors>
-              <Size x="18" y="18" />
-              <Color r="0.4" g="0.4" b="0.4" a="1"/>
-              <Gradient orientation="VERTICAL">
-                <MaxColor r="0.9" g="0.9" b="0.9" a="1"/>
-                <MinColor r="0.4" g="0.4" b="0.4" a="1"/>
-              </Gradient>
-            </Texture>
-          </Layer>
-        </Layers>
-      </ScrollingMessageFrame>
-    </Frames>
     <Layers>
       <Layer level="ARTWORK">
-        <Texture parentKey="titlebar" alphaMode="BLEND">
-          <Anchors>
-            <Anchor point="TOPLEFT" />
-            <Anchor point="TOPRIGHT" />
-          </Anchors>
-          <Size y="20" />
-          <Color r="0.3" g="0.3" b="0.3" a="1" />
-          <Gradient orientation="VERTICAL">
-            <MinColor r="0" g="0" b="0" a="0.7"/>
-            <MaxColor r="0.3" g="0.3" b="0.3" a="0.7"/>
-          </Gradient>
-        </Texture>
-        <FontString parentKey="header" font="Interface\Addons\Devian\font\SourceCodePro-Bold.ttf" wordwrap="true"
+        <FontString parentKey="title" font="Interface\Addons\Devian\font\SourceCodePro-Bold.ttf" wordwrap="true"
                     justifyH="LEFT"
                     indented="true">
           <Anchors>
@@ -163,6 +163,40 @@
           </Anchors>
         </Texture>
       </Layer>
+      <Layer level="OVERLAY">
+        <Texture name="$parentHeader" parentKey="header" inherits="DevianHeader">
+          <Anchors>
+            <Anchor point="TOPLEFT" />
+            <Anchor point="TOPRIGHT" />
+            <Size y="20" />
+          </Anchors>
+        </Texture>
+      </Layer>
     </Layers>
+    <Frames>
+      <ScrollingMessageFrame parentKey="out" inherits="DevianBuffer" />
+    </Frames>
+  </Frame>
+
+
+
+  <Frame
+      name="DevianDockFrame"
+      inherits="DevianConsole"
+      virtual="true">
+    <Layers>
+      <Layer level="ARTWORK">
+        <Texture name="$parentHeader" parentKey="headerbar" inherits="DevianHeader">
+          <Anchors>
+            <Anchor point="TOPLEFT" />
+            <Size x="150" y="20" />
+          </Anchors>
+        </Texture>
+        <!-- channel headers are moved here -->
+      </Layer>
+    </Layers>
+    <Frames>
+      <!-- channel scrollers are moved in here -->
+    </Frames>
   </Frame>
 </Ui>
\ No newline at end of file
--- a/Dock.lua	Sat Dec 26 21:51:57 2015 -0500
+++ b/Dock.lua	Sun Dec 27 02:30:46 2015 -0500
@@ -9,78 +9,9 @@
 local _G = _G
 local db = DevianDB
 
+local function Dock_MenuClick() end
 
 local function Dock_MouseDown(self, button, up)
-  local parent = self.dockedTo and D.console[self.dockedTo] or self
-  local docked = parent.docked
-  if docked == nil then
-    docked = {}
-  end
-  local worklist = {}
-  for _, i in pairs(docked) do
-    table.insert(worklist, D.console[i])
-  end
-
-  if not up then
-    if button ~= 'RightButton' then
-      if parent.titlebar:IsMouseOver() or not parent.isDocked then
-        parent:ToFront()
-      else
-        parent.out:Hide()
-      end
-
-      if parent.out.grip:IsMouseOver() then
-        parent:StartSizing()
-      else
-        parent:StartMoving()
-      end
-    else
-      parent:MinMax()
-    end
-
-  else
-    if button ~= 'RightButton' then
-      if parent.titlebar:IsMouseOver() then
-        parent.out:Show()
-      end
-      parent:StopMovingOrSizing()
-    end
-  end
-
-  local fixparent = true
-  for _, frame in pairs(worklist) do
-    if not up then
-      if button ~= 'RightButton' then
-        if frame.titlebar:IsMouseOver() then
-          frame:ToFront()
-          fixparent = nil
-        else
-          frame.out:Hide()
-        end
-        if parent.out.grip:IsMouseOver() then
-          frame:StartSizing()
-        else
-          frame:StartMoving()
-        end
-      end
-    else
-      if button ~= 'RightButton' then
-        frame:StopMovingOrSizing()
-        frame:SetPoint('TOPLEFT', parent, 'TOPLEFT')
-        frame:SetPoint('BOTTOMRIGHT', parent, 'BOTTOMRIGHT')
-        frame.x = nil
-        frame.y = nil
-        frame.width = nil
-        frame.height = nil
-        frame:Save()
-
-      end
-    end
-  end
-
-  if fixparent then
-    parent.out:Show()
-  end
 end
 local function Dock_MouseUp (self, button)
   Dock_MouseDown(self, button, true)
@@ -130,7 +61,8 @@
     frame.y = nil
     frame.width = nil
     frame.height = nil
-    frame.oldscript = frame:GetScript('OnMousedown')
+    frame.scriptsMD = frame:GetScript('OnMouseDown')
+    frame.scriptsMU = frame:GetScript('OnMouseUp')
     frame:SetScript('OnMouseDown', nil)
     frame:SetScript('OnMouseUp', nil)
     frame:Save()