PixelToCursor finds the cursor position that corresponds to the given pixel location (e.g., from mouse click) which has had ScBBox.Min subtracted from it (i.e, relative to upper left of text area)
(pt image.Point)
| 549 | // location (e.g., from mouse click) which has had ScBBox.Min subtracted from |
| 550 | // it (i.e, relative to upper left of text area) |
| 551 | func (ed *Editor) PixelToCursor(pt image.Point) lexer.Pos { |
| 552 | if ed.NumLines == 0 { |
| 553 | return lexer.PosZero |
| 554 | } |
| 555 | bb := ed.renderBBox() |
| 556 | sty := &ed.Styles |
| 557 | yoff := float32(bb.Min.Y) |
| 558 | xoff := float32(bb.Min.X) |
| 559 | stln := ed.firstVisibleLine(0) |
| 560 | cln := stln |
| 561 | fls := ed.charStartPos(lexer.Pos{Ln: stln}).Y - yoff |
| 562 | if pt.Y < int(math32.Floor(fls)) { |
| 563 | cln = stln |
| 564 | } else if pt.Y > bb.Max.Y { |
| 565 | cln = ed.NumLines - 1 |
| 566 | } else { |
| 567 | got := false |
| 568 | for ln := stln; ln < ed.NumLines; ln++ { |
| 569 | ls := ed.charStartPos(lexer.Pos{Ln: ln}).Y - yoff |
| 570 | es := ls |
| 571 | es += math32.Max(ed.renders[ln].BBox.Size().Y, ed.lineHeight) |
| 572 | if pt.Y >= int(math32.Floor(ls)) && pt.Y < int(math32.Ceil(es)) { |
| 573 | got = true |
| 574 | cln = ln |
| 575 | break |
| 576 | } |
| 577 | } |
| 578 | if !got { |
| 579 | cln = ed.NumLines - 1 |
| 580 | } |
| 581 | } |
| 582 | // fmt.Printf("cln: %v pt: %v\n", cln, pt) |
| 583 | if cln >= len(ed.renders) { |
| 584 | return lexer.Pos{Ln: cln, Ch: 0} |
| 585 | } |
| 586 | lnsz := ed.Buffer.LineLen(cln) |
| 587 | if lnsz == 0 || sty.Font.Face == nil { |
| 588 | return lexer.Pos{Ln: cln, Ch: 0} |
| 589 | } |
| 590 | scrl := ed.Geom.Scroll.Y |
| 591 | nolno := float32(pt.X - int(ed.LineNumberOffset)) |
| 592 | sc := int((nolno + scrl) / sty.Font.Face.Metrics.Ch) |
| 593 | sc -= sc / 4 |
| 594 | sc = max(0, sc) |
| 595 | cch := sc |
| 596 | |
| 597 | lnst := ed.charStartPos(lexer.Pos{Ln: cln}) |
| 598 | lnst.Y -= yoff |
| 599 | lnst.X -= xoff |
| 600 | rpt := math32.Vector2FromPoint(pt).Sub(lnst) |
| 601 | |
| 602 | si, ri, ok := ed.renders[cln].PosToRune(rpt) |
| 603 | if ok { |
| 604 | cch, _ := ed.renders[cln].SpanPosToRuneIndex(si, ri) |
| 605 | return lexer.Pos{Ln: cln, Ch: cch} |
| 606 | } |
| 607 | |
| 608 | return lexer.Pos{Ln: cln, Ch: cch} |
no test coverage detected