// Counting mouse clicks, so that a second one on the same spot means // something different from the first. package editor import ( "time" "codeberg.org/turbo-editors/turbo-core/buffer" ) // doubleClickWithin is how long after a press a second one on the same cell // still counts as a double click. // // Four hundred milliseconds is what most desktops settle on. Shorter and a // deliberate double click made with an unhurried hand is read as two separate // ones; longer and two unrelated clicks in the same place — which happens all // the time while reading — start selecting words nobody asked for. const doubleClickWithin = 400 * time.Millisecond // click is where and when a press landed, and how many have landed in a row. type click struct { at buffer.Position when time.Time count int } // countClick records a press and returns how many presses in a row have now // landed on the same cell: 1 for a fresh click, 2 for a double click. // // The cell has to be the same, not merely near: a press one column over is a // different word, and selecting the first one because the pointer drifted is // worse than not selecting at all. func (v *View) countClick(at buffer.Position) int { now := v.now() if v.lastClick.count > 0 && v.lastClick.at == at && now.Sub(v.lastClick.when) <= doubleClickWithin { v.lastClick.count++ } else { v.lastClick.count = 1 } v.lastClick.at = at v.lastClick.when = now return v.lastClick.count } // SetClock replaces the clock two clicks are timed against. // // Only a test has any business calling this. A double click measured against // the real clock is a test that passes or fails by how fast the machine is. // // view.SetClock(func() time.Time { return moment }) func (v *View) SetClock(now func() time.Time) { v.now = now }