2016-04-21 3 views
0

Я являюсь автором Hearthstone tracker, и мне нужно переместить несколько NSWindow над окном Каменного камня.NSWindow positioning

Я получаю раму из Hearthstone, используя CGWindowListCopyWindowInfo. Затем я должен переместить свои окна в некоторых положениях относительно Сердца.

HSTracker overlays Красные стрелки над картами противников, зеленая стрелка над кнопкой поворота, а синие стрелки расположены слева и справа от окна.

Моя текущая настройка экрана является следующее:

Screen setup

, который дает мне следующие кадры

// screen 1 : {x 0 y 0 w 1.440 h 900} 
// screen 2 : {x 1.440 y -180 w 1.920 h 1.080} 

Чтобы поместить противника трекер (левый кадр) в нужное положение, которое это самый простой случай, я использую {x 0 y somepadding w 185 h hearthstoneHeight - somepadding} и получаю правильную рамку с этим

func relativeFrame(frame: NSRect) -> NSRect { 
    var relative = frame 
    relative.origin.x = NSMinX(hearthstoneFrame) + NSMinX(frame) 
    relative.origin.y = NSMinY(hearthstoneFrame) + NSMinY(frame) 

    return relative 
} 

Право трекер находится с помощью {x hearthstoneWidth - trackerWidth, ...}

Для других наложений, я использовал мой текущий (Хартстон) разрешение поместить их и их вычислить их, используя простую математику

x = x/1404.0 * NSWidth(hearthstoneFrame) 
y = y/840.0 * NSHeight(hearthstoneFrame) 

Это работает очень хорошо. Кроме того, если я использую свой второй экран. В этом случае рамки кажутся правильными, но положение окна не очень хорошо.

Вот скриншот окна отладки с {x 0 y 0 w hearthstoneWidth h hearthsoneHeight }. Если я сравню рамки Сердца и моего наложения, они будут идентичны. Debug overlay

Полная функция следующая (я нахожусь в «статическом классе», я только показываю код переоценки). Наверное, мне не хватает чего-то в расчетах, но я не могу найти что.

class frameRelative { 
    static var hearthstoneFrame = NSZeroRect 
    static func findHearthstoneFrame() { 
     let options = CGWindowListOption(arrayLiteral: .ExcludeDesktopElements) 
     let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0)) 
     if let info = (windowListInfo as NSArray? as? [[String: AnyObject]])? 
      .filter({ 
       !$0.filter({ $0.0 == "kCGWindowName" && $0.1 as? String == "Hearthstone" }).isEmpty 
      }) 
      .first { 
       var rect = NSRect() 
       let bounds = info["kCGWindowBounds"] as! CFDictionary 
       CGRectMakeWithDictionaryRepresentation(bounds, &rect) 
       rect.size.height -= titleBarHeight // remove the 22px from the title 
       hearthstoneFrame = rect 
     } 
    } 

    static func frameRelative(frame: NSRect, _ isRelative: Bool = false) -> NSRect { 
     var relative = frame 
     var pointX = NSMinX(relative) 
     var pointY = NSMinY(relative) 

     if isRelative { 
      pointX = pointX/1404.0 * NSWidth(hearthstoneFrame) 
      pointY = pointY/840.0 * NSHeight(hearthstoneFrame) 
     } 

     let x: CGFloat = NSMinX(hearthstoneFrame) + pointX 
     let y = NSMinY(hearthstoneFrame) + pointY 

     relative.origin = NSMakePoint(x, y) 
     return relative 
    } 
} 

// somewhere here 
let frame = NSMakeRect(0, 0, hearthstoneWidth, hearthstoneHeight) 
let relativeFrame = SizeHelper.frameRelative(frame) 
myWindow.setFrame(relativeFrame, display: true) 

Любая помощь будет признателен :)

ответ

0

В конце концов я решил эту проблему, поэтому я решил опубликовать ответ, чтобы закрыть эту тему ... и, может быть, если кто-то столкнется и тот же вопрос один день.

Решение было вычесть макс у из первого экрана с макс у окна Hearthstone.

Окончательный код findHearthstoneFrame является

static func findHearthstoneFrame() { 
    let options = CGWindowListOption(arrayLiteral: .ExcludeDesktopElements) 
     let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0)) 
     if let info = (windowListInfo as NSArray? as? [[String: AnyObject]])?.filter({ 
      !$0.filter({ $0.0 == "kCGWindowName" 
       && $0.1 as? String == "Hearthstone" }).isEmpty 
     }).first { 
      if let id = info["kCGWindowNumber"] as? Int { 
       self.windowId = CGWindowID(id) 
      } 
      var rect = NSRect() 
      let bounds = info["kCGWindowBounds"] as! CFDictionary 
      CGRectMakeWithDictionaryRepresentation(bounds, &rect) 

      if let screen = NSScreen.screens()?.first { 
       rect.origin.y = NSMaxY(screen.frame) - NSMaxY(rect) 
      } 

      self._frame = rect 
     } 
} 

И frameRelative является

static let BaseWidth: CGFloat = 1440.0 
static let BaseHeight: CGFloat = 922.0 
var scaleX: CGFloat { 
    return NSWidth(_frame)/SizeHelper.BaseWidth 
} 

var scaleY: CGFloat { 
    // 22 is the height of the title bar 
    return (NSHeight(_frame) - 22)/SizeHelper.BaseHeight 
} 
func frameRelative(frame: NSRect, relative: Bool = true) -> NSRect { 
    var pointX = NSMinX(frame) 
    var pointY = NSMinY(frame) 
    let width = NSWidth(frame) 
    let height = NSHeight(frame) 

    if relative { 
     pointX = pointX * scaleX 
     pointY = pointY * scaleY 
    } 

    let x: CGFloat = NSMinX(self.frame) + pointX 
    let y: CGFloat = NSMinY(self.frame) + pointY 

    let relativeFrame = NSRect(x: x, y: y, width: width, height: height) 
    return relativeFrame 
}