Merge "croupier: Upgrade Flutter and Drawer"
diff --git a/go/src/hearts/assets/JoinGamePressed.png b/go/src/hearts/assets/JoinGamePressed.png
new file mode 100644
index 0000000..df323f5
--- /dev/null
+++ b/go/src/hearts/assets/JoinGamePressed.png
Binary files differ
diff --git a/go/src/hearts/assets/JoinGameUnpressed.png b/go/src/hearts/assets/JoinGameUnpressed.png
new file mode 100644
index 0000000..a38797f
--- /dev/null
+++ b/go/src/hearts/assets/JoinGameUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/NewGamePressed.png b/go/src/hearts/assets/NewGamePressed.png
new file mode 100644
index 0000000..733fe85
--- /dev/null
+++ b/go/src/hearts/assets/NewGamePressed.png
Binary files differ
diff --git a/go/src/hearts/assets/NewGameUnpressed.png b/go/src/hearts/assets/NewGameUnpressed.png
new file mode 100644
index 0000000..539bcac
--- /dev/null
+++ b/go/src/hearts/assets/NewGameUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/NewRoundPressed.png b/go/src/hearts/assets/NewRoundPressed.png
new file mode 100644
index 0000000..1cd0d3d
--- /dev/null
+++ b/go/src/hearts/assets/NewRoundPressed.png
Binary files differ
diff --git a/go/src/hearts/assets/NewRoundUnpressed.png b/go/src/hearts/assets/NewRoundUnpressed.png
new file mode 100644
index 0000000..cd9c796
--- /dev/null
+++ b/go/src/hearts/assets/NewRoundUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/QuitPressed.png b/go/src/hearts/assets/QuitPressed.png
new file mode 100644
index 0000000..f42be9b
--- /dev/null
+++ b/go/src/hearts/assets/QuitPressed.png
Binary files differ
diff --git a/go/src/hearts/assets/QuitUnpressed.png b/go/src/hearts/assets/QuitUnpressed.png
new file mode 100644
index 0000000..47deba6
--- /dev/null
+++ b/go/src/hearts/assets/QuitUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/SitSpotPressed.png b/go/src/hearts/assets/SitSpotPressed.png
new file mode 100644
index 0000000..b4ada5f
--- /dev/null
+++ b/go/src/hearts/assets/SitSpotPressed.png
Binary files differ
diff --git a/go/src/hearts/assets/SitSpotUnpressed.png b/go/src/hearts/assets/SitSpotUnpressed.png
new file mode 100644
index 0000000..0991f49
--- /dev/null
+++ b/go/src/hearts/assets/SitSpotUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/StartBlue.png b/go/src/hearts/assets/StartBlue.png
index 036938f..dd92db2 100644
--- a/go/src/hearts/assets/StartBlue.png
+++ b/go/src/hearts/assets/StartBlue.png
Binary files differ
diff --git a/go/src/hearts/assets/StartBluePressed.png b/go/src/hearts/assets/StartBluePressed.png
new file mode 100644
index 0000000..7f6154e
--- /dev/null
+++ b/go/src/hearts/assets/StartBluePressed.png
Binary files differ
diff --git a/go/src/hearts/assets/StartGray.png b/go/src/hearts/assets/StartGray.png
index 555592c..aced4e1 100644
--- a/go/src/hearts/assets/StartGray.png
+++ b/go/src/hearts/assets/StartGray.png
Binary files differ
diff --git a/go/src/hearts/assets/WatchSpotPressed.png b/go/src/hearts/assets/WatchSpotPressed.png
new file mode 100644
index 0000000..6060786
--- /dev/null
+++ b/go/src/hearts/assets/WatchSpotPressed.png
Binary files differ
diff --git a/go/src/hearts/assets/WatchSpotUnpressed.png b/go/src/hearts/assets/WatchSpotUnpressed.png
new file mode 100644
index 0000000..37b446c
--- /dev/null
+++ b/go/src/hearts/assets/WatchSpotUnpressed.png
Binary files differ
diff --git a/go/src/hearts/img/texture/texture.go b/go/src/hearts/img/texture/texture.go
index 187f3ab..fd96e76 100644
--- a/go/src/hearts/img/texture/texture.go
+++ b/go/src/hearts/img/texture/texture.go
@@ -271,8 +271,10 @@
 		"O-Lower-Gray.png", "P-Lower-Gray.png", "Q-Lower-Gray.png", "R-Lower-Gray.png", "S-Lower-Gray.png", "T-Lower-Gray.png",
 		"U-Lower-Gray.png", "V-Lower-Gray.png", "W-Lower-Gray.png", "X-Lower-Gray.png", "Y-Lower-Gray.png", "Z-Lower-Gray.png",
 		"Space-Gray.png", "RoundedRectangle-DBlue.png", "RoundedRectangle-LBlue.png", "RoundedRectangle-Gray.png", "Rectangle-LBlue.png",
