fetch_needs_update.o fetch_highscore.o fetch_top_scores_for_tournament.o \
fetch_top_chosen_songs_for_tournament.o fetch_auxilliary_screens.o
CCBS_BIGSCREEN_SCREEN_OBJS=groupscreen.o top10scorescreen.o top5chosenscreen.o splitscreen.o rotatescreen.o screen.o
-CCBS_BIGSCREEN_MAIN_OBJS=ccbs_bigscreen.o flagtrigger.o widestring.o fonts.o
+CCBS_BIGSCREEN_MAIN_OBJS=ccbs_bigscreen.o flagtrigger.o widestring.o fonts.o theme.o
CCBS_BIGSCREEN_OBJS=$(CCBS_BIGSCREEN_SQL_OBJS) $(CCBS_BIGSCREEN_SCREEN_OBJS) $(CCBS_BIGSCREEN_MAIN_OBJS)
all: ccbs-bigscreen
#include "fetch_group.h"
#include "fetch_auxilliary_screens.h"
#include "fonts.h"
+#include "theme.h"
#include "groupscreen.h"
#include "top10scorescreen.h"
#include "top5chosenscreen.h"
}
try {
+ init_theme();
init_freetype();
pqxx::connection conn("dbname=ccbs host=www.positivegaming.com user=ccbs password=GeT|>>B_");
FlagTrigger tournament_changed(conn, "active_tournament");
+++ /dev/null
-#ifndef DESIGN_H
-#define DESIGN_H 1
-
-#define BACKGROUND_RED 0
-#define BACKGROUND_GREEN 0
-#define BACKGROUND_BLUE 0
-
-#define MAIN_HEADING_RED 255
-#define MAIN_HEADING_GREEN 255
-#define MAIN_HEADING_BLUE 255
-
-#define COLUMN_HEADING_RED 255
-#define COLUMN_HEADING_GREEN 255
-#define COLUMN_HEADING_BLUE 255
-
-#define ROW_HEADING_RED 255
-#define ROW_HEADING_GREEN 255
-#define ROW_HEADING_BLUE 255
-
-#define DATA_RED 255
-#define DATA_GREEN 255
-#define DATA_BLUE 255
-
-#define FRESH_DATA_RED 255
-#define FRESH_DATA_GREEN 0
-#define FRESH_DATA_BLUE 0
-
-#define DIVIDER_RED 127
-#define DIVIDER_GREEN 127
-#define DIVIDER_BLUE 127
-
-#endif
#include <cstdio>
#include <vector>
#include <stdexcept>
+#include <map>
+#include <string>
#include "fonts.h"
#include "resolution.h"
+#include "theme.h"
-std::vector<FT_Face> fonts;
+extern std::map<std::string, std::string> config;
+std::map<std::string, FT_Face> faces;
+
+std::vector<std::string> split(const std::string &str, char delim)
+{
+ std::vector<std::string> ret;
+ std::string s;
+ for (unsigned i = 0; i < str.size(); ++i) {
+ if (str[i] == delim) {
+ ret.push_back(s);
+ s.clear();
+ } else {
+ s.push_back(str[i]);
+ }
+ }
+ if (!s.empty()) {
+ ret.push_back(s);
+ }
+ return ret;
+}
void init_freetype()
{
FT_Library library;
- FT_Face face;
if (FT_Init_FreeType(&library))
throw std::runtime_error("FreeType init failed.");
- // Georgia
- if (FT_New_Face(library, "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf", 0, &face))
- throw std::runtime_error("Face opening failed.");
- fonts.push_back(face);
+ // Preload all fonts.
+ for (std::map<std::string, std::string>::const_iterator it = config.begin();
+ it != config.end();
+ ++it) {
+ const std::string key = it->first;
+ if (key.size() <= 5 || key.substr(key.size() - 5) != ".font") {
+ continue;
+ }
- // FreeSerif
- if (FT_New_Face(library, "/usr/share/fonts/truetype/freefont/FreeSerif.ttf", 0, &face)) {
- std::fprintf(stderr, "Warning: Couldn't open FreeSerif, some glyphs might not be available\n");
- } else {
- fonts.push_back(face);
- }
-
- // Arial Unicode MS
- if (FT_New_Face(library, "arialuni.ttf", 0, &face)) {
- std::fprintf(stderr, "Warning: Couldn't open Arial Unicode MS, some glyphs might not be available\n");
- } else {
- fonts.push_back(face);
+ std::vector<std::string> font_list = split(it->second, ';');
+ for (unsigned i = 0; i < font_list.size(); ++i) {
+ if (faces.count(font_list[i])) {
+ // Already preloaded.
+ continue;
+ }
+
+ FT_Face face;
+ if (FT_New_Face(library, font_list[i].c_str(), 0, &face)) {
+ fprintf(stderr, "Warning: Couldn't open '%s', some glyphs might not be available\n", font_list[i].c_str());
+ }
+ faces[font_list[i]] = face;
+ }
}
}
screen_height = height;
}
-unsigned my_draw_text(const widestring &str, unsigned char *buf, double size, int xpos, int ypos, int r, int g, int b)
+unsigned my_draw_text(const widestring &str, unsigned char *buf, double size, const std::string &theme_element, int xpos, int ypos)
{
FT_GlyphSlot slot;
int x = 0;
+
+ int r = atoi(get_theme_config(theme_element, "red").c_str());
+ int g = atoi(get_theme_config(theme_element, "green").c_str());
+ int b = atoi(get_theme_config(theme_element, "blue").c_str());
+
+ // Find font faces.
+ std::vector<FT_Face> fonts;
+ std::vector<std::string> font_list = split(get_theme_config(theme_element, "font"), ';');
+ for (unsigned i = 0; i < font_list.size(); ++i) {
+ if (faces.count(font_list[i])) {
+ fonts.push_back(faces[font_list[i]]);
+ }
+ }
for (std::vector<FT_Face>::const_iterator i = fonts.begin(); i != fonts.end(); ++i) {
if (FT_Set_Char_Size(*i, 0, unsigned(size * 64.0), 96 * screen_width/LOGICAL_SCREEN_WIDTH, 96 * screen_height/LOGICAL_SCREEN_HEIGHT))
return x * LOGICAL_SCREEN_WIDTH / screen_width;
}
-void my_draw_text_deferred(std::vector<TextDefer> &td, const widestring &str, double size, int xpos, int ypos, int r, int g, int b, int rn, int gn, int bn)
+void my_draw_text_deferred(std::vector<TextDefer> &td, const widestring &str, double size, const std::string &theme_element, const std::string &fresh_theme_element, int xpos, int ypos)
{
TextDefer newtd;
newtd.str = str;
newtd.size = size;
newtd.xpos = xpos;
newtd.ypos = ypos;
- newtd.r = r;
- newtd.g = g;
- newtd.b = b;
- newtd.rn = rn;
- newtd.gn = gn;
- newtd.bn = bn;
+ newtd.theme_element = theme_element;
+ newtd.fresh_theme_element = fresh_theme_element;
td.push_back(newtd);
}
void draw_all_deferred_text(unsigned char *buf, std::vector<TextDefer> ¤t, std::vector<TextDefer> &old)
{
for (unsigned i = 0; i < current.size(); ++i) {
- int r, g, b;
+ std::string theme_element;
if (i < old.size() && current[i].str != old[i].str) {
// changed text
- r = current[i].rn;
- g = current[i].gn;
- b = current[i].bn;
+ theme_element = current[i].fresh_theme_element;
} else {
- r = current[i].r;
- g = current[i].g;
- b = current[i].b;
+ theme_element = current[i].theme_element;
}
- my_draw_text(current[i].str, buf, current[i].size, current[i].xpos, current[i].ypos, r, g, b);
+ my_draw_text(current[i].str, buf, current[i].size, theme_element, current[i].xpos, current[i].ypos);
}
}
#include <ft2build.h>
#include FT_FREETYPE_H
#include <vector>
+#include <string>
#include "widestring.h"
-#include "design.h"
struct TextDefer {
widestring str;
double size;
unsigned xpos, ypos;
- int r, g, b;
- int rn, gn, bn;
-
- bool changed;
+ std::string theme_element, fresh_theme_element;
};
void init_freetype();
void set_screen_size(unsigned width, unsigned height);
-unsigned my_draw_text(const widestring &str, unsigned char *buf, double size, int xpos = 0, int ypos = 0, int r = DATA_RED, int g = DATA_GREEN, int b = DATA_BLUE);
+unsigned my_draw_text(const widestring &str, unsigned char *buf, double size, const std::string &theme_element, int xpos = 0, int ypos = 0);
-// draw_all_deferred_text draws every string in current that is not the same in old, in red
-void my_draw_text_deferred(std::vector<TextDefer> &td, const widestring &str, double size, int xpos, int ypos, int r = DATA_RED, int g = DATA_GREEN, int b = DATA_BLUE, int rn = FRESH_DATA_RED, int gn = FRESH_DATA_GREEN, int bn = FRESH_DATA_BLUE);
+// draw_all_deferred_text draws every string in current that is not the same in old, with a different theme
+void my_draw_text_deferred(std::vector<TextDefer> &td, const widestring &str, double size, const std::string &theme_element, const std::string &fresh_theme_element, int xpos, int ypos);
void draw_all_deferred_text(unsigned char *buf, std::vector<TextDefer> ¤t, std::vector<TextDefer> &old);
#endif /* !defined(_FONTS_H) */
#include <map>
#include <assert.h>
-#include "design.h"
#include "resolution.h"
#include "groupscreen.h"
#include "fetch_group.h"
#include "fetch_needs_update.h"
#include "fetch_highscore.h"
#include "fonts.h"
+#include "theme.h"
GroupScreen::GroupScreen(pqxx::connection &conn, unsigned tournament, unsigned round, unsigned parallel, unsigned machine, unsigned num_machines, unsigned players_per_machine)
: tournament(tournament), round(round), parallel(parallel), machine(machine), num_machines(num_machines), players_per_machine(players_per_machine), scores_changed(conn, "scores"), conn(conn), valid(false)
}
}
- unsigned width = my_draw_text(heading, NULL, 40.0);
- my_draw_text_deferred(td, heading, 40.0, LOGICAL_SCREEN_WIDTH/2 - width/2, 60, MAIN_HEADING_RED, MAIN_HEADING_GREEN, MAIN_HEADING_BLUE);
+ unsigned width = my_draw_text(heading, NULL, 40.0, "mainheading");
+ my_draw_text_deferred(td, heading, 40.0, "mainheading", "mainheading", LOGICAL_SCREEN_WIDTH/2 - width/2, 60);
}
// make column headings from the first player's songs
unsigned x = 40 + colwidth[0];
for (std::vector<Score>::const_iterator i = group.players[0].scores.begin(); i != group.players[0].scores.end(); ++i, ++col) {
if (!i->chosen) {
- unsigned this_width = my_draw_text(i->song.short_title, NULL, 12.0);
- my_draw_text_deferred(td, i->song.short_title, 12.0, x + colwidth[col] / 2 - this_width / 2, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
+ unsigned this_width = my_draw_text(i->song.short_title, NULL, 12.0, "columnheading");
+ my_draw_text_deferred(td, i->song.short_title, 12.0, "columnheading", "columnheading", x + colwidth[col] / 2 - this_width / 2, 100);
}
x += colwidth[col] + 20;
}
if (num_scores > 1) {
- my_draw_text_deferred(td, "Total", 12.0, x + colwidth[num_scores + 1] / 2 - my_draw_text("Total", NULL, 12.0) / 2, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
+ unsigned this_width = my_draw_text("Total", NULL, 12.0, "columnheading");
+ my_draw_text_deferred(td, "Total", 12.0, "columnheading", "columnheading", x + colwidth[num_scores + 1] / 2 - this_width / 2, 100);
x += colwidth[num_scores + 1] + 20;
}
- my_draw_text_deferred(td, "Rank", 12.0, x + colwidth[num_scores + 2] / 2 - my_draw_text("Rank", NULL, 12.0) / 2, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
+ unsigned this_width = my_draw_text("Rank", NULL, 12.0, "columnheading");
+ my_draw_text_deferred(td, "Rank", 12.0, "columnheading", "columnheading", x + colwidth[num_scores + 2] / 2 - this_width / 2, 100);
}
// show all the players and the scores
void GroupScreen::draw_scores(std::vector<TextDefer> &td, const Group &group, unsigned min_player, const std::vector<unsigned> &colwidth)
{
- unsigned max_num_width = my_draw_text("8888", NULL, 22.0);
+ unsigned max_num_width = my_draw_text("8888", NULL, 22.0, "data");
unsigned num_scores = group.players[0].scores.size();
unsigned show_players = get_show_players(group);
unsigned y = (show_players <= 7) ? 140 : (140 - (show_players - 7) * 5);
if (m-1 < min_player)
continue;
- my_draw_text_deferred(td, i->nick, 18.0, 20, y, ROW_HEADING_RED, ROW_HEADING_GREEN, ROW_HEADING_BLUE);
+ my_draw_text_deferred(td, i->nick, 18.0, "rowheading", "rowheading", 20, y);
x = 40 + colwidth[0];
std::sprintf(text, "%u", j->score);
}
- unsigned this_width = my_draw_text(text, NULL, 22.0);
+ unsigned this_width = my_draw_text(text, NULL, 22.0, "data");
if (j->chosen) {
- my_draw_text_deferred(td, text, 22.0, x + max_num_width - this_width, y);
+ my_draw_text_deferred(td, text, 22.0, "data", "freshdata", x + max_num_width - this_width, y);
// draw the long name if we can, otherwise use the short one
- if (my_draw_text(j->song.title, NULL, 12.0) > (colwidth[col] - 10 - max_num_width)) {
- my_draw_text_deferred(td, j->song.short_title, 12.0, x + max_num_width + 10, y);
+ if (my_draw_text(j->song.title, NULL, 12.0, "data") > (colwidth[col] - 10 - max_num_width)) {
+ my_draw_text_deferred(td, j->song.short_title, 12.0, "data", "freshdata", x + max_num_width + 10, y);
} else {
- my_draw_text_deferred(td, j->song.title, 12.0, x + max_num_width + 10, y);
+ my_draw_text_deferred(td, j->song.title, 12.0, "data", "freshdata", x + max_num_width + 10, y);
}
} else {
- my_draw_text_deferred(td, text, 22.0, x + colwidth[col] / 2 - this_width / 2, y);
+ my_draw_text_deferred(td, text, 22.0, "data", "freshdata", x + colwidth[col] / 2 - this_width / 2, y);
}
x += colwidth[col] + 20;
}
char text[16];
std::sprintf(text, "%u", i->total);
- unsigned this_width = my_draw_text(text, NULL, 22.0);
- my_draw_text_deferred(td, text, 22.0, x + colwidth[num_scores + 1] / 2 - this_width / 2, y);
+ unsigned this_width = my_draw_text(text, NULL, 22.0, "data");
+ my_draw_text_deferred(td, text, 22.0, "data", "freshdata", x + colwidth[num_scores + 1] / 2 - this_width / 2, y);
x += colwidth[num_scores + 1] + 20;
}
void GroupScreen::find_column_widths(const Group &group, std::vector<unsigned> &colwidth)
{
unsigned num_scores;
- unsigned max_num_width = my_draw_text("8888", NULL, 22.0);
+ unsigned max_num_width = my_draw_text("8888", NULL, 22.0, "data");
unsigned sumcolwidth;
for (unsigned mode = 0; mode < 2; ++mode) {
if (colwidth.size() == 0)
colwidth.push_back(0);
- colwidth[0] = std::max(colwidth[0], my_draw_text(i->nick, NULL, 18.0));
+ colwidth[0] = std::max(colwidth[0], my_draw_text(i->nick, NULL, 18.0, "data"));
for (std::vector<Score>::const_iterator j = i->scores.begin(); j != i->scores.end(); ++j, ++col) {
if (colwidth.size() < col+1)
colwidth.push_back(0);
if (j->chosen) {
- colwidth[col] = std::max(colwidth[col], my_draw_text((mode == 0) ? j->song.title : j->song.short_title, NULL, 12.0) +
+ colwidth[col] = std::max(colwidth[col], my_draw_text((mode == 0) ? j->song.title : j->song.short_title, NULL, 12.0, "data") +
max_num_width + 10);
} else {
- colwidth[col] = std::max(colwidth[col], my_draw_text(j->song.short_title, NULL, 12.0));
+ colwidth[col] = std::max(colwidth[col], my_draw_text(j->song.short_title, NULL, 12.0, "data"));
colwidth[col] = std::max(colwidth[col], max_num_width);
}
}
}
if (num_scores > 1) {
- colwidth[num_scores + 1] = std::max(my_draw_text("Total", NULL, 12.0), max_num_width);
+ colwidth[num_scores + 1] = std::max(my_draw_text("Total", NULL, 12.0, "columnheading"), max_num_width);
}
- colwidth[num_scores + 2] = my_draw_text("Rank", NULL, 12.0);
+ colwidth[num_scores + 2] = my_draw_text("Rank", NULL, 12.0, "columnheading");
// if we're at long titles and that works, don't try the short ones
sumcolwidth = 0;
// OK, we have two players. Draw their nicks and the scores
widestring text = widestring("Next players: ") + next_player->nick + widestring(" and ") + other_player->nick;
- unsigned this_width = my_draw_text(text, NULL, 24.0);
- my_draw_text(text, buf, 24.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 420);
+ unsigned this_width = my_draw_text(text, NULL, 24.0, "data");
+ my_draw_text(text, buf, 24.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 420);
if (next_song->song.id != -1) {
- this_width = my_draw_text(next_song->song.title, NULL, 20.0);
- my_draw_text(next_song->song.title, buf, 20.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 457);
+ this_width = my_draw_text(next_song->song.title, NULL, 20.0, "data");
+ my_draw_text(next_song->song.title, buf, 20.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 457);
Highscore hs;
conn.perform(FetchHighscore(next_song->song.id, &hs));
if (hs.score != -1) {
text = widestring("High score: ") + widestring(pqxx::to_string(hs.score)) +
widestring(", by ") + hs.nick + widestring(" in ") + hs.tournament_name;
- this_width = my_draw_text(text, NULL, 16.0);
- my_draw_text(text, buf, 16.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 487);
+ this_width = my_draw_text(text, NULL, 16.0, "data");
+ my_draw_text(text, buf, 16.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 487);
}
}
}
const std::vector<unsigned> &max_score, const std::vector<unsigned> &min_score)
{
widestring text = widestring("Next player: ") + player.nick;
- unsigned this_width = my_draw_text(text, NULL, 24.0);
- my_draw_text(text, buf, 24.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 420);
+ unsigned this_width = my_draw_text(text, NULL, 24.0, "data");
+ my_draw_text(text, buf, 24.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 420);
if (song.song.id != -1) {
- this_width = my_draw_text(song.song.title, NULL, 20.0);
- my_draw_text(song.song.title, buf, 20.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 457);
+ this_width = my_draw_text(song.song.title, NULL, 20.0, "data");
+ my_draw_text(song.song.title, buf, 20.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 457);
Highscore hs;
conn.perform(FetchHighscore(song.song.id, &hs));
if (hs.score != -1) {
text = widestring("High score: ") + widestring(pqxx::to_string(hs.score)) +
widestring(", by ") + hs.nick + widestring(" in ") + hs.tournament_name;
- this_width = my_draw_text(text, NULL, 16.0);
- my_draw_text(text, buf, 16.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 487);
+ this_width = my_draw_text(text, NULL, 16.0, "data");
+ my_draw_text(text, buf, 16.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, 487);
}
}
if (lead_need > 1) {
text = widestring("Needs to lead: ") + widestring(pqxx::to_string(lead_need));
- this_width = my_draw_text(text, NULL, 18.0);
- my_draw_text(text, buf, 18.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
+ this_width = my_draw_text(text, NULL, 18.0, "data");
+ my_draw_text(text, buf, 18.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
y += 30;
}
if (win_need > 0) {
text = widestring("Needs to win: ") + widestring(pqxx::to_string(win_need));
- this_width = my_draw_text(text, NULL, 18.0);
- my_draw_text(text, buf, 18.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
+ this_width = my_draw_text(text, NULL, 18.0, "data");
+ my_draw_text(text, buf, 18.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
y += 30;
}
text = widestring("Needs to secure qualification: ") + widestring(pqxx::to_string(qual_need));
}
- this_width = my_draw_text(text, NULL, 18.0);
- my_draw_text(text, buf, 18.0, (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
+ this_width = my_draw_text(text, NULL, 18.0, "data");
+ my_draw_text(text, buf, 18.0, "data", (LOGICAL_SCREEN_WIDTH/2) - this_width/2, y);
y += 30;
}
conn.perform(FetchGroup(tournament, round, parallel, &group));
gettimeofday(&last_updated, NULL);
- unsigned char *ptr = buf;
- for (unsigned i = 0; i < width * height; ++i) {
- *ptr++ = BACKGROUND_BLUE;
- *ptr++ = BACKGROUND_GREEN;
- *ptr++ = BACKGROUND_RED;
- *ptr++ = 0;
- }
+ fill_background(buf, width, height);
std::vector<unsigned> colwidth;
if (num_scores <= 1)
x -= 20;
- unsigned this_width = my_draw_text(text, NULL, 22.0);
- my_draw_text_deferred(td, text, 22.0, x + colwidth[num_scores + 2] / 2 - this_width / 2, y);
+ unsigned this_width = my_draw_text(text, NULL, 22.0, "data");
+ my_draw_text_deferred(td, text, 22.0, "data", "freshdata", x + colwidth[num_scores + 2] / 2 - this_width / 2, y);
if (show_players > 7)
y += 40 - (show_players - 7) * 4;
/* NOTE: this class will _NOT_ handle resolution changes cleanly. You have been warned. :-) */
#include <cstring>
+#include <cstdlib>
#include "splitscreen.h"
-#include "design.h"
+#include "theme.h"
SplitScreen::SplitScreen(GenericScreen *s1, GenericScreen *s2, GenericScreen *s3, GenericScreen *s4)
: valid(false)
copy_subscreen(buf + width * (height/2) * 4 + (width/2) * 4, subbufs[3], width, height);
// make divider lines
+ int r = atoi(get_theme_config("divider", "red").c_str());
+ int g = atoi(get_theme_config("divider", "green").c_str());
+ int b = atoi(get_theme_config("divider", "blue").c_str());
+
unsigned char *ptr = buf + (height/2) * width * 4;
for (unsigned x = 0; x < width; ++x) {
- *ptr++ = DIVIDER_BLUE;
- *ptr++ = DIVIDER_GREEN;
- *ptr++ = DIVIDER_RED;
+ *ptr++ = b;
+ *ptr++ = g;
+ *ptr++ = r;
*ptr++ = 0;
}
ptr = buf + (width/2) * 4;
for (unsigned y = 0; y < height; ++y) {
- ptr[0] = DIVIDER_BLUE;
- ptr[1] = DIVIDER_GREEN;
- ptr[2] = DIVIDER_RED;
+ ptr[0] = b;
+ ptr[1] = g;
+ ptr[2] = r;
ptr[3] = 0;
ptr += width * 4;
--- /dev/null
+default.font=/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf;/usr/share/fonts/truetype/freefont/FreeSerif.ttf;arialuni.ttf
+default.red=255
+default.green=255
+default.blue=255
+background.red=0
+background.green=0
+background.blue=0
+mainheading.red=255
+mainheading.green=255
+mainheading.blue=255
+columnheading.red=255
+columnheading.green=255
+columnheading.blue=255
+freshcolumnheading.red=255
+freshcolumnheading.green=0
+freshcolumnheading.blue=0
+rowheading.red=255
+rowheading.green=255
+rowheading.blue=255
+data.red=255
+data.green=255
+data.blue=255
+freshdata.red=255
+freshdata.green=0
+freshdata.blue=0
+divider.red=127
+divider.green=127
+divider.blue=127
--- /dev/null
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <map>
+#include <string>
+#include <stdexcept>
+
+std::map<std::string, std::string> config;
+
+void init_theme()
+{
+ FILE *fp = fopen("theme.config", "rb");
+ if (fp == NULL)
+ throw std::runtime_error("Couldn't open theme.config.");
+
+ while (!feof(fp)) {
+ char buf[1024];
+ if (fgets(buf, 1024, fp) == NULL) {
+ break;
+ }
+
+ char *ptr = strchr(buf, '\n');
+ if (ptr != NULL)
+ *ptr = 0;
+
+ ptr = strchr(buf, '\r');
+ if (ptr != NULL)
+ *ptr = 0;
+
+ ptr = strchr(buf, '#');
+ if (ptr != NULL)
+ *ptr = 0;
+
+ int len = strlen(buf);
+ while (len > 0 && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) {
+ buf[--len] = 0;
+ }
+
+ if (len == 0) {
+ continue;
+ }
+
+ char key[1024], value[1024];
+ if (sscanf(buf, "%[^=] = %[^=]", key, value) != 2) {
+ fprintf(stderr, "Warning: Ignoring malformed line '%s'.\n", buf);
+ continue;
+ }
+
+ config.insert(std::make_pair(key, value));
+ }
+ fclose(fp);
+}
+
+std::string get_theme_config(const std::string &key, const std::string subkey)
+{
+ if (config.count(key + "." + subkey)) {
+ return config[key + "." + subkey];
+ }
+
+ return config["default." + subkey];
+}
+
+void fill_background(unsigned char *buf, unsigned width, unsigned height)
+{
+ int bg_r = atoi(get_theme_config("background", "red").c_str());
+ int bg_g = atoi(get_theme_config("background", "green").c_str());
+ int bg_b = atoi(get_theme_config("background", "blue").c_str());
+
+ unsigned char *ptr = buf;
+ for (unsigned i = 0; i < width * height; ++i) {
+ *ptr++ = bg_r;
+ *ptr++ = bg_g;
+ *ptr++ = bg_b;
+ *ptr++ = 0;
+ }
+}
--- /dev/null
+#ifndef THEME_H
+#define THEME_H 1
+
+#include <string>
+
+void init_theme();
+std::string get_theme_config(const std::string &key, const std::string subkey);
+void fill_background(unsigned char *buf, unsigned width, unsigned height);
+
+#endif
#include "resolution.h"
#include "top10scorescreen.h"
#include "fonts.h"
+#include "theme.h"
#define RANK_X 30
#define PLAYER_X 70
void Top10ScoreScreen::draw(unsigned char *buf, unsigned width, unsigned height)
{
scores_changed.reset_flag();
- unsigned char *ptr = buf;
- for (unsigned i = 0; i < width * height; ++i) {
- *ptr++ = BACKGROUND_BLUE;
- *ptr++ = BACKGROUND_GREEN;
- *ptr++ = BACKGROUND_RED;
- *ptr++ = 0;
- }
+ fill_background(buf, width, height);
set_screen_size(width, height);
// fetch the top 10 scores
conn.perform(FetchTopScoresForTournament(tournament, 10, &scores));
{
- unsigned width = my_draw_text("Today's top 10 scores", NULL, 40.0);
- my_draw_text("Today's top 10 scores", buf, 40.0, LOGICAL_SCREEN_WIDTH/2 - width/2, 60, MAIN_HEADING_RED, MAIN_HEADING_GREEN, MAIN_HEADING_BLUE);
+ unsigned width = my_draw_text("Today's top 10 scores", NULL, 40.0, "mainheading");
+ my_draw_text("Today's top 10 scores", buf, 40.0, "mainheading", LOGICAL_SCREEN_WIDTH/2 - width/2, 60);
}
// simple headings
- my_draw_text("Player", buf, 12.0, PLAYER_X, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
- my_draw_text("Song", buf, 12.0, SONG_X, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
- width = my_draw_text("Score", NULL, 12.0);
- my_draw_text("Score", buf, 12.0, SCORE_X - width/2, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
+ my_draw_text("Player", buf, 12.0, "columnheading", PLAYER_X, 100);
+ my_draw_text("Song", buf, 12.0, "columnheading", SONG_X, 100);
+ width = my_draw_text("Score", NULL, 12.0, "columnheading");
+ my_draw_text("Score", buf, 12.0, "columnheading", SCORE_X - width/2, 100);
unsigned row = 1, y = 140;
for (std::vector<TopScore>::const_iterator i = scores.begin(); i != scores.end(); ++i) {
char str[16];
- unsigned r = DATA_RED, g = DATA_GREEN, b = DATA_BLUE, rh = ROW_HEADING_RED, gh = ROW_HEADING_GREEN, bh = ROW_HEADING_BLUE;
+ std::string theme_element = "data";
+ std::string heading_theme_element = "rowheading";
// print new entries in red
if (seen_topscore.count(*i) == 0 && seen_topscore.size() > 0) {
- r = rh = FRESH_DATA_RED;
- g = gh = FRESH_DATA_GREEN;
- b = bh = FRESH_DATA_BLUE;
+ theme_element = "freshdata";
+ heading_theme_element = "freshrowheading";
}
std::sprintf(str, "%u", row++);
- unsigned width = my_draw_text(str, NULL, 24.0);
- my_draw_text(str, buf, 24.0, RANK_X - width/2, y, rh, gh, bh);
+ unsigned width = my_draw_text(str, NULL, 24.0, heading_theme_element);
+ my_draw_text(str, buf, 24.0, heading_theme_element, RANK_X - width/2, y);
- my_draw_text(i->nick, buf, 24.0, PLAYER_X, y, r, g, b);
+ my_draw_text(i->nick, buf, 24.0, theme_element, PLAYER_X, y);
- if (my_draw_text(i->title, NULL, 24.0) > SONG_MAX_WIDTH &&
+ if (my_draw_text(i->title, NULL, 24.0, theme_element) > SONG_MAX_WIDTH &&
!i->shorttitle.empty()) {
- my_draw_text(i->shorttitle, buf, 24.0, SONG_X, y, r, g, b);
+ my_draw_text(i->shorttitle, buf, 24.0, theme_element, SONG_X, y);
} else {
- my_draw_text(i->title, buf, 24.0, SONG_X, y, r, g, b);
+ my_draw_text(i->title, buf, 24.0, theme_element, SONG_X, y);
}
std::sprintf(str, "%u", i->score);
- width = my_draw_text(str, NULL, 24.0);
- my_draw_text(str, buf, 24.0, SCORE_X - width/2, y, r, g, b);
+ width = my_draw_text(str, NULL, 24.0, theme_element);
+ my_draw_text(str, buf, 24.0, theme_element, SCORE_X - width/2, y);
y += 40;
}
#include "resolution.h"
#include "top5chosenscreen.h"
#include "fonts.h"
+#include "theme.h"
#define RANK_X 30
#define SONG_X 70
void Top5ChosenScreen::draw(unsigned char *buf, unsigned width, unsigned height)
{
scores_changed.reset_flag();
- unsigned char *ptr = buf;
- for (unsigned i = 0; i < width * height; ++i) {
- *ptr++ = BACKGROUND_BLUE;
- *ptr++ = BACKGROUND_GREEN;
- *ptr++ = BACKGROUND_RED;
- *ptr++ = 0;
- }
+ fill_background(buf, width, height);
set_screen_size(width, height);
// fetch the top 5 chosen songs
conn.perform(FetchTopChosenSongsForTournament(tournament, 5, &scores));
{
- unsigned width = my_draw_text("Today's top 5 chosen songs", NULL, 40.0);
- my_draw_text("Today's top 5 chosen songs", buf, 40.0, LOGICAL_SCREEN_WIDTH/2 - width/2, 60, MAIN_HEADING_RED, MAIN_HEADING_GREEN, MAIN_HEADING_BLUE);
+ unsigned width = my_draw_text("Today's top 5 chosen songs", NULL, 40.0, "mainheading");
+ my_draw_text("Today's top 5 chosen songs", buf, 40.0, "mainheading", LOGICAL_SCREEN_WIDTH/2 - width/2, 60);
}
// simple headings
- my_draw_text("Song", buf, 12.0, SONG_X, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
- width = my_draw_text("Frequency", NULL, 12.0);
- my_draw_text("Frequency", buf, 12.0, FREQUENCY_X - width/2, 100, COLUMN_HEADING_RED, COLUMN_HEADING_GREEN, COLUMN_HEADING_BLUE);
+ my_draw_text("Song", buf, 12.0, "columnheading", SONG_X, 100);
+ width = my_draw_text("Frequency", NULL, 12.0, "columnheading");
+ my_draw_text("Frequency", buf, 12.0, "columnheading", FREQUENCY_X - width/2, 100);
unsigned row = 1, y = 140;
for (std::vector<TopChosen>::const_iterator i = scores.begin(); i != scores.end(); ++i) {
char str[16];
- unsigned r = DATA_RED, g = DATA_GREEN, b = DATA_BLUE, rh = ROW_HEADING_RED, gh = ROW_HEADING_GREEN, bh = ROW_HEADING_BLUE;
+ std::string theme_element = "data";
+ std::string heading_theme_element = "rowheading";
// print new entries in red
if (seen_topchosen.count(*i) == 0 && seen_topchosen.size() > 0) {
- r = rh = FRESH_DATA_RED;
- g = gh = FRESH_DATA_GREEN;
- b = bh = FRESH_DATA_BLUE;
+ theme_element = "freshdata";
+ heading_theme_element = "freshrowheading";
}
std::sprintf(str, "%u", row++);
- unsigned width = my_draw_text(str, NULL, 24.0);
- my_draw_text(str, buf, 24.0, RANK_X - width/2, y, rh, gh, bh);
+ unsigned width = my_draw_text(str, NULL, 24.0, heading_theme_element);
+ my_draw_text(str, buf, 24.0, heading_theme_element, RANK_X - width/2, y);
- if (my_draw_text(i->title, NULL, 24.0) > SONG_MAX_WIDTH) {
- my_draw_text(i->shorttitle, buf, 24.0, SONG_X, y, r, g, b);
+ if (my_draw_text(i->title, NULL, 24.0, theme_element) > SONG_MAX_WIDTH) {
+ my_draw_text(i->shorttitle, buf, 24.0, theme_element, SONG_X, y);
} else {
- my_draw_text(i->title, buf, 24.0, SONG_X, y, r, g, b);
+ my_draw_text(i->title, buf, 24.0, theme_element, SONG_X, y);
}
std::sprintf(str, "%u", i->frequency);
- width = my_draw_text(str, NULL, 24.0);
- my_draw_text(str, buf, 24.0, FREQUENCY_X - width/2, y, r, g, b);
+ width = my_draw_text(str, NULL, 24.0, theme_element);
+ my_draw_text(str, buf, 24.0, theme_element, FREQUENCY_X - width/2, y);
y += 40;
}