]> git.sesse.net Git - ccbs/commitdiff
Move the theming out to a runtime-read config file. Opens, among others, for differen...
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 18 Feb 2012 19:00:48 +0000 (20:00 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 18 Feb 2012 19:00:48 +0000 (20:00 +0100)
12 files changed:
bigscreen/Makefile
bigscreen/ccbs_bigscreen.cpp
bigscreen/design.h [deleted file]
bigscreen/fonts.cpp
bigscreen/fonts.h
bigscreen/groupscreen.cpp
bigscreen/splitscreen.cpp
bigscreen/theme.config [new file with mode: 0644]
bigscreen/theme.cpp [new file with mode: 0644]
bigscreen/theme.h [new file with mode: 0644]
bigscreen/top10scorescreen.cpp
bigscreen/top5chosenscreen.cpp

index b137750ecf6af1f979f453cc246d6baed7aab60f..c25f7e97879e19ce0550304cbb7dd69bd1646e27 100644 (file)
@@ -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
index ce65d043a349e7d74b3c8e8a3f0688fa6b2cd14e..05b32b89cec2b341630eeada909ee718bc0cd149 100644 (file)
@@ -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 (file)
index 6cffd32..0000000
+++ /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
index 86910a6b2757a4c27974274eecc2b874fde95eb4..0381157c687097dfe59642deb976b301b23c42a5 100644 (file)
@@ -1,35 +1,61 @@
 #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;
+               }
        }
 }
 
@@ -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<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))
@@ -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<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> &current, 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);
        }
 }
 
index 6950168432abb4f0d6973f91ef5ba6776d50b8d3..0174a7058a286f555deacbbf5da2491b86aa442b 100644 (file)
@@ -4,25 +4,22 @@
 #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> &current, std::vector<TextDefer> &old);
 
 #endif /* !defined(_FONTS_H) */
index 6639f4c057db0a83494ebe10e5c07963d9c1656e..ee646840601c6119f08fa0b8738cdc83bc3f0ba1 100644 (file)
@@ -3,7 +3,6 @@
 #include <map>
 #include <assert.h>
 
-#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<TextDefer> &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<TextDefer> &td, const Group &
        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);
@@ -101,7 +103,7 @@ void GroupScreen::draw_scores(std::vector<TextDefer> &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<TextDefer> &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<TextDefer> &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<TextDefer> &td, const Group &group, un
 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) {
@@ -164,17 +166,17 @@ void GroupScreen::find_column_widths(const Group &group, std::vector<unsigned> &
                        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);
                                }
                        }
@@ -188,9 +190,9 @@ void GroupScreen::find_column_widths(const Group &group, std::vector<unsigned> &
                }
        
                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<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));
@@ -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<unsigned> 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;
index b2939be755e2769eef5656bf0bd1e036a6388978..1a39df44efa472974dde8dc903bb6679b4627a35 100644 (file)
@@ -1,8 +1,9 @@
 /* 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)
@@ -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 (file)
index 0000000..25184df
--- /dev/null
@@ -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 (file)
index 0000000..008c37f
--- /dev/null
@@ -0,0 +1,76 @@
+#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;
+       }
+}
diff --git a/bigscreen/theme.h b/bigscreen/theme.h
new file mode 100644 (file)
index 0000000..1b0e33e
--- /dev/null
@@ -0,0 +1,10 @@
+#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 
index 5ff01a88f54db6f9689c52d928aa690d483b0dfb..2a52568355b0866544f37a5052b33af16842b07e 100644 (file)
@@ -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<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;
        }
index 3f50f82d121095e42c0bdc941f09b62564207133..57a54f0a20833e77634110c77ce3a50e5375c9d7 100644 (file)
@@ -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<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;
        }