package ui import ( "strings" "time" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" "viewsagent/internal/capture" "viewsagent/internal/win32" ) // cardTitle 是答案浮窗的标题,win32 靠它找 HWND。 const cardTitle = "viewsagent-card" // floatCard 是贴在选区旁边的置顶小窗,只显示最新答案。 type floatCard struct { win fyne.Window body *widget.RichText region capture.Region visible bool } func newFloatCard(a fyne.App) *floatCard { c := &floatCard{win: a.NewWindow(cardTitle)} rt := widget.NewRichText() rt.Wrapping = fyne.TextWrapWord c.body = rt c.win.SetContent(container.NewBorder( nil, nil, nil, nil, container.NewPadded(rt), )) c.win.Resize(fyne.NewSize(400, 240)) return c } // setRegion 记录当前监视区域,用于定位浮窗。 func (c *floatCard) setRegion(r capture.Region) { c.region = r } // update 刷新浮窗内容。 func (c *floatCard) update(text string) { text = strings.TrimSpace(text) if text == "" { text = "(空)" } c.body.ParseMarkdown(text) if c.visible { c.place() } } // show 显示浮窗。 func (c *floatCard) show() { if c.visible { c.place() c.win.RequestFocus() return } c.visible = true c.win.Show() go func() { time.Sleep(120 * time.Millisecond) fyne.Do(c.place) }() } // hide 隐藏浮窗。 func (c *floatCard) hide() { c.visible = false c.win.Hide() } // toggle 切换显示状态。 func (c *floatCard) toggle() { if c.visible { c.hide() return } c.show() } // visibleNow 返回是否正在显示。 func (c *floatCard) visibleNow() bool { return c.visible } // place 把浮窗贴到选区下方(放不下就贴上方),并置顶。 func (c *floatCard) place() { hwnd, err := win32.FindWindowByTitle(cardTitle) if err != nil { return } _ = win32.SetTopMost(hwnd) rect, err := win32.WindowRect(hwnd) if err != nil || rect.Width() <= 0 || rect.Height() <= 0 { return } if !c.region.Valid() { return } mon, _ := win32.MonitorAt(c.region.X+c.region.W/2, c.region.Y+c.region.H/2) work := mon.Work if work.Width() <= 0 { work = mon.Rect } gap := int(8 * max(mon.Scale, 1)) x := c.region.X y := c.region.Y + c.region.H + gap if y+rect.Height() > work.Bottom { y = c.region.Y - rect.Height() - gap } if y < work.Top { y = work.Bottom - rect.Height() } if x+rect.Width() > work.Right { x = work.Right - rect.Width() } if x < work.Left { x = work.Left } _ = win32.MoveTo(hwnd, win32.Rect{Left: x, Top: y, Right: x + rect.Width(), Bottom: y + rect.Height()}) }