From: Steinar H. Gunderson Date: Sat, 18 Feb 2012 19:00:48 +0000 (+0100) Subject: Move the theming out to a runtime-read config file. Opens, among others, for differen... X-Git-Url: https://git.sesse.net/?p=ccbs;a=commitdiff_plain;h=bbbf0f34d43aa3b6f43225fb6c2d45566a423ab1 Move the theming out to a runtime-read config file. Opens, among others, for different font lists per element type. --- diff --git a/bigscreen/Makefile b/bigscreen/Makefile index b137750..c25f7e9 100644 --- a/bigscreen/Makefile +++ b/bigscreen/Makefile @@ -11,7 +11,7 @@ CCBS_BIGSCREEN_SQL_OBJS=fetch_current_tournament.o fetch_list_of_active_groups.o 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 diff --git a/bigscreen/ccbs_bigscreen.cpp b/bigscreen/ccbs_bigscreen.cpp index ce65d04..05b32b8 100644 --- a/bigscreen/ccbs_bigscreen.cpp +++ b/bigscreen/ccbs_bigscreen.cpp @@ -13,6 +13,7 @@ #include "fetch_group.h" #include "fetch_auxilliary_screens.h" #include "fonts.h" +#include "theme.h" #include "groupscreen.h" #include "top10scorescreen.h" #include "top5chosenscreen.h" @@ -195,6 +196,7 @@ int main(int argc, char **argv) } 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"); diff --git a/bigscreen/design.h b/bigscreen/design.h deleted file mode 100644 index 6cffd32..0000000 --- a/bigscreen/design.h +++ /dev/null @@ -1,32 +0,0 @@ -#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 diff --git a/bigscreen/fonts.cpp b/bigscreen/fonts.cpp index 86910a6..0381157 100644 --- a/bigscreen/fonts.cpp +++ b/bigscreen/fonts.cpp @@ -1,35 +1,61 @@ #include #include #include +#include +#include #include "fonts.h" #include "resolution.h" +#include "theme.h" -std::vector fonts; +extern std::map config; +std::map faces; + +std::vector split(const std::string &str, char delim) +{ + std::vector 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::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 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; + } } } @@ -41,10 +67,23 @@ void set_screen_size(unsigned width, unsigned height) 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 fonts; + std::vector 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::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)) @@ -126,38 +165,30 @@ unsigned my_draw_text(const widestring &str, unsigned char *buf, double size, in return x * LOGICAL_SCREEN_WIDTH / screen_width; } -void my_draw_text_deferred(std::vector &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 &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 ¤t, std::vector &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); } } diff --git a/bigscreen/fonts.h b/bigscreen/fonts.h index 6950168..0174a70 100644 --- a/bigscreen/fonts.h +++ b/bigscreen/fonts.h @@ -4,25 +4,22 @@ #include #include FT_FREETYPE_H #include +#include #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 &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 &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 ¤t, std::vector &old); #endif /* !defined(_FONTS_H) */ diff --git a/bigscreen/groupscreen.cpp b/bigscreen/groupscreen.cpp index 6639f4c..ee64684 100644 --- a/bigscreen/groupscreen.cpp +++ b/bigscreen/groupscreen.cpp @@ -3,7 +3,6 @@ #include #include -#include "design.h" #include "resolution.h" #include "groupscreen.h" #include "fetch_group.h" @@ -12,6 +11,7 @@ #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) @@ -60,8 +60,8 @@ void GroupScreen::draw_main_heading(std::vector &td) } } - 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 @@ -73,23 +73,25 @@ void GroupScreen::draw_column_headings(std::vector &td, const Group & unsigned x = 40 + colwidth[0]; for (std::vector::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 &td, const Group &group, unsigned min_player, const std::vector &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); @@ -101,7 +103,7 @@ void GroupScreen::draw_scores(std::vector &td, const Group &group, un 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]; @@ -112,18 +114,18 @@ void GroupScreen::draw_scores(std::vector &td, const Group &group, un 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; } @@ -133,8 +135,8 @@ void GroupScreen::draw_scores(std::vector &td, const Group &group, un 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; } @@ -154,7 +156,7 @@ void GroupScreen::draw_scores(std::vector &td, const Group &group, un void GroupScreen::find_column_widths(const Group &group, std::vector &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) { @@ -164,17 +166,17 @@ void GroupScreen::find_column_widths(const Group &group, std::vector & 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::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); } } @@ -188,9 +190,9 @@ void GroupScreen::find_column_widths(const Group &group, std::vector & } 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; @@ -407,12 +409,12 @@ void GroupScreen::draw_next_up_versus(unsigned char *buf, const Group &group, // 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)); @@ -420,8 +422,8 @@ void GroupScreen::draw_next_up_versus(unsigned char *buf, const Group &group, 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); } } } @@ -431,12 +433,12 @@ void GroupScreen::draw_next_up_player(unsigned char *buf, const Group &group, co const std::vector &max_score, const std::vector &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)); @@ -444,8 +446,8 @@ void GroupScreen::draw_next_up_player(unsigned char *buf, const Group &group, co 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); } } @@ -540,8 +542,8 @@ void GroupScreen::draw_next_up_player(unsigned char *buf, const Group &group, co 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; } @@ -553,8 +555,8 @@ void GroupScreen::draw_next_up_player(unsigned char *buf, const Group &group, co 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; } @@ -573,8 +575,8 @@ void GroupScreen::draw_next_up_player(unsigned char *buf, const Group &group, co 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; } @@ -602,13 +604,7 @@ void GroupScreen::draw(unsigned char *buf, unsigned width, unsigned height) 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 colwidth; @@ -720,8 +716,8 @@ void GroupScreen::draw(unsigned char *buf, unsigned width, unsigned height) 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; diff --git a/bigscreen/splitscreen.cpp b/bigscreen/splitscreen.cpp index b2939be..1a39df4 100644 --- a/bigscreen/splitscreen.cpp +++ b/bigscreen/splitscreen.cpp @@ -1,8 +1,9 @@ /* NOTE: this class will _NOT_ handle resolution changes cleanly. You have been warned. :-) */ #include +#include #include "splitscreen.h" -#include "design.h" +#include "theme.h" SplitScreen::SplitScreen(GenericScreen *s1, GenericScreen *s2, GenericScreen *s3, GenericScreen *s4) : valid(false) @@ -51,19 +52,23 @@ void SplitScreen::draw(unsigned char *buf, unsigned width, unsigned height) 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; diff --git a/bigscreen/theme.config b/bigscreen/theme.config new file mode 100644 index 0000000..25184df --- /dev/null +++ b/bigscreen/theme.config @@ -0,0 +1,28 @@ +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 diff --git a/bigscreen/theme.cpp b/bigscreen/theme.cpp new file mode 100644 index 0000000..008c37f --- /dev/null +++ b/bigscreen/theme.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +std::map 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; + } +} diff --git a/bigscreen/theme.h b/bigscreen/theme.h new file mode 100644 index 0000000..1b0e33e --- /dev/null +++ b/bigscreen/theme.h @@ -0,0 +1,10 @@ +#ifndef THEME_H +#define THEME_H 1 + +#include + +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 diff --git a/bigscreen/top10scorescreen.cpp b/bigscreen/top10scorescreen.cpp index 5ff01a8..2a52568 100644 --- a/bigscreen/top10scorescreen.cpp +++ b/bigscreen/top10scorescreen.cpp @@ -4,6 +4,7 @@ #include "resolution.h" #include "top10scorescreen.h" #include "fonts.h" +#include "theme.h" #define RANK_X 30 #define PLAYER_X 70 @@ -45,13 +46,7 @@ bool Top10ScoreScreen::check_invalidated() 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 @@ -59,44 +54,44 @@ void Top10ScoreScreen::draw(unsigned char *buf, unsigned width, unsigned height) 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::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; } diff --git a/bigscreen/top5chosenscreen.cpp b/bigscreen/top5chosenscreen.cpp index 3f50f82..57a54f0 100644 --- a/bigscreen/top5chosenscreen.cpp +++ b/bigscreen/top5chosenscreen.cpp @@ -4,6 +4,7 @@ #include "resolution.h" #include "top5chosenscreen.h" #include "fonts.h" +#include "theme.h" #define RANK_X 30 #define SONG_X 70 @@ -44,13 +45,7 @@ bool Top5ChosenScreen::check_invalidated() 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 @@ -58,40 +53,40 @@ void Top5ChosenScreen::draw(unsigned char *buf, unsigned width, unsigned height) 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::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; }