<commit_before>package uik

import (
	"code.google.com/p/draw2d/draw2d"
	"github.com/skelterjohn/go.wde"
	"github.com/skelterjohn/go.wde/xgb"
)

var WindowGenerator func(parent wde.Window, width, height int) (window wde.Window, err error)

func init() {
	WindowGenerator = func(parent wde.Window, width, height int) (window wde.Window, err error) {
		window, err = xgb.NewWindow(width, height)
		return
	}
}

type DrawRequest struct {
	GC draw2d.GraphicContext
	Dirty Bounds
	Done chan bool
}

// The Block type is a basic unit that can receive events and draw itself.
type Block struct {
	Parent *Foundation

	ListenedChannels map[interface{}]bool

	CloseEvents     chan wde.CloseEvent
	MouseDownEvents chan MouseDownEvent
	MouseUpEvents   chan MouseUpEvent

	allEventsIn     chan<- interface{}
	allEventsOut    <-chan interface{}

	Draw            chan DrawRequest
	Redraw          chan Bounds

	Paint func(gc draw2d.GraphicContext)

	// minimum point relative to the block's parent: only the parent should set this
	Min Coord
	// size of block
	Size Coord
}

func (b *Block) doPaint(gc draw2d.GraphicContext) {
	if b.Paint != nil {
		b.Paint(gc)
	}
}

func (b *Block) draw() {
	for dr := range b.Draw {
		b.doPaint(dr.GC)
		dr.Done <- true
	}
}

func (b *Block) handleSplitEvents() {
	for e := range b.allEventsOut {
		switch e := e.(type) {
		case MouseDownEvent:
			if b.ListenedChannels[b.MouseDownEvents] {
				b.MouseDownEvents <- e
			}
		case MouseUpEvent:
			if b.ListenedChannels[b.MouseUpEvents] {
				b.MouseUpEvents <- e
			}
		case wde.CloseEvent:
			if b.ListenedChannels[b.CloseEvents] {
				b.CloseEvents <- e
			}
		}
	}
}

func (b *Block) BoundsInParent() (bounds Bounds) {
	bounds.Min = b.Min
	bounds.Max = b.Min
	bounds.Max.X += b.Size.X
	bounds.Max.Y += b.Size.Y
	return
}

func (b *Block) MakeChannels() {
	b.ListenedChannels = make(map[interface{}]bool)
	b.CloseEvents = make(chan wde.CloseEvent)
	b.MouseDownEvents = make(chan MouseDownEvent)
	b.MouseUpEvents = make(chan MouseUpEvent)
	b.Draw = make(chan DrawRequest)
	b.Redraw = make(chan Bounds)
	b.allEventsIn, b.allEventsOut = QueuePipe()
	go b.handleSplitEvents()
}

// The foundation type is for channeling events to children, and passing along
// draw calls.
type Foundation struct {
	Block
	Children    []*Block

	// this block currently has keyboard priority
	KeyboardBlock    *Block
}

func (f *Foundation) AddBlock(b *Block) {
	// TODO: place the block somewhere clever
	// TODO: resize the block in a clever way
	f.Children = append(f.Children, b)
	b.Parent = f
}

// func (f *Foundation) handleDrawing() {
// 	for {
// 		select {
// 		case dr := <-f.Draw:
// 			if f.Paint != nil {
// 				f.Paint(dr.GC)
// 			}
// 			for _, child := range f.Children {
// 				dr.GC.Save()

// 				translatedDirty := dr.Dirty
// 				translatedDirty.Min.X -= child.Min.X
// 				translatedDirty.Min.Y -= child.Min.Y

// 				// TODO: clip to child.BoundsInParent()?
// 				dr.GC.Translate(child.Min.X, child.Min.Y)
// 				cdr := DrawRequest{
// 					GC: dr.GC,
// 					Dirty: translatedDirty,
// 					Done: make(chan bool),
// 				}
// 				child.Draw <- dr
// 				<- cdr.Done

// 				dr.GC.Restore()
// 			}
// 			dr.Done<- true
// 		case dirtyBounds := <-f.Redraw:
// 			dirtyBounds.Min.X -= f.Min.X
// 			dirtyBounds.Min.Y -= f.Min.Y
// 			f.Parent.Redraw <- dirtyBounds
// 		}
// 	}
// }