-		"Rectangle-DBlue.png", "HorizontalPullTab.png", "VerticalPullTab.png", "NewGame.png", "NewRound.png", "JoinGame.png", "Period.png",
-		"SitSpot.png", "WatchSpot.png", "StartBlue.png", "StartGray.png", "Restart.png", "Visibility.png", "VisibilityOff.png", "Quit.png",
+		"Rectangle-DBlue.png", "HorizontalPullTab.png", "VerticalPullTab.png", "NewGamePressed.png", "NewGameUnpressed.png",
+		"NewRoundPressed.png", "NewRoundUnpressed.png", "JoinGamePressed.png", "JoinGameUnpressed.png", "Period.png",
+		"SitSpotPressed.png", "SitSpotUnpressed.png", "WatchSpotPressed.png", "WatchSpotUnpressed.png", "StartBlue.png", "StartGray.png",
+		"StartBluePressed.png", "Restart.png", "Visibility.png", "VisibilityOff.png", "QuitPressed.png", "QuitUnpressed.png",
 	}
 	for _, f := range boundedImgs {
 		a, err := asset.Open(f)
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index 95e9231..29d26bd 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -34,7 +34,8 @@
 	resetImgs(u)
 	resetScene(u)
 	addHeader(u)
-	watchImg := u.Texs["WatchSpot.png"]
+	watchImg := u.Texs["WatchSpotUnpressed.png"]
+	watchAlt := u.Texs["WatchSpotPressed.png"]
 	arrangeBlockLength := u.WindowSize.X - 4*u.Padding
 	if u.WindowSize.Y < u.WindowSize.X {
 		arrangeBlockLength = u.WindowSize.Y - u.CardDim.Y
@@ -50,17 +51,18 @@
 	addArrangePlayer(3, arrangeDim, arrangeBlockLength, u)
 	// table
 	watchPos := coords.MakeVec((u.WindowSize.X-arrangeDim.X)/2, (u.WindowSize.Y+arrangeBlockLength)/2-2*arrangeDim.Y-4*u.Padding)
-	u.Buttons["joinTable"] = texture.MakeImgWithoutAlt(watchImg, watchPos, arrangeDim, u)
-	quitImg := u.Texs["Quit.png"]
+	u.Buttons["joinTable"] = texture.MakeImgWithAlt(watchImg, watchAlt, watchPos, arrangeDim, true, u)
+	quitImg := u.Texs["QuitUnpressed.png"]
+	quitAlt := u.Texs["QuitPressed.png"]
 	quitDim := u.CardDim
 	quitPos := coords.MakeVec(u.Padding, u.TopPadding+10)
-	u.Buttons["exit"] = texture.MakeImgWithoutAlt(quitImg, quitPos, quitDim, u)
+	u.Buttons["exit"] = texture.MakeImgWithAlt(quitImg, quitAlt, quitPos, quitDim, true, u)
 	if u.IsOwner {
-		startImg := u.Texs["StartBlue.png"]
-		startAlt := u.Texs["StartGray.png"]
+		startImg := u.Texs["StartGray.png"]
+		startAlt := u.Texs["StartBlue.png"]
 		startDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
 		startPos := u.WindowSize.MinusVec(startDim).Minus(u.BottomPadding)
-		display := u.CurTable.AllReadyForNewRound()
+		display := !u.CurTable.AllReadyForNewRound()
 		u.Buttons["start"] = texture.MakeImgWithAlt(startImg, startAlt, startPos, startDim, display, u)
 	}
 }
@@ -86,10 +88,11 @@
 	reposition.ResetAnims(u)
 	resetImgs(u)
 	resetScene(u)
-	newGameImg := u.Texs["NewGame.png"]
+	newGameImg := u.Texs["NewGameUnpressed.png"]
+	newGameAlt := u.Texs["NewGamePressed.png"]
 	newGameDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
 	newGamePos := coords.MakeVec((u.WindowSize.X-newGameDim.X)/2, u.TopPadding)
-	u.Buttons["newGame"] = texture.MakeImgWithoutAlt(newGameImg, newGamePos, newGameDim, u)
+	u.Buttons["newGame"] = texture.MakeImgWithAlt(newGameImg, newGameAlt, newGamePos, newGameDim, true, u)
 	buttonNum := 1
 	for _, d := range u.DiscGroups {
 		if d != nil {
@@ -112,9 +115,10 @@
 				for _, img := range textImgs {
 					u.BackgroundImgs = append(u.BackgroundImgs, img)
 				}
-				joinGameImg := u.Texs["JoinGame.png"]
+				joinGameImg := u.Texs["JoinGameUnpressed.png"]
+				joinGameAlt := u.Texs["JoinGamePressed.png"]
 				joinGamePos := coords.MakeVec(u.WindowSize.X-u.BottomPadding-newGameDim.X, newGamePos.Y+float32(buttonNum)*(bgBannerDim.Y+u.Padding))
-				u.Buttons[fmt.Sprintf("joinGame-%d", buttonNum)] = texture.MakeImgWithoutAlt(joinGameImg, joinGamePos, newGameDim, u)
+				u.Buttons[fmt.Sprintf("joinGame-%d", buttonNum)] = texture.MakeImgWithAlt(joinGameImg, joinGameAlt, joinGamePos, newGameDim, true, u)
 				u.Buttons[fmt.Sprintf("joinGame-%d", buttonNum)].SetInfo(d.LogAddr)
 				buttonNum++
 			}
@@ -484,7 +488,8 @@
 }
 
 func addArrangePlayer(player int, arrangeDim *coords.Vec, arrangeBlockLength float32, u *uistate.UIState) {
-	sitImg := u.Texs["SitSpot.png"]
+	sitImg := u.Texs["SitSpotUnpressed.png"]
+	sitAlt := u.Texs["SitSpotPressed.png"]
 	var sitPos *coords.Vec
 	switch player {
 	case 0:
@@ -497,7 +502,7 @@
 		sitPos = coords.MakeVec((u.WindowSize.X-arrangeDim.X)/2+arrangeDim.X+2*u.Padding, (u.WindowSize.Y+arrangeBlockLength)/2-2*arrangeDim.Y-4*u.Padding)
 	}
 	if u.PlayerData[player] == 0 {
-		u.Buttons[fmt.Sprintf("joinPlayer-%d", player)] = texture.MakeImgWithoutAlt(sitImg, sitPos, arrangeDim, u)
+		u.Buttons[fmt.Sprintf("joinPlayer-%d", player)] = texture.MakeImgWithAlt(sitImg, sitAlt, sitPos, arrangeDim, true, u)
 	} else {
 		avatar := uistate.GetAvatar(player, u)
 		u.BackgroundImgs = append(u.BackgroundImgs, texture.MakeImgWithoutAlt(avatar, sitPos, arrangeDim, u))
@@ -1095,14 +1100,17 @@
 
 func addScoreButton(gameOver bool, u *uistate.UIState) {
 	var buttonImg sprite.SubTex
+	var buttonAlt sprite.SubTex
 	if gameOver {
-		buttonImg = u.Texs["NewGame.png"]
+		buttonImg = u.Texs["NewGameUnpressed.png"]
+		buttonAlt = u.Texs["NewGamePressed.png"]
 	} else {
-		buttonImg = u.Texs["NewRound.png"]
+		buttonImg = u.Texs["NewRoundUnpressed.png"]
+		buttonAlt = u.Texs["NewRoundPressed.png"]
 	}
 	buttonDim := coords.MakeVec(2*u.CardDim.X, 3*u.CardDim.Y/4)
 	buttonPos := coords.MakeVec((u.WindowSize.X-buttonDim.X)/2, u.WindowSize.Y-buttonDim.Y-u.BottomPadding)
-	u.Buttons["ready"] = texture.MakeImgWithoutAlt(buttonImg, buttonPos, buttonDim, u)
+	u.Buttons["ready"] = texture.MakeImgWithAlt(buttonImg, buttonAlt, buttonPos, buttonDim, true, u)
 }
 
 func resetImgs(u *uistate.UIState) {
diff --git a/go/src/hearts/sync/client.go b/go/src/hearts/sync/client.go
index 27b721d..63f57fe 100644
--- a/go/src/hearts/sync/client.go
+++ b/go/src/hearts/sync/client.go
@@ -30,7 +30,7 @@
 	}
 	ds := ldiscovery.NewWithPlugins([]ldiscovery.Plugin{mdns})
 	fmt.Printf("Start scanning...\n")
-	ch, err := ds.Scan(ctx, "")
+	ch, err := ds.Scan(ctx, fmt.Sprintf("v.InterfaceName = \"%s\"", CroupierInterface))
 	if err != nil {
 		ctx.Fatalf("Scan failed: %v", err)
 	}
@@ -39,12 +39,7 @@
 	for {
 		select {
 		case update := <-ch:
-			key, discStruct := GetSG(instances, update, u)
-			if discStruct != nil {
-				settingsAddr := discStruct.SettingsAddr
-				JoinSettingsSyncgroup(settingsAddr, u)
-				u.DiscGroups[key] = discStruct
-			}
+			GetSG(instances, update, u)
 			view.LoadDiscoveryView(u)
 		case <-signals.ShutdownOnSignals(ctx):
 			break loop
@@ -55,16 +50,18 @@
 }
 
 // Returns the addresses of any discovered syncgroups that contain croupier game information
-func GetSG(instances map[string]string, update discovery.Update, u *uistate.UIState) (string, *uistate.DiscStruct) {
+func GetSG(instances map[string]string, update discovery.Update, u *uistate.UIState) {
 	switch uType := update.(type) {
 	case discovery.UpdateFound:
 		found := uType.Value
 		instances[string(found.Service.InstanceId)] = found.Service.InstanceName
 		fmt.Printf("Discovered %q: Instance=%x, Interface=%q, Addrs=%v\n", found.Service.InstanceName, found.Service.InstanceId, found.Service.InterfaceName, found.Service.Addrs)
-		if found.Service.InterfaceName == CroupierInterface {
-			key := found.Service.InstanceId
-			ds := uistate.MakeDiscStruct(found.Service.Attrs["settings_sgname"], found.Service.Addrs[0], found.Service.Attrs["game_start_data"])
-			return key, ds
+		key := found.Service.InstanceId
+		ds := uistate.MakeDiscStruct(found.Service.Attrs["settings_sgname"], found.Service.Addrs[0], found.Service.Attrs["game_start_data"])
+		if ds != nil {
+			settingsAddr := ds.SettingsAddr
+			JoinSettingsSyncgroup(settingsAddr, u)
+			u.DiscGroups[key] = ds
 		}
 	case discovery.UpdateLost:
 		lost := uType.Value
@@ -76,7 +73,6 @@
 		u.DiscGroups[lost.InstanceId] = nil
 		fmt.Printf("Lost %q: Instance=%x\n", name, lost.InstanceId)
 	}
-	return "", nil
 }
 
 // Returns a watchstream of the data in the table
diff --git a/go/src/hearts/sync/util.go b/go/src/hearts/sync/util.go
index 1e4f12e..8c6b586 100644
--- a/go/src/hearts/sync/util.go
+++ b/go/src/hearts/sync/util.go
@@ -8,8 +8,8 @@
 
 const (
 	// switch back to my mountpoint with the following code:
-	//MountPoint = "users/emshack@google.com"
-	MountPoint        = "/192.168.86.254:8101"
+	MountPoint = "users/emshack@google.com"
+	//MountPoint        = "/192.168.86.254:8101"
 	UserID            = 2222
 	UserColor         = 16777215
 	UserAvatar        = "player1.jpeg"
diff --git a/go/src/hearts/sync/watch.go b/go/src/hearts/sync/watch.go
index 985c91f..5e489f7 100644
--- a/go/src/hearts/sync/watch.go
+++ b/go/src/hearts/sync/watch.go
@@ -363,6 +363,8 @@
 		if u.CurView == uistate.Arrange {
 			b := u.Buttons["start"]
 			if !b.GetDisplayingImage() {
+				b.SetImage(b.GetAlt())
+				b.SetAlt(u.Texs["StartBluePressed.png"])
 				u.Eng.SetSubTex(b.GetNode(), b.GetImage())
 				b.SetDisplayingImage(true)
 			}
@@ -414,15 +416,5 @@
 func (us updateSorter) Less(i, j int) bool {
 	iKey := us[i].Row
 	jKey := us[j].Row
-	itmp := strings.Split(iKey, "/")
-	if len(itmp) < 3 {
-		return true
-	}
-	iTime := itmp[2]
-	jtmp := strings.Split(jKey, "/")
-	if len(jtmp) < 3 {
-		return false
-	}
-	jTime := jtmp[2]
-	return iTime < jTime
+	return iKey < jKey
 }
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index bf2c271..f2cc3aa 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -34,11 +34,19 @@
 		switch t.Type {
 		case touch.TypeBegin:
 			beginClickDiscovery(t, u)
+		case touch.TypeMove:
+			moveClickDiscovery(t, u)
+		case touch.TypeEnd:
+			endClickDiscovery(t, u)
 		}
 	case uistate.Arrange:
 		switch t.Type {
 		case touch.TypeBegin:
 			beginClickArrange(t, u)
+		case touch.TypeMove:
+			moveClickArrange(t, u)
+		case touch.TypeEnd:
+			endClickArrange(t, u)
 		}
 	case uistate.Table:
 		switch t.Type {
@@ -101,6 +109,10 @@
 		switch t.Type {
 		case touch.TypeBegin:
 			beginClickScore(t, u)
+		case touch.TypeMove:
+			moveClickScore(t, u)
+		case touch.TypeEnd:
+			endClickScore(t, u)
 		}
 	}
 	u.LastMouseXY.X = t.X
@@ -110,6 +122,21 @@
 func beginClickDiscovery(t touch.Event, u *uistate.UIState) {
 	buttonList := findClickedButton(t, u)
 	for _, button := range buttonList {
+		pressButton(button, u)
+	}
+}
+
+func moveClickDiscovery(t touch.Event, u *uistate.UIState) {
+	curPressed := findClickedButton(t, u)
+	alreadyPressed := getPressed(u)
+	if len(alreadyPressed) > 0 && len(curPressed) == 0 {
+		unpressButtons(u)
+	}
+}
+
+func endClickDiscovery(t touch.Event, u *uistate.UIState) {
+	pressed := unpressButtons(u)
+	for _, button := range pressed {
 		if button == u.Buttons["newGame"] {
 			logCh := make(chan string)
 			settingsCh := make(chan string)
@@ -155,6 +182,33 @@
 	buttonList := findClickedButton(t, u)
 	for _, b := range buttonList {
 		if b == u.Buttons["exit"] {
+			pressButton(b, u)
+		} else if b == u.Buttons["start"] {
+			if u.CurTable.AllReadyForNewRound() {
+				pressButton(b, u)
+			}
+		} else if u.CurPlayerIndex < 0 {
+			for _, button := range u.Buttons {
+				if b == button {
+					pressButton(b, u)
+				}
+			}
+		}
+	}
+}
+
+func moveClickArrange(t touch.Event, u *uistate.UIState) {
+	curPressed := findClickedButton(t, u)
+	alreadyPressed := getPressed(u)
+	if len(alreadyPressed) > 0 && len(curPressed) == 0 {
+		unpressButtons(u)
+	}
+}
+
+func endClickArrange(t touch.Event, u *uistate.UIState) {
+	pressed := unpressButtons(u)
+	for _, b := range pressed {
+		if b == u.Buttons["exit"] {
 			if u.SGChan != nil {
 				u.SGChan <- true
 				u.SGChan = nil
@@ -165,7 +219,7 @@
 			go sync.ScanForSG(u.Ctx, u.ScanChan, u)
 			view.LoadDiscoveryView(u)
 		} else if b == u.Buttons["start"] {
-			if b.GetDisplayingImage() {
+			if u.CurTable.AllReadyForNewRound() {
 				successStart := sync.LogGameStart(u)
 				for !successStart {
 					successStart = sync.LogGameStart(u)
@@ -450,7 +504,22 @@
 
 func beginClickScore(t touch.Event, u *uistate.UIState) {
 	buttonList := findClickedButton(t, u)
-	if len(buttonList) > 0 {
+	for _, b := range buttonList {
+		pressButton(b, u)
+	}
+}
+
+func moveClickScore(t touch.Event, u *uistate.UIState) {
+	curPressed := findClickedButton(t, u)
+	alreadyPressed := getPressed(u)
+	if len(alreadyPressed) > 0 && len(curPressed) == 0 {
+		unpressButtons(u)
+	}
+}
+
+func endClickScore(t touch.Event, u *uistate.UIState) {
+	pressed := unpressButtons(u)
+	if len(pressed) > 0 {
 		success := sync.LogReady(u)
 		for !success {
 			sync.LogReady(u)
@@ -570,11 +639,28 @@
 	b.SetDisplayingImage(false)
 }
 
-func unpressButtons(u *uistate.UIState) {
+// returns buttons that were pressed
+func unpressButtons(u *uistate.UIState) []*staticimg.StaticImg {
+	pressed := make([]*staticimg.StaticImg, 0)
 	for _, b := range u.Buttons {
-		u.Eng.SetSubTex(b.GetNode(), b.GetImage())
-		b.SetDisplayingImage(true)
+		if b.GetDisplayingImage() == false {
+			u.Eng.SetSubTex(b.GetNode(), b.GetImage())
+			b.SetDisplayingImage(true)
+			pressed = append(pressed, b)
+		}
 	}
+	return pressed
+}
+
+// returns pressed buttons without unpressing them
+func getPressed(u *uistate.UIState) []*staticimg.StaticImg {
+	pressed := make([]*staticimg.StaticImg, 0)
+	for _, b := range u.Buttons {
+		if b.GetDisplayingImage() == false {
+			pressed = append(pressed, b)
+		}
+	}
+	return pressed
 }
 
 // checks all drop targets to see if a card was dropped there