| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // touchhandler handles all touch events for the app |
| |
| package touchhandler |
| |
| import ( |
| "fmt" |
| "golang.org/x/mobile/event/touch" |
| "golang.org/x/mobile/exp/sprite" |
| "hearts/img/coords" |
| "hearts/img/reposition" |
| "hearts/img/staticimg" |
| "hearts/img/uistate" |
| "hearts/img/view" |
| "hearts/logic/card" |
| "hearts/syncbase/gamelog" |
| ) |
| |
| func OnTouch(t touch.Event, u *uistate.UIState) { |
| switch u.CurView { |
| case uistate.Opening: |
| switch t.Type.String() { |
| case "begin": |
| beginClickOpening(t, u) |
| } |
| case uistate.Table: |
| switch t.Type.String() { |
| case "begin": |
| beginClickTable(t, u) |
| } |
| case uistate.Pass: |
| switch t.Type.String() { |
| case "begin": |
| beginClickPass(t, u) |
| case "move": |
| moveClickPass(t, u) |
| case "end": |
| endClickPass(t, u) |
| } |
| case uistate.Take: |
| switch t.Type.String() { |
| case "begin": |
| beginClickTake(t, u) |
| case "move": |
| moveClickTake(t, u) |
| case "end": |
| endClickTake(t, u) |
| } |
| case uistate.Play: |
| switch t.Type.String() { |
| case "begin": |
| beginClickPlay(t, u) |
| case "move": |
| moveClickPlay(t, u) |
| case "end": |
| endClickPlay(t, u) |
| } |
| case uistate.Split: |
| switch t.Type.String() { |
| case "begin": |
| beginClickSplit(t, u) |
| case "move": |
| moveClickSplit(t, u) |
| case "end": |
| endClickSplit(t, u) |
| } |
| case uistate.Score: |
| switch t.Type.String() { |
| case "begin": |
| beginClickScore(t, u) |
| } |
| } |
| u.LastMouseXY.X = t.X |
| u.LastMouseXY.Y = t.Y |
| } |
| |
| func beginClickOpening(t touch.Event, u *uistate.UIState) { |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| if u.CurTable.GetPlayers()[0].GetHand() == nil { |
| fmt.Println("Dealing") |
| allHands := u.CurTable.Deal() |
| gamelog.LogDeal(u, u.CurPlayerIndex, allHands) |
| } |
| } |
| } |
| |
| func beginClickTable(t touch.Event, u *uistate.UIState) { |
| if u.Debug { |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| if u.Buttons[0] == buttonList[0] { |
| u.CurPlayerIndex = 0 |
| view.LoadPassOrTakeOrPlay(u) |
| } else if u.Buttons[1] == buttonList[0] { |
| u.CurPlayerIndex = 1 |
| view.LoadPassOrTakeOrPlay(u) |
| } else if u.Buttons[2] == buttonList[0] { |
| u.CurPlayerIndex = 2 |
| view.LoadPassOrTakeOrPlay(u) |
| } else if u.Buttons[3] == buttonList[0] { |
| u.CurPlayerIndex = 3 |
| view.LoadPassOrTakeOrPlay(u) |
| } else if u.Buttons[4] == buttonList[0] { |
| view.LoadTableView(u) |
| } else if u.Buttons[5] == buttonList[0] { |
| view.LoadPassOrTakeOrPlay(u) |
| } |
| } |
| } |
| } |
| |
| func beginClickPass(t touch.Event, u *uistate.UIState) { |
| u.CurCard = findClickedCard(t, u) |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| if u.Debug { |
| if u.Buttons[0] == buttonList[0] { |
| pullTab := u.Buttons[0] |
| if pullTab.GetDisplayingImage() { |
| u.CurImg = u.Buttons[0] |
| for _, img := range u.Other { |
| u.Eng.SetSubTex(img.GetNode(), img.GetAlt()) |
| img.SetDisplayingImage(false) |
| } |
| blueBanner := u.Other[0] |
| if blueBanner.GetNode().Arranger == nil { |
| finalX := blueBanner.GetInitial().X |
| finalY := pullTab.GetInitial().Y + pullTab.GetDimensions().Y - blueBanner.GetDimensions().Y |
| finalPos := coords.MakeVec(finalX, finalY) |
| reposition.AnimateImageNoChannel(blueBanner, finalPos, blueBanner.GetDimensions(), u) |
| } |
| } |
| } else if u.Buttons[1] == buttonList[0] { |
| view.LoadTableView(u) |
| } else if u.Buttons[2] == buttonList[0] { |
| view.LoadPassOrTakeOrPlay(u) |
| } |
| } else { |
| pullTab := u.Buttons[0] |
| if pullTab.GetDisplayingImage() { |
| for _, img := range u.Other { |
| u.Eng.SetSubTex(img.GetNode(), img.GetAlt()) |
| img.SetDisplayingImage(false) |
| } |
| } |
| } |
| } |
| } |
| |
| func moveClickPass(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| reposition.DragCard(t, u) |
| } else if u.CurImg != nil { |
| imgs := make([]*staticimg.StaticImg, 0) |
| cards := make([]*card.Card, 0) |
| pullTab := u.Buttons[0] |
| blueBanner := u.BackgroundImgs[1] |
| imgs = append(imgs, pullTab) |
| imgs = append(imgs, blueBanner) |
| for _, d := range u.DropTargets { |
| imgs = append(imgs, d) |
| cards = append(cards, d.GetCardHere()) |
| } |
| for i := 2; i < 7; i++ { |
| text := u.BackgroundImgs[i] |
| u.Eng.SetSubTex(text.GetNode(), text.GetAlt()) |
| text.SetDisplayingImage(false) |
| } |
| reposition.DragImgs(t, cards, imgs, u) |
| } |
| } |
| |
| func endClickPass(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| if !dropCardOnTarget(u.CurCard, t, u) { |
| // check to see if card was removed from a drop target |
| removeCardFromTarget(u.CurCard, u) |
| // add card back to hand |
| reposition.ResetCardPosition(u.CurCard, u.Eng) |
| reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u) |
| } |
| // check to see whether pull tab should be displayed |
| readyToPass := true |
| for _, d := range u.DropTargets { |
| if d.GetCardHere() == nil { |
| readyToPass = false |
| } |
| } |
| pullTab := u.Buttons[0] |
| if readyToPass { |
| u.Eng.SetSubTex(pullTab.GetNode(), pullTab.GetImage()) |
| pullTab.SetDisplayingImage(true) |
| } else { |
| u.Eng.SetSubTex(pullTab.GetNode(), pullTab.GetAlt()) |
| pullTab.SetDisplayingImage(false) |
| } |
| } else if u.CurImg != nil && touchingStaticImg(t, u.Other[0], u) { |
| ch := make(chan bool) |
| success := passCards(ch, u.CurPlayerIndex, u) |
| go func() { |
| <-ch |
| if !success { |
| fmt.Println("Invalid pass") |
| } else { |
| view.LoadTakeView(u) |
| } |
| }() |
| } |
| u.CurCard = nil |
| u.CurImg = nil |
| } |
| |
| func beginClickTake(t touch.Event, u *uistate.UIState) { |
| u.CurCard = findClickedCard(t, u) |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| if u.Debug { |
| if u.Buttons[0] == buttonList[0] { |
| view.LoadTableView(u) |
| } else if u.Buttons[1] == buttonList[0] { |
| view.LoadPassOrTakeOrPlay(u) |
| } |
| } |
| } |
| } |
| |
| func moveClickTake(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| reposition.DragCard(t, u) |
| } |
| } |
| |
| func endClickTake(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| // check to see if card was removed from a drop target |
| removeCardFromTarget(u.CurCard, u) |
| // add card back to hand |
| reposition.ResetCardPosition(u.CurCard, u.Eng) |
| reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u) |
| doneTaking := true |
| for _, d := range u.DropTargets { |
| if d.GetCardHere() != nil { |
| doneTaking = false |
| } |
| } |
| if doneTaking { |
| ch := make(chan bool) |
| success := takeCards(ch, u.CurPlayerIndex, u) |
| go func() { |
| <-ch |
| if !success { |
| fmt.Println("Invalid take") |
| } else { |
| view.LoadPlayView(u) |
| } |
| }() |
| } |
| } |
| u.CurCard = nil |
| } |
| |
| func beginClickPlay(t touch.Event, u *uistate.UIState) { |
| u.CurCard = findClickedCard(t, u) |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| if u.Debug { |
| if u.Buttons[0] == buttonList[0] { |
| u.CurImg = u.Buttons[0] |
| view.LoadSplitView(u) |
| } else if u.Buttons[1] == buttonList[0] { |
| view.LoadTableView(u) |
| } else if u.Buttons[2] == buttonList[0] { |
| view.LoadPassOrTakeOrPlay(u) |
| } |
| } |
| } |
| } |
| |
| func moveClickPlay(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| reposition.DragCard(t, u) |
| } |
| } |
| |
| func endClickPlay(t touch.Event, u *uistate.UIState) { |
| if u.CurCard != nil { |
| if !dropCardOnTarget(u.CurCard, t, u) { |
| // check to see if card was removed from a drop target |
| removeCardFromTarget(u.CurCard, u) |
| // add card back to hand |
| reposition.ResetCardPosition(u.CurCard, u.Eng) |
| reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u) |
| } else { |
| ch := make(chan bool) |
| if err := playCard(ch, u.CurPlayerIndex, u); err != "" { |
| view.ChangePlayMessage(err, u) |
| } |
| go func() { |
| <-ch |
| view.LoadPlayView(u) |
| }() |
| } |
| } |
| u.CurCard = nil |
| } |
| |
| func beginClickSplit(t touch.Event, u *uistate.UIState) { |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| view.LoadPlayView(u) |
| } |
| } |
| |
| func moveClickSplit(t touch.Event, u *uistate.UIState) { |
| } |
| |
| func endClickSplit(t touch.Event, u *uistate.UIState) { |
| } |
| |
| func beginClickScore(t touch.Event, u *uistate.UIState) { |
| buttonList := findClickedButton(t, u) |
| if len(buttonList) > 0 { |
| success := gamelog.LogReady(u) |
| for !success { |
| gamelog.LogReady(u) |
| } |
| } |
| } |
| |
| // returns a card object if a card was clicked, or nil if no card was clicked |
| func findClickedCard(t touch.Event, u *uistate.UIState) *card.Card { |
| // i goes from the end backwards so that it checks cards displayed on top of other cards first |
| for i := len(u.Cards) - 1; i >= 0; i-- { |
| c := u.Cards[i] |
| if touchingCard(t, c, u) { |
| return c |
| } |
| } |
| return nil |
| } |
| |
| // returns a button object if a button was clicked, or nil if no button was clicked |
| func findClickedButton(t touch.Event, u *uistate.UIState) []*staticimg.StaticImg { |
| pressed := make([]*staticimg.StaticImg, 0) |
| for _, b := range u.Buttons { |
| if touchingStaticImg(t, b, u) { |
| pressed = append(pressed, b) |
| } |
| } |
| return pressed |
| } |
| |
| // returns true if pass was successful |
| func passCards(ch chan bool, playerId int, u *uistate.UIState) bool { |
| cardsPassed := make([]*card.Card, 0) |
| dropsToReset := make([]*staticimg.StaticImg, 0) |
| for _, d := range u.DropTargets { |
| passCard := d.GetCardHere() |
| if passCard != nil { |
| cardsPassed = append(cardsPassed, passCard) |
| dropsToReset = append(dropsToReset, d) |
| } |
| } |
| // if the pass is not valid, don't pass any cards |
| if u.CurTable.ValidPass(cardsPassed) && !u.CurTable.GetPlayers()[playerId].GetDonePassing() { |
| success := gamelog.LogPass(u, cardsPassed) |
| for !success { |
| success = gamelog.LogPass(u, cardsPassed) |
| } |
| // UI component |
| pullTab := u.Buttons[0] |
| blueBanner := u.BackgroundImgs[1] |
| imgs := []*staticimg.StaticImg{pullTab, blueBanner} |
| for _, d := range dropsToReset { |
| imgs = append(imgs, d) |
| d.SetCardHere(nil) |
| } |
| var blankTex sprite.SubTex |
| for _, i := range imgs { |
| u.Eng.SetSubTex(i.GetNode(), blankTex) |
| } |
| reposition.AnimateHandCardPass(ch, u.Other, cardsPassed, u) |
| return true |
| } |
| return false |
| } |
| |
| func takeCards(ch chan bool, playerId int, u *uistate.UIState) bool { |
| player := u.CurTable.GetPlayers()[playerId] |
| passedCards := player.GetPassedTo() |
| if len(passedCards) == 3 { |
| success := gamelog.LogTake(u) |
| for !success { |
| success = gamelog.LogTake(u) |
| } |
| reposition.AnimateHandCardTake(ch, u.Other, u) |
| return true |
| } |
| return false |
| } |
| |
| func playCard(ch chan bool, playerId int, u *uistate.UIState) string { |
| c := u.DropTargets[0].GetCardHere() |
| if c != nil { |
| // checks to make sure that: |
| // -player has not already played a card this round |
| // -all players have passed cards |
| // -the play is in the right order |
| // -the play is valid given game logic |
| if u.CurTable.GetPlayers()[playerId].GetDonePlaying() { |
| return "You have already played a card in this trick" |
| } |
| if !u.CurTable.AllDonePassing() { |
| return "Not all players have passed their cards" |
| } |
| if !u.CurTable.ValidPlayOrder(playerId) { |
| return "It is not your turn" |
| } |
| if err := u.CurTable.ValidPlayLogic(c, playerId); err != "" { |
| return err |
| } |
| u.DropTargets[0].SetCardHere(nil) |
| success := gamelog.LogPlay(u, c) |
| for !success { |
| success = gamelog.LogPlay(u, c) |
| } |
| reposition.AnimateHandCardPlay(ch, c, u) |
| return "" |
| } |
| return "No card has been played" |
| } |
| |
| func pressButton(b *staticimg.StaticImg, u *uistate.UIState) { |
| u.Eng.SetSubTex(b.GetNode(), b.GetAlt()) |
| b.SetDisplayingImage(false) |
| } |
| |
| func unpressButtons(u *uistate.UIState) { |
| for _, b := range u.Buttons { |
| u.Eng.SetSubTex(b.GetNode(), b.GetImage()) |
| b.SetDisplayingImage(true) |
| } |
| } |
| |
| func dropCardOnTarget(c *card.Card, t touch.Event, u *uistate.UIState) bool { |
| for _, d := range u.DropTargets { |
| // checking to see if card was dropped onto a drop target |
| if touchingStaticImg(t, d, u) { |
| lastDroppedCard := d.GetCardHere() |
| if lastDroppedCard != nil { |
| reposition.ResetCardPosition(lastDroppedCard, u.Eng) |
| if u.CurView == uistate.Pass || u.CurView == uistate.Play { |
| reposition.RealignSuit(lastDroppedCard.GetSuit(), lastDroppedCard.GetInitial().Y, u) |
| } else if u.CurView == uistate.Table { |
| u.Eng.SetSubTex(lastDroppedCard.GetNode(), lastDroppedCard.GetBack()) |
| lastDroppedCard.Move(lastDroppedCard.GetCurrent(), u.TableCardDim, u.Eng) |
| } |
| } |
| oldY := c.GetInitial().Y |
| suit := c.GetSuit() |
| u.CurCard.Move(d.GetCurrent(), c.GetDimensions(), u.Eng) |
| d.SetCardHere(u.CurCard) |
| // realign suit the card just left |
| if u.CurView == uistate.Pass || u.CurView == uistate.Play { |
| reposition.RealignSuit(suit, oldY, u) |
| } |
| return true |
| } |
| } |
| return false |
| } |
| |
| func removeCardFromTarget(c *card.Card, u *uistate.UIState) bool { |
| for _, d := range u.DropTargets { |
| if d.GetCardHere() == c { |
| d.SetCardHere(nil) |
| return true |
| } |
| } |
| return false |
| } |
| |
| func touchingCard(t touch.Event, c *card.Card, u *uistate.UIState) bool { |
| withinXBounds := t.X/u.PixelsPerPt >= c.GetCurrent().X && t.X/u.PixelsPerPt <= c.GetDimensions().X+c.GetCurrent().X |
| withinYBounds := t.Y/u.PixelsPerPt >= c.GetCurrent().Y && t.Y/u.PixelsPerPt <= c.GetDimensions().Y+c.GetCurrent().Y |
| return withinXBounds && withinYBounds |
| } |
| |
| func touchingStaticImg(t touch.Event, s *staticimg.StaticImg, u *uistate.UIState) bool { |
| withinXBounds := t.X/u.PixelsPerPt >= s.GetCurrent().X && t.X/u.PixelsPerPt <= s.GetDimensions().X+s.GetCurrent().X |
| withinYBounds := t.Y/u.PixelsPerPt >= s.GetCurrent().Y && t.Y/u.PixelsPerPt <= s.GetDimensions().Y+s.GetCurrent().Y |
| return withinXBounds && withinYBounds |
| } |