func (f *Foundation) BlockForCoord(p Coord) (b *Block) {
	// quad-tree one day?
	for _, bl := range f.Children {
		if bl.BoundsInParent().Contains(p) {
			b = bl
			return
		}
	}
	return
}

func (f *Foundation) handleRedraw() {
	for dirtyBounds := range f.Redraw {
		dirtyBounds.Min.X -= f.Min.X
		dirtyBounds.Min.Y -= f.Min.Y
		f.Parent.Redraw <- dirtyBounds
	}
}

// dispense events to children, as appropriate
func (f *Foundation) handleEvents() {
	f.ListenedChannels[f.CloseEvents] = true
	f.ListenedChannels[f.MouseDownEvents] = true
	f.ListenedChannels[f.MouseUpEvents] = true
	for {
		select {
		case e := <-f.CloseEvents:
			for _, b := range f.Children {
				b.allEventsIn <- e
			}
		case e := <-f.MouseDownEvents:
			b := f.BlockForCoord(e.Loc)
			if b == nil {
				break
			}
			e.Loc.X -= b.Min.X
			e.Loc.Y -= b.Min.Y
			b.allEventsIn <- e
		case e := <-f.MouseUpEvents:
			b := f.BlockForCoord(e.Loc)
			if b == nil {
				break
			}
			e.Loc.X -= b.Min.X
			e.Loc.Y -= b.Min.Y
			b.allEventsIn <- e

		case dr := <-f.Draw:
			if f.Paint != nil {
				f.Paint(dr.GC)
			}
			for _, child := range f.Children {
				dr.GC.Save()

				translatedDirty := dr.Dirty
				translatedDirty.Min.X -= child.Min.X
				translatedDirty.Min.Y -= child.Min.Y

				// TODO: clip to child.BoundsInParent()?
				dr.GC.Translate(child.Min.X, child.Min.Y)
				cdr := DrawRequest{
					GC: dr.GC,
					Dirty: translatedDirty,<commit_msg>send button events outside of bounds also to their origin<commit_after>package uik

import (
	"code.google.com/p/draw2d/draw2d"
	"github.com/skelterjohn/go.wde"
	"github.com/skelterjohn/go.wde/xgb"
)

var WindowGenerator func(parent wde.Window, width, height int) (window wde.Window, err error)

func init() {
	WindowGenerator = func(parent wde.Window, width, height int) (window wde.Window, err error) {
		window, err = xgb.NewWindow(width, height)
		return
	}
}

type DrawRequest struct {
	GC draw2d.GraphicContext
	Dirty Bounds
	Done chan bool
}

// The Block type is a basic unit that can receive events and draw itself.
type Block struct {
	Parent *Foundation

	ListenedChannels map[interface{}]bool

	CloseEvents     chan wde.CloseEvent
	MouseDownEvents chan MouseDownEvent
	MouseUpEvents   chan MouseUpEvent

	allEventsIn     chan<- interface{}
	allEventsOut    <-chan interface{}

	Draw            chan DrawRequest
	Redraw          chan Bounds

	Paint func(gc draw2d.GraphicContext)

	// minimum point relative to the block's parent: only the parent should set this
	Min Coord
	// size of block
	Size Coord
}

func (b *Block) doPaint(gc draw2d.GraphicContext) {
	if b.Paint != nil {
		b.Paint(gc)
	}
}

func (b *Block) draw() {
	for dr := range b.Draw {
		b.doPaint(dr.GC)
		dr.Done <- true
	}
}

func (b *Block) handleSplitEvents() {
	for e := range b.allEventsOut {
		switch e := e.(type) {
		case MouseDownEvent:
			if b.ListenedChannels[b.MouseDownEvents] {
				b.MouseDownEvents <- e
			}
		case MouseUpEvent:
			if b.ListenedChannels[b.MouseUpEvents] {
				b.MouseUpEvents <- e
			}
		case wde.CloseEvent:
			if b.ListenedChannels[b.CloseEvents] {
				b.CloseEvents <- e
			}
		}
	}
}

func (b *Block) BoundsInParent() (bounds Bounds) {
	bounds.Min = b.Min
	bounds.Max = b.Min
	bounds.Max.X += b.Size.X
	bounds.Max.Y += b.Size.Y
	return
}

func (b *Block) MakeChannels() {
	b.ListenedChannels = make(map[interface{}]bool)
	b.CloseEvents = make(chan wde.CloseEvent)
	b.MouseDownEvents = make(chan MouseDownEvent)
	b.MouseUpEvents = make(chan MouseUpEvent)
	b.Draw = make(chan DrawRequest)
	b.Redraw = make(chan Bounds)
	b.allEventsIn, b.allEventsOut = QueuePipe()
	go b.handleSplitEvents()
}

// The foundation type is for channeling events to children, and passing along
// draw calls.
type Foundation struct {
	Block
	Children    []*Block

	// this block currently has keyboard priority
	KeyboardBlock    *Block
}

func (f *Foundation) AddBlock(b *Block) {
	// TODO: place the block somewhere clever
	// TODO: resize the block in a clever way
	f.Children = append(f.Children, b)
	b.Parent = f
}

// func (f *Foundation) handleDrawing() {
// 	for {
// 		select {
// 		case dr := <-f.Draw:
// 			if f.Paint != nil {
// 				f.Paint(dr.GC)
// 			}
// 			for _, child := range f.Children {
// 				dr.GC.Save()

// 				translatedDirty := dr.Dirty
// 				translatedDirty.Min.X -= child.Min.X
// 				translatedDirty.Min.Y -= child.Min.Y

// 				// TODO: clip to child.BoundsInParent()?
// 				dr.GC.Translate(child.Min.X, child.Min.Y)
// 				cdr := DrawRequest{
// 					GC: dr.GC,
// 					Dirty: translatedDirty,
// 					Done: make(chan bool),
// 				}
// 				child.Draw <- dr
// 				<- cdr.Done

// 				dr.GC.Restore()
// 			}
// 			dr.Done<- true
// 		case dirtyBounds := <-f.Redraw:
// 			dirtyBounds.Min.X -= f.Min.X
// 			dirtyBounds.Min.Y -= f.Min.Y
// 			f.Parent.Redraw <- dirtyBounds
// 		}
// 	}
// }

func (f *Foundation) BlockForCoord(p Coord) (b *Block) {
	// quad-tree one day?
	for _, bl := range f.Children {
		if bl.BoundsInParent().Contains(p) {
			b = bl
			return
		}
	}
	return
}

func (f *Foundation) handleRedraw() {
	for dirtyBounds := range f.Redraw {
		dirtyBounds.Min.X -= f.Min.X
		dirtyBounds.Min.Y -= f.Min.Y
		f.Parent.Redraw <- dirtyBounds
	}
}

// dispense events to children, as appropriate
func (f *Foundation) handleEvents() {
	f.ListenedChannels[f.CloseEvents] = true
	f.ListenedChannels[f.MouseDownEvents] = true
	f.ListenedChannels[f.MouseUpEvents] = true

	var dragOriginBlocks = map[wde.Button]*Block{}
	// drag and up events for the same button get sent to the origin as well

	for {
		select {
		case e := <-f.CloseEvents:
			for _, b := range f.Children {
				b.allEventsIn <- e
			}
		case e := <-f.MouseDownEvents:
			b := f.BlockForCoord(e.Loc)
			if b == nil {
				break
			}
			dragOriginBlocks[e.Which] = b
			e.Loc.X -= b.Min.X
			e.Loc.Y -= b.Min.Y
			b.allEventsIn <- e
		case e := <-f.MouseUpEvents:
			b := f.BlockForCoord(e.Loc)
			if b != nil {
				be := e
				be.Loc.X -= b.Min.X
				be.Loc.Y -= b.Min.Y
				b.allEventsIn <- be
			}
			if origin, ok := dragOriginBlocks[e.Which]; ok {
				oe := e
				oe.Loc.X -= origin.Min.X
				oe.Loc.Y -= origin.Min.Y
				origin.allEventsIn <- oe
			}

		case dr := <-f.Draw:
			if f.Paint != nil {
				f.Paint(dr.GC)
			}
			for _, child := range f.Children {
				dr.GC.Save()

				translatedDirty := dr.Dirty
				translatedDirty.Min.X -= child.Min.X
				translatedDirty.Min.Y -= child.Min.Y

				// TODO: clip to child.BoundsInParent()?
				dr.GC.Translate(child.Min.X, child.Min.Y)
				cdr := DrawRequest{
					GC: dr.GC,
					Dirty: translatedDirty,
{'fraction_non_alphanumeric': 0.14087481146304676, 'fraction_numerical': 0.001005530417295123, 'mean_word_length': 2.643223443223443, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5742186', 'n_tokens_mistral': 4195, 'n_tokens_neox': 3746, 'n_words': 894}