mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Added lower thirds.
This commit is contained in:
2
arena.go
2
arena.go
@@ -77,6 +77,7 @@ type Arena struct {
|
||||
playSoundNotifier *Notifier
|
||||
allianceStationDisplayNotifier *Notifier
|
||||
allianceSelectionNotifier *Notifier
|
||||
lowerThirdNotifier *Notifier
|
||||
audienceDisplayScreen string
|
||||
allianceStationDisplays map[string]string
|
||||
allianceStationDisplayScreen string
|
||||
@@ -114,6 +115,7 @@ func (arena *Arena) Setup() {
|
||||
arena.playSoundNotifier = NewNotifier()
|
||||
arena.allianceStationDisplayNotifier = NewNotifier()
|
||||
arena.allianceSelectionNotifier = NewNotifier()
|
||||
arena.lowerThirdNotifier = NewNotifier()
|
||||
|
||||
// Load empty match as current.
|
||||
arena.MatchState = PRE_MATCH
|
||||
|
||||
@@ -23,6 +23,7 @@ type Database struct {
|
||||
rankingMap *modl.DbMap
|
||||
teamMap *modl.DbMap
|
||||
allianceTeamMap *modl.DbMap
|
||||
lowerThirdMap *modl.DbMap
|
||||
}
|
||||
|
||||
// Opens the SQLite database at the given path, creating it if it doesn't exist, and runs any pending
|
||||
@@ -75,4 +76,7 @@ func (database *Database) mapTables() {
|
||||
|
||||
database.allianceTeamMap = modl.NewDbMap(database.db, dialect)
|
||||
database.allianceTeamMap.AddTableWithName(AllianceTeam{}, "alliance_teams").SetKeys(true, "Id")
|
||||
|
||||
database.lowerThirdMap = modl.NewDbMap(database.db, dialect)
|
||||
database.lowerThirdMap.AddTableWithName(LowerThird{}, "lower_thirds").SetKeys(true, "Id")
|
||||
}
|
||||
|
||||
9
db/migrations/20140811222034_CreateLowerThirds.sql
Normal file
9
db/migrations/20140811222034_CreateLowerThirds.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE lower_thirds (
|
||||
id INTEGER PRIMARY KEY,
|
||||
toptext VARCHAR(255),
|
||||
bottomtext VARCHAR(255)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE lower_thirds;
|
||||
@@ -62,6 +62,8 @@ func AudienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
defer close(playSoundListener)
|
||||
allianceSelectionListener := mainArena.allianceSelectionNotifier.Listen()
|
||||
defer close(allianceSelectionListener)
|
||||
lowerThirdListener := mainArena.lowerThirdNotifier.Listen()
|
||||
defer close(lowerThirdListener)
|
||||
|
||||
// Send the various notifications immediately upon connection.
|
||||
var data interface{}
|
||||
@@ -186,6 +188,12 @@ func AudienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
messageType = "allianceSelection"
|
||||
message = cachedAlliances
|
||||
case lowerThird, ok := <-lowerThirdListener:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
messageType = "lowerThird"
|
||||
message = lowerThird
|
||||
}
|
||||
err = websocket.Write(messageType, message)
|
||||
if err != nil {
|
||||
|
||||
46
lower_third.go
Normal file
46
lower_third.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Model and datastore CRUD methods for the text on a lower third slide.
|
||||
|
||||
package main
|
||||
|
||||
type LowerThird struct {
|
||||
Id int
|
||||
TopText string
|
||||
BottomText string
|
||||
}
|
||||
|
||||
func (database *Database) CreateLowerThird(lowerThird *LowerThird) error {
|
||||
return database.lowerThirdMap.Insert(lowerThird)
|
||||
}
|
||||
|
||||
func (database *Database) GetLowerThirdById(id int) (*LowerThird, error) {
|
||||
lowerThird := new(LowerThird)
|
||||
err := database.lowerThirdMap.Get(lowerThird, id)
|
||||
if err != nil && err.Error() == "sql: no rows in result set" {
|
||||
lowerThird = nil
|
||||
err = nil
|
||||
}
|
||||
return lowerThird, err
|
||||
}
|
||||
|
||||
func (database *Database) SaveLowerThird(lowerThird *LowerThird) error {
|
||||
_, err := database.lowerThirdMap.Update(lowerThird)
|
||||
return err
|
||||
}
|
||||
|
||||
func (database *Database) DeleteLowerThird(lowerThird *LowerThird) error {
|
||||
_, err := database.lowerThirdMap.Delete(lowerThird)
|
||||
return err
|
||||
}
|
||||
|
||||
func (database *Database) TruncateLowerThirds() error {
|
||||
return database.lowerThirdMap.TruncateTables()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllLowerThirds() ([]LowerThird, error) {
|
||||
var lowerThirds []LowerThird
|
||||
err := database.teamMap.Select(&lowerThirds, "SELECT * FROM lower_thirds ORDER BY id")
|
||||
return lowerThirds, err
|
||||
}
|
||||
78
setup_lower_thirds.go
Normal file
78
setup_lower_thirds.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Web routes for managing lower thirds.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Shows the lower third configuration page.
|
||||
func LowerThirdsGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
template, err := template.ParseFiles("templates/lower_thirds.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
lowerThirds, err := db.GetAllLowerThirds()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
data := struct {
|
||||
*EventSettings
|
||||
LowerThirds []LowerThird
|
||||
}{eventSettings, lowerThirds}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Saves the new or modified lower third to the database and triggers showing it on the audience display.
|
||||
func LowerThirdsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
lowerThirdId, _ := strconv.Atoi(r.PostFormValue("id"))
|
||||
lowerThird, err := db.GetLowerThirdById(lowerThirdId)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
if r.PostFormValue("action") == "delete" {
|
||||
err := db.DeleteLowerThird(lowerThird)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Save the lower third even if the show or hide buttons were clicked.
|
||||
if lowerThird == nil {
|
||||
lowerThird = &LowerThird{TopText: r.PostFormValue("topText"),
|
||||
BottomText: r.PostFormValue("bottomText")}
|
||||
err = db.CreateLowerThird(lowerThird)
|
||||
} else {
|
||||
lowerThird.TopText = r.PostFormValue("topText")
|
||||
lowerThird.BottomText = r.PostFormValue("bottomText")
|
||||
err = db.SaveLowerThird(lowerThird)
|
||||
}
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if r.PostFormValue("action") == "show" {
|
||||
mainArena.lowerThirdNotifier.Notify(lowerThird)
|
||||
mainArena.audienceDisplayScreen = "lowerThird"
|
||||
mainArena.audienceDisplayNotifier.Notify(nil)
|
||||
} else if r.PostFormValue("action") == "hide" {
|
||||
mainArena.audienceDisplayScreen = "blank"
|
||||
mainArena.audienceDisplayNotifier.Notify(nil)
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/setup/lower_thirds", 302)
|
||||
}
|
||||
@@ -304,3 +304,33 @@ html {
|
||||
width: 250px;
|
||||
color: #fff;
|
||||
}
|
||||
#lowerThird {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: -1000px;
|
||||
bottom: 100px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
color: #000;
|
||||
font-size: 30px;
|
||||
width: 800px;
|
||||
height: 87px;
|
||||
}
|
||||
#lowerThirdLogo {
|
||||
margin: 20px;
|
||||
height: 45px;
|
||||
float: left;
|
||||
}
|
||||
#lowerThirdTop {
|
||||
display: none;
|
||||
font-family: "FuturaLTBold";
|
||||
}
|
||||
#lowerThirdBottom {
|
||||
display: none;
|
||||
font-family: "FuturaLT";
|
||||
}
|
||||
#lowerThirdSingle {
|
||||
display: none;
|
||||
font-family: "FuturaLTBold";
|
||||
line-height: 87px;
|
||||
}
|
||||
@@ -88,3 +88,6 @@
|
||||
.scoring-message {
|
||||
color: #f00;
|
||||
}
|
||||
.btn-lower-third {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,21 @@ var handleAllianceSelection = function(alliances) {
|
||||
}
|
||||
};
|
||||
|
||||
var handleLowerThird = function(data) {
|
||||
if (data.BottomText == "") {
|
||||
$("#lowerThirdTop").hide();
|
||||
$("#lowerThirdBottom").hide();
|
||||
$("#lowerThirdSingle").text(data.TopText);
|
||||
$("#lowerThirdSingle").show();
|
||||
} else {
|
||||
$("#lowerThirdSingle").hide();
|
||||
$("#lowerThirdTop").text(data.TopText);
|
||||
$("#lowerThirdBottom").text(data.BottomText);
|
||||
$("#lowerThirdTop").show();
|
||||
$("#lowerThirdBottom").show();
|
||||
}
|
||||
};
|
||||
|
||||
var transitionBlankToIntro = function(callback) {
|
||||
$("#centering").transition({queue: false, bottom: "0px"}, 500, "ease", function() {
|
||||
$(".teams").transition({queue: false, width: "75px"}, 100, "linear", function() {
|
||||
@@ -233,6 +248,20 @@ var transitionAllianceSelectionToBlank = function(callback) {
|
||||
}
|
||||
};
|
||||
|
||||
var transitionBlankToLowerThird = function(callback) {
|
||||
$("#lowerThird").show();
|
||||
$("#lowerThird").transition({queue: false, left: "150px"}, 750, "ease", callback);
|
||||
};
|
||||
|
||||
var transitionLowerThirdToBlank = function(callback) {
|
||||
$("#lowerThird").transition({queue: false, left: "-1000px"}, 1000, "ease", function() {
|
||||
$("#lowerThird").hide();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$(function() {
|
||||
// Set up the websocket back to the server.
|
||||
websocket = new CheesyWebsocket("/displays/audience/websocket", {
|
||||
@@ -243,7 +272,8 @@ $(function() {
|
||||
realtimeScore: function(event) { handleRealtimeScore(event.data); },
|
||||
setFinalScore: function(event) { handleSetFinalScore(event.data); },
|
||||
playSound: function(event) { handlePlaySound(event.data); },
|
||||
allianceSelection: function(event) { handleAllianceSelection(event.data); }
|
||||
allianceSelection: function(event) { handleAllianceSelection(event.data); },
|
||||
lowerThird: function(event) { handleLowerThird(event.data); }
|
||||
});
|
||||
|
||||
// Map how to transition from one screen to another. Missing links between screens indicate that first we
|
||||
@@ -254,7 +284,8 @@ $(function() {
|
||||
match: transitionBlankToInMatch,
|
||||
score: transitionBlankToScore,
|
||||
logo: transitionBlankToLogo,
|
||||
allianceSelection: transitionBlankToAllianceSelection
|
||||
allianceSelection: transitionBlankToAllianceSelection,
|
||||
lowerThird: transitionBlankToLowerThird
|
||||
},
|
||||
intro: {
|
||||
blank: transitionIntroToBlank,
|
||||
@@ -274,6 +305,9 @@ $(function() {
|
||||
},
|
||||
allianceSelection: {
|
||||
blank: transitionAllianceSelectionToBlank
|
||||
},
|
||||
lowerThird: {
|
||||
blank: transitionLowerThirdToBlank
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -112,6 +112,7 @@ var handleMatchTime = function(data) {
|
||||
};
|
||||
|
||||
var handleSetAudienceDisplay = function(data) {
|
||||
$("input[name=audienceDisplay]:checked").prop("checked", false);
|
||||
$("input[name=audienceDisplay][value=" + data + "]").prop("checked", true);
|
||||
};
|
||||
|
||||
@@ -123,6 +124,7 @@ var handleScoringStatus = function(data) {
|
||||
};
|
||||
|
||||
var handleSetAllianceStationDisplay = function(data) {
|
||||
$("input[name=allianceStationDisplay]:checked").prop("checked", false);
|
||||
$("input[name=allianceStationDisplay][value=" + data + "]").prop("checked", true);
|
||||
};
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center" id="matchCircle">
|
||||
<img id="logo" src="/static/img/logo-min.svg"</img>
|
||||
<img id="logo" src="/static/img/logo-min.svg" />
|
||||
<div id="matchTime"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@
|
||||
<div class="blinds right center-blank"></div>
|
||||
<div class="blinds left background"></div>
|
||||
<div id="blindsCenter">
|
||||
<img id="blindsLogo" src="/static/img/logo-min.svg"</img>
|
||||
<img id="blindsLogo" src="/static/img/logo-min.svg" />
|
||||
</div>
|
||||
<div class="blinds left center-blank"></div>
|
||||
<div id="finalScore">
|
||||
@@ -101,6 +101,12 @@
|
||||
<div id="allianceSelectionCentering" style="display: none;">
|
||||
<div id="allianceSelection"></div>
|
||||
</div>
|
||||
<div id="lowerThird">
|
||||
<img id="lowerThirdLogo" src="/static/img/logo-min.svg" />
|
||||
<div id="lowerThirdTop"></div>
|
||||
<div id="lowerThirdBottom"></div>
|
||||
<div id="lowerThirdSingle"></div>
|
||||
</div>
|
||||
<script id="allianceSelectionTemplate" type="text/x-handlebars-template">
|
||||
<table id="allianceSelectionTable">
|
||||
{{"{{#each this}}"}}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<li><a href="/setup/teams">Team List</a></li>
|
||||
<li><a href="/setup/schedule">Match Scheduling</a></li>
|
||||
<li><a href="/setup/alliance_selection">Alliance Selection</a></li>
|
||||
<li><a href="/setup/lower_thirds">Lower Thirds</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
|
||||
43
templates/lower_thirds.html
Normal file
43
templates/lower_thirds.html
Normal file
@@ -0,0 +1,43 @@
|
||||
{{define "title"}}Lower Thirds{{end}}
|
||||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-lg-offset-3">
|
||||
<div class="well">
|
||||
<legend>Lower Thirds</legend>
|
||||
{{range $lowerThird := .LowerThirds}}
|
||||
<form class="form-horizontal" action="/setup/lower_thirds" method="POST">
|
||||
<div class="form-group">
|
||||
<div class="col-lg-7">
|
||||
<input type="hidden" name="id" value="{{$lowerThird.Id}}" />
|
||||
<input type="text" class="form-control" name="topText" value="{{$lowerThird.TopText}}"
|
||||
placeholder="Top Text"/>
|
||||
<input type="text" class="form-control" name="bottomText" value="{{$lowerThird.BottomText}}"
|
||||
placeholder="Bottom Text"/>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<button type="submit" class="btn btn-info btn-lower-third" name="action" value="save">Save</button>
|
||||
<button type="submit" class="btn btn-success btn-lower-third" name="action" value="show">Show</button>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary btn-lower-third" name="action" value="delete">Delete</button>
|
||||
<button type="submit" class="btn btn-default btn-lower-third" name="action" value="hide">Hide</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
<form class="form-horizontal" action="/setup/lower_thirds" method="POST">
|
||||
<div class="form-group">
|
||||
<div class="col-lg-7">
|
||||
<input type="text" class="form-control" name="topText" placeholder="Top or Solo Text" />
|
||||
<input type="text" class="form-control" name="bottomText" placeholder="Bottom Text" />
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<button type="submit" class="btn btn-info btn-lower-third" name="action" value="save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
{{end}}
|
||||
2
web.go
2
web.go
@@ -122,6 +122,8 @@ func newHandler() http.Handler {
|
||||
router.HandleFunc("/setup/alliance_selection/finalize", AllianceSelectionFinalizeHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/field", FieldGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/field", FieldPostHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/lower_thirds", LowerThirdsGetHandler).Methods("GET")
|
||||
router.HandleFunc("/setup/lower_thirds", LowerThirdsPostHandler).Methods("POST")
|
||||
router.HandleFunc("/match_play", MatchPlayHandler).Methods("GET")
|
||||
router.HandleFunc("/match_play/{matchId}/load", MatchPlayLoadHandler).Methods("GET")
|
||||
router.HandleFunc("/match_play/{matchId}/show_result", MatchPlayShowResultHandler).Methods("GET")
|
||||
|
||||
Reference in New Issue
Block a user