func newTransition(x, y float64) *transition { return &transition{ Rect: geometry.NewRect(x-TransitionWidth/2, y-TransitionHeight/2, TransitionWidth, TransitionHeight), id: util.GenUUID(), } }
func (g *group) updateBounds(move bool) { if g.model == nil { return } var w, h float64 x0, y0, x1, y1 := detectBounds(g.model.Items()) if !g.folded { w, h = (x1-x0)+2*GroupMargin, (y1-y0)+2*GroupMargin k := math.Ceil(w / GridDefaultGap) w = k * GridDefaultGap k = math.Ceil(h / GridDefaultGap) h = k * GridDefaultGap } fw, fh := g.getFoldedSize() if w < fw { w = fw } if h < fh { h = fh } if move { x, y := x0-GroupMargin, y0-GroupMargin g.Rect = geometry.NewRect(x, y, w, h) } else { g.Rect.Resize(w, h) } }
func newControlPoint(x float64, y float64, modified bool) *controlPoint { return &controlPoint{ geometry.NewRect( x-ControlPointWidth/2, y-ControlPointHeight/2, ControlPointWidth, ControlPointHeight), modified, } }
func constructTransition(model *Transition) *transition { t := &transition{ Rect: geometry.NewRect(model.X, model.Y, TransitionWidth, TransitionHeight), id: model.Id, horizontal: model.Horizontal, label: model.Label, kind: model.Kind, } if t.horizontal { t.Rect.Rotate(t.horizontal) } return t }
func (g *group) Copy() item { gNew := newGroup() /* items := make(map[item]bool, len(g.model.places)+ len(g.model.transitions)+len(g.model.groups)) for _, p := range g.model.places { items[p] = true } for _, t := range g.model.transitions { items[t] = true } for _, g := range g.model.groups { items[g] = true } clonemap := group.model.cloneItems(items) */ gNew.Rect = geometry.NewRect(g.X(), g.Y(), 0, 0) gNew.model = g.model gNew.label = g.label gNew.parent = g.parent gNew.folded = g.folded return item(gNew) }
func (c *Ctrl) handleEvents() { go func() { var x0, y0 float64 var focused *vertex for { switch ev := (<-c.events).(type) { case *stopEvent: return case *keyEvent: if c.Layers.Length < 1 { continue } c.handleKeyEvent(ev) case *mouseEvent: if c.Layers.Length < 1 { continue } x, y := c.WindowCoordsToRelativeGlobal(ev.x, ev.y) switch ev.kind { case EventMouseHover: active := c.Active() if active == nil { continue } v, found := active.findV(x, y) var text string if found { text = dioid.Gd{G: v.G(), D: v.D()}.String() } if text != c.VertexText { c.VertexText = text qml.Changed(c, &c.VertexText) } case EventMousePress: active := c.Active() if active == nil { continue } x0, y0 = x, y v, found := active.findV(x, y) if c.ModifierKeyShift && !found { active.deselectAll() v := active.placeV(x, y) active.selectV(v) focused = v } else if !found { if !c.ModifierKeyControl { active.deselectAll() active.update() } active.util.min = &geometry.Point{x, y} } else { focused = v x0, y0 = v.X, v.Y if len(active.selected) > 1 { if v.isSelected() && c.ModifierKeyControl { active.deselectV(v) } else if c.ModifierKeyControl { active.selectV(v) } else if !v.isSelected() { active.deselectAll() active.selectV(v) } } else if !c.ModifierKeyControl { active.deselectAll() active.selectV(v) } else { active.selectV(v) } active.update() } case EventMouseMove: active := c.Active() if active == nil { continue } dx, dy := x-x0, y-y0 x0, y0 = x, y if focused != nil { active.util.kind = UtilNone active.util.max = nil //active.placeV(x, y) for v := range active.selected { v.shift(dx, dy) } active.update() } else { active.util.kind = UtilRect active.util.max = &geometry.Point{x, y} dx := active.util.max.X - active.util.min.X dy := active.util.max.Y - active.util.min.Y var rect *geometry.Rect if dx == 0 || dy == 0 { continue } w, h := math.Abs(dx), math.Abs(dy) if dx < 0 && dy < 0 { rect = geometry.NewRect( active.util.max.X, active.util.max.Y, w, h, ) } else if dx < 0 /* && dy > 0 */ { rect = geometry.NewRect( active.util.max.X, active.util.max.Y-h, w, h, ) } else if dx > 0 && dy < 0 { rect = geometry.NewRect( active.util.max.X-w, active.util.max.Y, w, h, ) } else /* dx > 0 && dy > 0 */ { rect = geometry.NewRect( active.util.min.X, active.util.min.Y, w, h, ) } for _, v := range active.defined { if v.bound().Intersect(rect) { active.selectV(v) } else { active.deselectV(v) } } for _, v := range active.temporary { if v.bound().Intersect(rect) { active.selectV(v) } else { active.deselectV(v) } } active.update() } case EventMouseRelease: active := c.Active() if active == nil { continue } for v := range active.selected { v.align() } focused = nil active.util.kind = UtilNone active.update() } default: log.Println("Event not supported") } } }() }
func (v *vertex) bound() *geometry.Rect { return geometry.NewRect(v.X-PointRadius, v.Y-PointRadius, 2*PointRadius, 2*PointRadius) }
func (tg *teg) Construct(model *Teg) { tg.id = model.Id submodels := make(map[string]*teg, len(model.Groups)) madePlaces := make(map[string]*place, 256) for _, g := range model.Groups { gNew := newGroup() gNew.id = g.Id gNew.label = g.Label gNew.folded = g.Folded gNew.parent = tg sub, ok := submodels[g.Model.Id] if !ok { sub = newTeg() sub.Construct(g.Model) sub.parent = tg submodels[g.Model.Id] = sub } gNew.model = sub gNew.Rect = geometry.NewRect(g.X, g.Y, 0, 0) for _, t := range g.Inputs { tNew := constructTransition(t) proxId, ok := g.Iostate[t.Id] if !ok { panic(errors.New("group constructing: iostate broken")) } tNew.group = gNew tNew.proxy = gNew.model.findById(proxId).(*transition) tNew.parent = tg for _, p := range t.In { pNew, ok := madePlaces[p.Id] if !ok { pNew = constructPlace(p) pNew.parent = tg madePlaces[p.Id] = pNew tg.places = append(tg.places, pNew) } pNew.out = tNew tNew.in = append(tNew.in, pNew) if p.OutControl != nil { pNew.outControl = newControlPoint(p.OutControl.X, p.OutControl.Y, p.OutControl.Modified) } pNew.refineControls() } for _, p := range t.Out { pInner := gNew.model.findById(p.Id).(*place) tNew.out = append(tNew.out, pInner) } tNew.refineSize() gNew.inputs = append(gNew.inputs, tNew) } for _, t := range g.Outputs { tNew := constructTransition(t) proxId := g.Iostate[t.Id] tNew.group = gNew tNew.proxy = gNew.model.findById(proxId).(*transition) tNew.parent = tg for _, p := range t.Out { pNew, ok := madePlaces[p.Id] if !ok { pNew = constructPlace(p) pNew.parent = tg madePlaces[p.Id] = pNew tg.places = append(tg.places, pNew) } pNew.in = tNew tNew.out = append(tNew.out, pNew) if p.InControl != nil { pNew.inControl = newControlPoint(p.InControl.X, p.InControl.Y, p.InControl.Modified) } pNew.refineControls() } for _, p := range t.In { pInner := gNew.model.findById(p.Id).(*place) tNew.in = append(tNew.in, pInner) } tNew.refineSize() gNew.outputs = append(gNew.outputs, tNew) } gNew.iostate = make(map[*transition]*transition, len(gNew.inputs)+len(gNew.outputs)) for _, t := range gNew.inputs { if t.proxy != nil { gNew.iostate[t.proxy] = t } } for _, t := range gNew.outputs { if t.proxy != nil { gNew.iostate[t.proxy] = t } } tg.groups = append(tg.groups, gNew) gNew.updateBounds(false) gNew.updateIO() gNew.adjustIO() gNew.Align() } for _, t := range model.Transitions { tNew := constructTransition(t) tNew.parent = tg for _, p := range t.In { pNew, ok := madePlaces[p.Id] if !ok { pNew = constructPlace(p) pNew.parent = tg madePlaces[p.Id] = pNew tg.places = append(tg.places, pNew) } pNew.out = tNew tNew.in = append(tNew.in, pNew) if p.OutControl != nil { pNew.outControl = newControlPoint(p.OutControl.X, p.OutControl.Y, p.OutControl.Modified) } pNew.refineControls() } for _, p := range t.Out { pNew, ok := madePlaces[p.Id] if !ok { pNew = constructPlace(p) pNew.parent = tg madePlaces[p.Id] = pNew tg.places = append(tg.places, pNew) } pNew.in = tNew tNew.out = append(tNew.out, pNew) if p.InControl != nil { pNew.inControl = newControlPoint(p.InControl.X, p.InControl.Y, p.InControl.Modified) } pNew.refineControls() } tNew.refineSize() tg.transitions = append(tg.transitions, tNew) } for _, p := range model.Places { _, ok := madePlaces[p.Id] if !ok { pNew := constructPlace(p) pNew.parent = tg tg.places = append(tg.places, pNew) } } }
func (c *Ctrl) handleEvents() { go func() { var x0, y0 float64 var focused interface{} var copied bool for { switch ev := (<-c.events).(type) { case *stopEvent: return case *keyEvent: c.handleKeyEvent(ev) case *mouseEvent: x, y := c.WindowCoordsToRelativeGlobal(ev.x, ev.y) switch ev.kind { case EventMousePress: x0, y0 = x, y smth, found := c.model.findDrawable(x, y) if c.ModifierKeyAlt { if !found { c.model.deselectAll() c.model.update() } else if _, cp := smth.(*controlPoint); !cp { focused = smth c.model.deselectAll() c.model.selectItem(smth.(item)) c.model.update() } c.model.util.min = &geometry.Point{x, y} } else if c.ModifierKeyShift && !found { var it item c.model.deselectAll() if c.ModifierKeyControl { it = c.model.addTransition(x, y) } else { it = c.model.addPlace(x, y) } c.model.selectItem(it) focused = it copied = true // prevent copy of item } else if !found { if !c.ModifierKeyControl { c.model.deselectAll() c.model.update() } c.model.util.min = &geometry.Point{x, y} } else { focused = smth if control, ok := smth.(*controlPoint); ok { control.modified = true } else { it := smth.(item) //x0, y0 = it.Center().X, it.Center().Y if len(c.model.selected) > 1 { if c.model.isSelected(it) && c.ModifierKeyControl { c.model.deselectItem(it) } else if c.ModifierKeyControl { c.model.selectItem(it) } else if !c.model.isSelected(it) { c.model.deselectAll() c.model.selectItem(it) } } else if !c.ModifierKeyControl { c.model.deselectAll() c.model.selectItem(it) } else { c.model.selectItem(it) } } c.model.update() } case EventMouseMove: dx, dy := x-x0, y-y0 x0, y0 = x, y if c.ModifierKeyAlt { c.model.util.kind = UtilStroke c.model.util.max = &geometry.Point{x, y} if focused != nil { smth, found := c.model.findDrawable(x, y) if _, cp := smth.(*controlPoint); found && !cp { c.model.selectItem(smth.(item)) } else if _, cp := focused.(*controlPoint); !found && !cp { c.model.deselectAll() c.model.selectItem(focused.(item)) } } c.model.update() } else if c.ModifierKeyShift && !copied { copied = true clones := c.model.cloneItems(c.model.selected) c.model.deselectAll() for _, v := range clones { c.model.selectItem(v) } c.model.update() } else if focused != nil { c.model.util.kind = UtilNone c.model.util.max = nil if point, cp := focused.(*controlPoint); cp { point.Move(x, y) c.model.update() continue } toOrder := make(map[*transition]bool, len(c.model.transitions)) for it := range c.model.selected { if p, ok := it.(*place); ok { p.Shift(dx, dy) if p.in != nil { toOrder[p.in] = true } if p.out != nil { toOrder[p.out] = true } } else if t, ok := it.(*transition); ok { if t.proxy == nil { t.Shift(dx, dy) toOrder[t] = true } } else { it.Shift(dx, dy) } } for t := range toOrder { t.OrderArcs(true) t.OrderArcs(false) } c.model.update() } else { c.model.util.kind = UtilRect c.model.util.max = &geometry.Point{x, y} dx := c.model.util.max.X - c.model.util.min.X dy := c.model.util.max.Y - c.model.util.min.Y var rect *geometry.Rect if dx == 0 || dy == 0 { continue } w, h := math.Abs(dx), math.Abs(dy) if dx < 0 && dy < 0 { rect = geometry.NewRect( c.model.util.max.X, c.model.util.max.Y, w, h, ) } else if dx < 0 /* && dy > 0 */ { rect = geometry.NewRect( c.model.util.max.X, c.model.util.max.Y-h, w, h, ) } else if dx > 0 && dy < 0 { rect = geometry.NewRect( c.model.util.max.X-w, c.model.util.max.Y, w, h, ) } else /* dx > 0 && dy > 0 */ { rect = geometry.NewRect( c.model.util.min.X, c.model.util.min.Y, w, h, ) } for _, p := range c.model.places { if p.Bound().Intersect(rect) { c.model.selectItem(p) } else { c.model.deselectItem(p) } } for _, t := range c.model.transitions { if t.Bound().Intersect(rect) { c.model.selectItem(t) } else { c.model.deselectItem(t) } } for _, g := range c.model.groups { if g.Bound().Intersect(rect) { c.model.selectItem(g) for _, t := range g.inputs { c.model.selectItem(t) } for _, t := range g.outputs { c.model.selectItem(t) } } else { c.model.deselectItem(g) for _, t := range g.inputs { c.model.deselectItem(t) } for _, t := range g.outputs { c.model.deselectItem(t) } } } c.model.update() } case EventMouseRelease: if c.ModifierKeyAlt && c.model.util.kind == UtilStroke { if it, ok := c.model.findDrawable(x, y); focused != nil && focused != it && ok { if p, ok := it.(*place); ok && p.in == nil { if t, ok := focused.(*transition); ok { t.link(p, false) } else if p2, ok := focused.(*place); ok && p2.out == nil { // p -- p2, new transition between pCenter, p2Center := p.Center(), p2.Center() t := c.model.addTransition((pCenter.X+p2Center.X)/2, (pCenter.Y+p2Center.Y)/2) t.link(p2, true) t.link(p, false) } else { log.Println("Unable to link smth to place") } } else if t, ok := it.(*transition); ok { if p, ok := focused.(*place); ok { t.link(p, true) } else if t2, ok := focused.(*transition); ok { // t -- t2, new place between tCenter, t2Center := t.Center(), t2.Center() p := c.model.addPlace((tCenter.X+t2Center.X)/2, (tCenter.Y+t2Center.Y)/2) t2.link(p, false) t.link(p, true) } else { log.Println("Unable to link smth to transition") } } c.model.deselectAll() } else if focused == nil && !ok { // stroking the void, cut the links start := c.model.util.min end := c.model.util.max unlink := func(t *transition, p *place, inbound bool, i int) bool { if inbound { control := p.outControl.Center() borderP := p.BorderPoint(control.X, control.Y, BorderPlaceDist) borderT := t.BorderPoint(true, i) if geometry.CheckSegmentsCrossing(start, end, borderP, control) || geometry.CheckSegmentsCrossing(start, end, control, borderT) { return true } } else { control := p.inControl.Center() borderP := p.BorderPoint(control.X, control.Y, BorderPlaceTipDist) borderT := t.BorderPoint(false, i) if geometry.CheckSegmentsCrossing(start, end, borderP, control) || geometry.CheckSegmentsCrossing(start, end, control, borderT) { return true } } return false } var toUnlink map[*place]bool for _, t := range c.model.transitions { toUnlink = make(map[*place]bool, len(t.in)) for i, p := range t.in { if unlink(t, p, true, i) { toUnlink[p] = true } } for p := range toUnlink { t.unlink(p, true, false) } toUnlink = make(map[*place]bool, len(t.out)) for i, p := range t.out { if unlink(t, p, false, i) { toUnlink[p] = true } } for p := range toUnlink { t.unlink(p, false, false) } } grps := make(map[*group]bool, len(c.model.groups)) for _, g := range c.model.groups { for _, t := range g.inputs { toUnlink = make(map[*place]bool, len(t.in)) for i, p := range t.in { if unlink(t, p, true, i) { toUnlink[p] = true } } for p := range toUnlink { grps[g] = true t.unlink(p, true, true) } } for _, t := range g.outputs { toUnlink = make(map[*place]bool, len(t.out)) for i, p := range t.out { if unlink(t, p, false, i) { toUnlink[p] = true } } for p := range toUnlink { grps[g] = true t.unlink(p, false, true) } } } for g := range grps { g.updateIO() g.adjustIO() } } } else { toAlign := make(map[item]bool, len(c.model.selected)) for it := range c.model.selected { if _, ok := it.(*group); ok { continue } toAlign[it] = true } c.alignItems(toAlign) } focused = nil copied = false c.model.util.kind = UtilNone c.model.update() case EventMouseDoubleClick: if c.ModifierKeyControl || c.ModifierKeyShift { continue } if focused != nil { c.model.deselectAll() c.model.selectItem(focused.(item)) if t, ok := focused.(*transition); ok { t.rotate() if t.proxy != nil { t.group.adjustIO() } c.model.update() } if p, ok := focused.(*place); ok { if c.ModifierKeyAlt { p.timer++ } else { p.counter++ } c.model.update() } if g, ok := focused.(*group); ok { if g.folded { c.model.unfoldGroup(g) } else { c.model.foldGroup(g) } c.model.update() } } } default: log.Println("Event not supported") } } }() }