WIP components (as built)
This commit is contained in:
112 files changed
+3607
-1241
No files matched your search
+40
-28
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/egoist/mygo/ui"
|
||||
)
|
||||
|
||||
// DrawingTool is what clicks on a price chart do. The zero value selects and moves drawings.
|
||||
// DrawingTool selects annotation creation or selection behavior.
|
||||
type DrawingTool int
|
||||
|
||||
const (
|
||||
@@ -22,7 +22,7 @@ const (
|
||||
ToolText
|
||||
)
|
||||
|
||||
// DrawingPoint anchors a drawing at a candle time and a price, so it survives panning and new data.
|
||||
// DrawingPoint anchors annotations to candle time and price.
|
||||
type DrawingPoint struct {
|
||||
Time time.Time
|
||||
Price float64
|
||||
@@ -35,7 +35,7 @@ type Drawing struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
// DrawingTools is the caller-held set of drawings, the current tool and an undo history.
|
||||
// DrawingTools holds annotations, the current tool, and undo history.
|
||||
type DrawingTools struct {
|
||||
Items []Drawing
|
||||
Tool DrawingTool
|
||||
@@ -50,7 +50,7 @@ type DrawingTools struct {
|
||||
moving bool
|
||||
}
|
||||
|
||||
// fibLevels are the retracement ratios drawn between a Fibonacci's two points.
|
||||
// fibLevels lists Fibonacci retracement ratios.
|
||||
var fibLevels = []float64{0, 0.236, 0.382, 0.5, 0.618, 0.786, 1}
|
||||
|
||||
// Selected returns the selected drawing's index, or -1.
|
||||
@@ -63,10 +63,10 @@ func (d *DrawingTools) save() {
|
||||
d.undo = append(d.undo, slices.Clone(d.Items))
|
||||
}
|
||||
|
||||
// Undo restores the drawings before the last change and reports whether there was one.
|
||||
// Undo restores the preceding annotations unless locked.
|
||||
func (d *DrawingTools) Undo() bool {
|
||||
n := len(d.undo)
|
||||
if n == 0 {
|
||||
if d.Locked || n == 0 {
|
||||
return false
|
||||
}
|
||||
d.Items, d.undo = d.undo[n-1], d.undo[:n-1]
|
||||
@@ -103,12 +103,12 @@ func (t DrawingTool) twoPoint() bool {
|
||||
return t == ToolTrendLine || t == ToolFibonacci || t == ToolRectangle
|
||||
}
|
||||
|
||||
// point turns a plot position into a drawing point on the nearest candle.
|
||||
// point maps plot coordinates onto the nearest candle.
|
||||
func (d *DrawingTools) point(m *mktCore, g mktGeom, x, y float32) DrawingPoint {
|
||||
return DrawingPoint{Time: m.candles[g.index(m, x)].Time, Price: m.priceAt(g.ys.Invert(y))}
|
||||
}
|
||||
|
||||
// priceAt turns an axis value back into a price, rounded to the decimals.
|
||||
// priceAt resolves an axis value into a rounded price.
|
||||
func (m *mktCore) priceAt(v float64) float64 {
|
||||
if m.base != 0 {
|
||||
v = m.base * (1 + v/100)
|
||||
@@ -123,11 +123,19 @@ func (d *DrawingTools) xy(m *mktCore, g mktGeom, pt DrawingPoint) (float32, floa
|
||||
return g.x(m, i), g.ys.Map(m.val(pt.Price))
|
||||
}
|
||||
|
||||
// input places, selects, drags, nudges and deletes drawings; it reports taking the pointer.
|
||||
// input places, selects, moves, and deletes chart annotations.
|
||||
func (d *DrawingTools) input(m *mktCore, plot *ui.Element, g mktGeom, x, y float32, over, held bool, dx, dy float32) bool {
|
||||
if d.Tool < ToolSelect || d.Tool > ToolText {
|
||||
panic(fmt.Sprintf("mujica: unknown DrawingTool %d", d.Tool))
|
||||
}
|
||||
if d.pending != nil && d.pending.Tool != d.Tool {
|
||||
d.pending, d.moving = nil, false
|
||||
}
|
||||
if plot.Shortcut(ui.Alt, ui.KeyEnter) && !d.Locked && len(d.Items) > 0 {
|
||||
d.sel = d.sel%len(d.Items) + 1
|
||||
m.st.alertFocus = -1
|
||||
m.c.Announce(fmt.Sprintf(msg(m.c, "drawing_tools.selected"), d.sel))
|
||||
}
|
||||
if plot.Shortcut(ui.Cmd, ui.KeyZ) {
|
||||
d.Undo()
|
||||
}
|
||||
@@ -155,22 +163,7 @@ func (d *DrawingTools) input(m *mktCore, plot *ui.Element, g mktGeom, x, y float
|
||||
}
|
||||
if plot.Clicked() && d.Tool != ToolSelect {
|
||||
pt := d.point(m, g, x, y)
|
||||
switch {
|
||||
case d.Tool.twoPoint() && d.pending == nil:
|
||||
d.pending = &Drawing{Tool: d.Tool, A: pt, B: pt}
|
||||
default:
|
||||
item := Drawing{Tool: d.Tool, A: pt, B: pt, Text: d.Text}
|
||||
if d.pending != nil {
|
||||
item.A = d.pending.A
|
||||
}
|
||||
if d.Tool == ToolText && item.Text == "" {
|
||||
item.Text = msg(m.c, "drawing_tools.note")
|
||||
}
|
||||
d.save()
|
||||
d.Items = append(slices.Clone(d.Items), item)
|
||||
d.sel, d.pending, d.Tool = len(d.Items), nil, ToolSelect
|
||||
slog.Debug("mujica: drawing_tools add", "tool", item.Tool)
|
||||
}
|
||||
d.place(m, pt)
|
||||
return true
|
||||
}
|
||||
if d.pending != nil {
|
||||
@@ -203,7 +196,7 @@ func (d *DrawingTools) input(m *mktCore, plot *ui.Element, g mktGeom, x, y float
|
||||
return true
|
||||
}
|
||||
|
||||
// nudge moves item i by candles and price, keeping it on the chart's candles.
|
||||
// nudge moves annotations by candles and price.
|
||||
func (d *DrawingTools) nudge(m *mktCore, i, candles int, price float64) {
|
||||
it := &d.Items[i]
|
||||
move := func(pt *DrawingPoint) {
|
||||
@@ -214,7 +207,7 @@ func (d *DrawingTools) nudge(m *mktCore, i, candles int, price float64) {
|
||||
move(&it.B)
|
||||
}
|
||||
|
||||
// hit returns the drawing within 6 DIPs of (x, y), newest first, or -1.
|
||||
// hit finds the newest annotation within 6 DIPs.
|
||||
func (d *DrawingTools) hit(m *mktCore, g mktGeom, x, y float32) int {
|
||||
for i := len(d.Items) - 1; i >= 0; i-- {
|
||||
it := d.Items[i]
|
||||
@@ -239,7 +232,7 @@ func (d *DrawingTools) hit(m *mktCore, g mktGeom, x, y float32) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// drawingSegmentDist is the distance from (x, y) to the segment a-b.
|
||||
// drawingSegmentDist measures distance to a line segment.
|
||||
func drawingSegmentDist(x, y, ax, ay, bx, by float32) float64 {
|
||||
vx, vy := float64(bx-ax), float64(by-ay)
|
||||
t := 0.0
|
||||
@@ -248,3 +241,22 @@ func drawingSegmentDist(x, y, ax, ay, bx, by float32) float64 {
|
||||
}
|
||||
return math.Hypot(float64(x-ax)-t*vx, float64(y-ay)-t*vy)
|
||||
}
|
||||
|
||||
func (d *DrawingTools) place(m *mktCore, pt DrawingPoint) {
|
||||
if d.Tool.twoPoint() && d.pending == nil {
|
||||
d.pending = &Drawing{Tool: d.Tool, A: pt, B: pt}
|
||||
} else {
|
||||
item := Drawing{Tool: d.Tool, A: pt, B: pt, Text: d.Text}
|
||||
if d.pending != nil {
|
||||
item.A = d.pending.A
|
||||
}
|
||||
if d.Tool == ToolText && item.Text == "" {
|
||||
item.Text = msg(m.c, "drawing_tools.note")
|
||||
}
|
||||
d.save()
|
||||
d.Items = append(slices.Clone(d.Items), item)
|
||||
d.sel, d.pending, d.Tool = len(d.Items), nil, ToolSelect
|
||||
slog.Debug("mujica: drawing_tools add", "tool", item.Tool)
|
||||
}
|
||||
m.c.Invalidate()
|
||||
}
|
||||
Reference in new issue
Block a user