← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/font_size-lua into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/font_size-lua into lp:widelands.

Commit message:
Except for scenario and win condition messages, define all font styles via Lua.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/font_size-lua/+merge/366938

The long-term goal is to allow user-defined styles.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/font_size-lua into lp:widelands.
=== modified file 'data/templates/default/init.lua'
--- data/templates/default/init.lua	2017-06-14 06:40:42 +0000
+++ data/templates/default/init.lua	2019-05-03 19:28:13 +0000
@@ -1,5 +1,6 @@
 -- This script defines a GUI style for Widelands. At the moment, we only
 -- support the default template.
+-- NOCOM update documentation
 -- So far, only background textures and colors can be defined, and they all have
 -- the format { image = filename, color = {r, g, b } }.
 
@@ -17,43 +18,222 @@
 local wui_green =  {3, 15, 0}
 local wui_brown =  {32, 19, 8}
 
+local fs_font_color = {255, 255, 0}
+local fs_font_face = "sans"
+local fs_font_size = 14
+
+local wui_font_color = {255, 255, 0}
+local wui_font_face = "sans"
+local wui_font_size = 14
+
+local default_ui_font = {
+   color = fs_font_color,
+   face = fs_font_face,
+   size = fs_font_size,
+   bold = true,
+   shadow = true
+}
+
+local default_button_fonts = {
+   enabled = default_ui_font,
+   disabled = {
+         color = {127, 127, 127},
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+   },
+}
+
+local productivity_colors = {
+   low = {187, 0, 0},
+   medium = {255, 225, 30},
+   high = {0, 187, 0},
+}
+
 -- These are the style definitions to be returned.
 -- Note: you have to keep all the keys intact, or Widelands will not be happy.
 return {
-   -- Button backgrounds
+   -- Automatic resizing of fonts to make them fit onto buttons etc.
+   -- won't go below this size
+   minimum_font_size = 10,
+   minimap_icon_frame = fs_font_color,
+
+   -- Buttons
    buttons = {
       -- Buttons used in Fullscreen menus
       fsmenu = {
          -- Main menu ("Single Player", "Watch Replay", ...)
-         menu = { image = fs_button, color = fs_blue },
+         menu = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_blue,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_blue,
+               }
+            }
+         },
          -- Primary user selection ("OK", ...)
-         primary = { image = fs_button, color = fs_green },
+         primary = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_green,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_green,
+               }
+            }
+         },
          -- Secondary user selection ("Cancel", "Delete", selection buttons, ...)
-         secondary = { image = fs_button, color = fs_brown },
+         secondary = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_brown,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = fs_button,
+                  color = fs_brown,
+               }
+            }
+         },
       },
       -- Buttons used in-game and in the editor
       wui = {
          -- Main menu ("Exit Game"), Building Windows, selection buttons, ...
-         menu = { image = wui_button, color = wui_light },
+         menu = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_light,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_light,
+               }
+            }
+         },
          -- Primary user selection ("OK", attack, ...)
-         primary = { image = wui_button, color = wui_green },
+         primary = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_green,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_green,
+               }
+            }
+         },
          -- Secondary user selection ("Cancel", "Delete", ...)
-         secondary = { image = wui_button, color = wui_brown },
+         secondary = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_brown,
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = wui_button,
+                  color = wui_brown,
+               }
+            }
+         },
          -- Building buttons on fieldaction and building statistics need to be
          -- transparent in order to match the background of the tab panel.
-         building_stats = { image = "", color = {0, 0, 0} },
+         building_stats = {
+            enabled = {
+               font = default_button_fonts["enabled"],
+               background = {
+                  image = "",
+                  color = {0, 0, 0},
+               }
+            },
+            disabled = {
+               font = default_button_fonts["disabled"],
+               background = {
+                  image = "",
+                  color = {0, 0, 0},
+               }
+            }
+         },
       }
    },
    -- Slider cursors (Sound control, attack, statistics, ...)
    sliders = {
       fsmenu = {
-         menu = { image = fs_button, color = fs_blue },
+         menu = {
+            background = {
+               image = fs_button,
+               color = fs_blue,
+            },
+            font = {
+               color = fs_font_color,
+               face = "condensed",
+               size = 11,
+               bold = true,
+               shadow = true
+            }
+         }
       },
       wui = {
          -- Sound Options, Statistics
-         light = { image = wui_button, color = wui_brown },
+         light = {
+            background = {
+               image = wui_button,
+               color = wui_brown,
+            },
+            font = {
+               color = fs_font_color,
+               face = "condensed",
+               size = 11,
+               bold = true,
+               shadow = true
+            }
+         },
          -- Fieldaction (attack)
-         dark = { image = wui_button, color = wui_green },
+         dark = {
+            background = {
+               image = wui_button,
+               color = wui_green,
+            },
+            font = {
+               color = fs_font_color,
+               face = "condensed",
+               size = 11,
+               bold = true,
+               shadow = true
+            }
+         },
       }
    },
    -- Background for tab panels
@@ -74,11 +254,31 @@
    -- Used both for one-line and multiline edit boxes
    editboxes = {
       fsmenu = {
-         menu = { image = fs_button, color = fs_green },
+         background = {
+            image = fs_button,
+            color = fs_green,
+            margin = 4
+         },
+         font = {
+            color = fs_font_color,
+            face = fs_font_face,
+            size = fs_font_size,
+            shadow = true
+         },
       },
       wui = {
-         menu = { image = wui_button, color = wui_brown },
-      }
+         background = {
+            image = wui_button,
+            color = wui_brown,
+            margin = 2,
+         },
+         font = {
+            color = wui_font_color,
+            face = wui_font_face,
+            size = wui_font_size,
+            shadow = true
+         },
+      },
    },
    -- Background for dropdown menus
    dropdowns = {
@@ -97,5 +297,360 @@
       wui = {
          menu = { image = wui_button, color = wui_brown },
       }
-   }
+   },
+
+   -- In-game statistics plots
+   statistics_plot = {
+      fonts = {
+         x_tick = {
+            color = { 255, 0, 0 },
+            face = "condensed",
+            size = 13,
+         },
+         y_min_value = {
+            color = { 125, 0, 0 },
+            face = "condensed",
+            size = 13,
+         },
+         y_max_value = {
+            color = { 60, 125, 0 },
+            face = "condensed",
+            size = 13,
+         },
+      },
+      colors = {
+         axis_line = { 0, 0, 0 },
+         zero_line = { 255, 255, 255 },
+      }
+   },
+
+   -- Map census and statistics, and building statistics window
+   building_statistics = {
+      census_font = {
+         color = wui_font_color, -- Default color
+         face = "condensed",
+         size = wui_font_size,
+         bold = true,
+         shadow = true
+      },
+      statistics_font = {
+         color = wui_font_color, -- Default color
+         face = "condensed",
+         size = wui_font_size,
+         bold = true,
+         shadow = true
+      },
+      -- Building statistics window
+      statistics_window = {
+         fonts = {
+            button_font = {
+               color = wui_font_color, -- Default color
+               face = "condensed",
+               size = 12, -- Do not make this bigger - the UI element size is still hard-coded.
+               bold = true,
+               shadow = true
+            },
+            details_font = {
+               color = wui_font_color, -- Default color
+               face = "sans",
+               size = 12, -- Do not make this bigger - the UI element size is still hard-coded.
+               bold = true,
+               shadow = true
+            },
+         },
+         editbox_margin = 0
+      },
+      colors = {
+         construction = { 163, 144, 19 },
+         neutral = { 255, 250, 170 },
+         low = productivity_colors["low"],
+         medium = productivity_colors["medium"],
+         high = productivity_colors["high"],
+      }
+   },
+
+   progressbar = {
+      fsmenu = {
+         font = {
+            color = { 128, 128, 255 },
+            face = fs_font_face,
+            size = fs_font_size,
+            bold = true,
+            shadow = true
+         },
+         background_colors = {
+            low = { 64, 64, 0 }, -- Unused
+            medium = { 64, 64, 0 },
+            high = { 64, 64, 0 }, -- Unused
+         }
+      },
+      wui = {
+         font = {
+            color = {255, 250, 170},
+            face = wui_font_face,
+            size = wui_font_size,
+            bold = true,
+            shadow = true
+         },
+         background_colors = {
+            low = productivity_colors["low"],
+            medium = productivity_colors["medium"],
+            high = productivity_colors["high"],
+         }
+      }
+   },
+
+   tables = {
+      fsmenu = {
+         enabled = {
+            color = fs_font_color,
+            face = fs_font_face,
+            size = fs_font_size,
+            bold = true,
+            shadow = true
+         },
+         disabled = {
+            color = {127, 127, 127},
+            face = fs_font_face,
+            size = fs_font_size,
+            bold = true,
+            shadow = true
+         }
+      },
+      wui = {
+         enabled = {
+            color = fs_font_color,
+            face = fs_font_face,
+            size = fs_font_size,
+            bold = true,
+            shadow = true
+         },
+         disabled = {
+            color = {127, 127, 127},
+            face = fs_font_face,
+            size = fs_font_size,
+            bold = true,
+            shadow = true
+         }
+      },
+   },
+
+   wareinfo = {
+      -- TODO(GunChleoc): This design is ugly.
+      -- Group stuff more logically once everything has been styled.
+      normal = {
+         fonts = {
+            header = {
+               color = wui_font_color,
+               face = "sans",
+               size = 11,
+            },
+            info = {
+               color = wui_font_color,
+               face = "condensed",
+               size = 10,
+            },
+         },
+         colors = {
+            icon_frame = { 69, 69, 69 },
+            icon_background = { 69, 69, 69 },
+            info_background = { 0, 0, 0 },
+         },
+         icon_background_image = "images/wui/ware_list_bg.png",
+      },
+      highlight = {
+         fonts = {
+            header = {
+               color = wui_font_color,
+               face = "sans",
+               size = 11,
+            },
+            info = {
+               color = wui_font_color,
+               face = "condensed",
+               size = 10,
+            },
+         },
+         colors = {
+            icon_frame = {255, 255, 0},
+            icon_background = {69, 69, 69},
+            info_background = {0, 0, 0},
+         },
+         icon_background_image = "images/wui/ware_list_bg_selected.png",
+      }
+   },
+
+   -- Font styles. Required parameters are:
+   -- * face: string
+   -- * color: table with r, g, b values as int
+   -- * size; int
+   -- Optional bools are: bold, italic, underline, shadow
+   fonts = {
+      -- Basic chat message text color
+      chat_message = {
+         color = wui_font_color,
+         face = "serif",
+         size = fs_font_size,
+         shadow = true,
+      },
+      -- Basic chat message text color
+      chat_timestamp = {
+         color = { 51, 255, 51 },
+         face = "serif",
+         size = 9,
+         shadow = true,
+      },
+      -- Chat for private messages
+      chat_whisper = {
+         color = { 238, 238, 238 },
+         face = "serif",
+         size = fs_font_size,
+         italic = true,
+         shadow = true,
+      },
+      -- Chat playername highlight
+      chat_playername = {
+         color = { 255, 255, 255 },
+         face = "serif",
+         size = fs_font_size,
+         bold = true,
+         underline = true,
+         shadow = true,
+      },
+      -- Chat log messages color. Also doubles as spectator playercolor for chat messages.
+      chat_server = {
+         color = { 221, 221, 221 },
+         face = "serif",
+         size = fs_font_size,
+         bold = true,
+         shadow = true,
+      },
+      -- Intro screen
+      fsmenu_intro = {
+         color = { 192, 192, 128 },
+         face = fs_font_face,
+         size = 16,
+         bold = true,
+         shadow = true
+      },
+      -- Displayed in the loading screens
+      fsmenu_gametip = {
+         color = { 33, 33, 27 },
+         face = "serif",
+         size = 16,
+      },
+      -- Game and Map info panels
+      fsmenu_info_panel_heading = {
+         color = { 255, 255, 0 },
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+      },
+      fsmenu_info_panel_paragraph = {
+         color = { 209, 209, 209 },
+         face = fs_font_face,
+         size = fs_font_size,
+         shadow = true
+      },
+      -- Internet lobby and launch game
+      fsmenu_game_setup_headings = {
+         color = { 0, 255, 0 },
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+      },
+      fsmenu_game_setup_mapname = {
+         color = { 255, 255, 127 },
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+      },
+      -- List IRC clients in the internet lobby
+      fsmenu_game_setup_irc_client = {
+         color = { 221, 221, 221  },
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+      },
+      -- Page titles. Also used in game summary TODO(GunChleoc): Refactor game summary
+      fsmenu_title = {
+         color = fs_font_color,
+         face = fs_font_face,
+         size = 22,
+         bold = true,
+         shadow = true
+      },
+      -- Make font a bit smaller so the link will fit at 800x600 resolution.
+      fsmenu_translation_info = {
+         color = fs_font_color,
+         face = fs_font_face,
+         size = fs_font_size - 2,
+         bold = true,
+         shadow = true
+      },
+
+      -- Textarea default style, also used for sliders, checkboxes, both in fsmenu and wui ...
+      label = default_ui_font,
+      tooltip = {
+         color = fs_font_color,
+         face = fs_font_face,
+         size = 14,
+         bold = false,
+      },
+      tooltip_header = {
+         color = fs_font_color,
+         face = fs_font_face,
+         size = 16,
+         bold = true,
+      },
+      warning = {
+         color = {255, 22, 22},
+         face = fs_font_face,
+         size = fs_font_size,
+         bold = true,
+         shadow = true
+      },
+
+      wui_info_panel_heading = {
+         color = { 209, 209, 209 },
+         face = wui_font_face,
+         size = wui_font_size,
+         bold = true,
+      },
+      wui_info_panel_paragraph = {
+         color = { 255, 255, 0 },
+         face = wui_font_face,
+         size = wui_font_size,
+      },
+      -- Messages
+      wui_message_heading = {
+         color = { 209, 209, 209 },
+         face = wui_font_face,
+         size = 18,
+         bold = true,
+      },
+      wui_message_paragraph = {
+         color = { 255, 255, 0 },
+         face = wui_font_face,
+         size = 12,
+      },
+      wui_window_title = {
+         color = fs_font_color,
+         face = wui_font_face,
+         size = 13,
+         bold=true,
+         shadow=true,
+      },
+      wui_game_speed_and_coordinates = {
+         color = wui_font_color,
+         face = "condensed",
+         size = wui_font_size,
+         bold = true,
+         shadow = true
+      },
+   },
 }

=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt	2018-09-06 09:06:55 +0000
+++ src/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -107,7 +107,6 @@
     graphic
     graphic_fonthandler
     graphic_text
-    graphic_text_constants
     helper
     io_filesystem
     logic

=== modified file 'src/editor/tools/info_tool.cc'
--- src/editor/tools/info_tool.cc	2019-04-09 16:43:49 +0000
+++ src/editor/tools/info_tool.cc	2019-05-03 19:28:13 +0000
@@ -39,7 +39,8 @@
                                           EditorActionArgs* /* args */,
                                           Widelands::Map* map) {
 
-	static constexpr int kListFontsize = UI_FONT_SIZE_MESSAGE;
+	constexpr UI::FontStyle font_style = UI::FontStyle::kWuiInfoPanelParagraph;
+
 	parent.stop_painting();
 
 	UI::Window* const w =
@@ -53,7 +54,7 @@
 	std::string buf = as_heading(_("Node"), UI::PanelStyle::kWui, true);
 	buf += as_listitem(
 	   (boost::format(_("Coordinates: (%1$i, %2$i)")) % center.node.x % center.node.y).str(),
-	   kListFontsize);
+	   font_style);
 
 	std::vector<std::string> caps_strings;
 	Widelands::NodeCaps const caps = f.nodecaps();
@@ -100,15 +101,15 @@
 	buf += as_listitem((boost::format(_("Caps: %s")) %
 	                    i18n::localize_list(caps_strings, i18n::ConcatenateWith::COMMA))
 	                      .str(),
-	                   kListFontsize);
+	                   font_style);
 
 	if (f.get_owned_by() > 0) {
 		buf += as_listitem(
 		   (boost::format(_("Owned by: Player %u")) % static_cast<unsigned int>(f.get_owned_by()))
 		      .str(),
-		   kListFontsize);
+		   font_style);
 	} else {
-		buf += as_listitem(_("Owned by: —"), kListFontsize);
+		buf += as_listitem(_("Owned by: —"), font_style);
 	}
 
 	// *** Terrain info
@@ -119,7 +120,7 @@
 	   center.triangle.t == Widelands::TriangleIndex::D ? tf.terrain_d() : tf.terrain_r());
 
 	buf += as_listitem(
-	   (boost::format(pgettext("terrain_name", "Name: %s")) % ter.descname()).str(), kListFontsize);
+	   (boost::format(pgettext("terrain_name", "Name: %s")) % ter.descname()).str(), font_style);
 
 	std::vector<std::string> terrain_is_strings;
 	for (const Widelands::TerrainDescription::Type& terrain_type : ter.get_types()) {
@@ -132,10 +133,10 @@
 	   (boost::format(_("Is: %s")) %
 	    i18n::localize_list(terrain_is_strings, i18n::ConcatenateWith::AMPERSAND))
 	      .str(),
-	   kListFontsize);
+	   font_style);
 	buf += as_listitem(
 	   (boost::format(_("Editor Category: %s")) % ter.editor_category()->descname()).str(),
-	   kListFontsize);
+	   font_style);
 
 	// *** Map Object info
 	const Widelands::BaseImmovable* immovable = f.get_immovable();
@@ -146,7 +147,7 @@
 		if (immovable) {
 			buf +=
 			   as_listitem((boost::format(_("Immovable: %s")) % immovable->descr().descname()).str(),
-			               kListFontsize);
+			               font_style);
 		}
 
 		if (bob) {
@@ -179,19 +180,19 @@
 				buf += as_listitem((boost::format(_("Animals: %s")) %
 				                    i18n::localize_list(critternames, i18n::ConcatenateWith::COMMA))
 				                      .str(),
-				                   kListFontsize);
+				                   font_style);
 			}
 			if (!workernames.empty()) {
 				buf += as_listitem((boost::format(_("Workers: %s")) %
 				                    i18n::localize_list(workernames, i18n::ConcatenateWith::COMMA))
 				                      .str(),
-				                   kListFontsize);
+				                   font_style);
 			}
 			if (!shipnames.empty()) {
 				buf += as_listitem((boost::format(_("Ships: %s")) %
 				                    i18n::localize_list(shipnames, i18n::ConcatenateWith::COMMA))
 				                      .str(),
-				                   kListFontsize);
+				                   font_style);
 			}
 		}
 	}
@@ -204,28 +205,28 @@
 		   (boost::format(pgettext("resources", "%1%x %2%")) % static_cast<unsigned int>(ramount) %
 		    world.get_resource(f.get_resources())->descname())
 		      .str(),
-		   kListFontsize);
+		   font_style);
 	}
 
 	// *** Map info
 	buf += as_heading(_("Map"), UI::PanelStyle::kWui);
 	buf += as_listitem(
-	   (boost::format(pgettext("map_name", "Name: %s")) % map->get_name()).str(), kListFontsize);
+	   (boost::format(pgettext("map_name", "Name: %s")) % map->get_name()).str(), font_style);
 	buf += as_listitem(
 	   (boost::format(_("Size: %1% x %2%")) % map->get_width() % map->get_height()).str(),
-	   kListFontsize);
+	   font_style);
 
 	if (map->get_nrplayers() > 0) {
 		buf += as_listitem(
 		   (boost::format(_("Players: %u")) % static_cast<unsigned int>(map->get_nrplayers())).str(),
-		   kListFontsize);
+		   font_style);
 	} else {
-		buf += as_listitem(_("Players: –"), kListFontsize);
+		buf += as_listitem(_("Players: –"), font_style);
 	}
 
-	buf += as_listitem((boost::format(_("Author: %s")) % map->get_author()).str(), kListFontsize);
+	buf += as_listitem((boost::format(_("Author: %s")) % map->get_author()).str(), font_style);
 	buf += as_listitem(
-	   (boost::format(_("Description: %s")) % map->get_description()).str(), kListFontsize);
+	   (boost::format(_("Description: %s")) % map->get_description()).str(), font_style);
 
 	multiline_textarea->set_text(as_richtext(buf));
 

=== modified file 'src/editor/ui_menus/main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/main_menu_load_or_save_map.cc	2019-04-18 16:50:35 +0000
+++ src/editor/ui_menus/main_menu_load_or_save_map.cc	2019-05-03 19:28:13 +0000
@@ -55,7 +55,7 @@
                   get_inner_w() - right_column_x_ - padding_,
                   tableh_,
                   UI::PanelStyle::kWui),
-     directory_info_(this, padding_, get_inner_h() - 2 * buth_ - 4 * padding_),
+     directory_info_(this, padding_, get_inner_h() - 2 * buth_ - 4 * padding_, 0, 0),
      ok_(this,
          "ok",
          UI::g_fh->fontset()->is_rtl() ? get_inner_w() / 2 - butw_ - padding_ :

=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc	2019-05-03 19:28:13 +0000
@@ -28,6 +28,7 @@
 #include "editor/editorinteractive.h"
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
+#include "graphic/text_layout.h"
 #include "logic/map.h"
 #include "ui_basic/editbox.h"
 #include "ui_basic/multilineeditbox.h"
@@ -45,7 +46,7 @@
    : UI::Window(&parent, "map_options", 0, 0, 350, parent.get_inner_h() - 80, _("Map Options")),
      padding_(4),
      indent_(10),
-     labelh_(text_height() + 4),
+     labelh_(text_height(UI::FontStyle::kLabel) + 4),
      checkbox_space_(25),
      butw_((get_inner_w() - 3 * padding_) / 2),
      max_w_(get_inner_w() - 2 * padding_),
@@ -72,8 +73,8 @@
      tags_box_(&tabs_, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
      teams_box_(&tabs_, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
 
-     name_(&main_box_, 0, 0, max_w_, 0, 2, UI::PanelStyle::kWui),
-     author_(&main_box_, 0, 0, max_w_, 0, 2, UI::PanelStyle::kWui),
+     name_(&main_box_, 0, 0, max_w_, UI::PanelStyle::kWui),
+     author_(&main_box_, 0, 0, max_w_, UI::PanelStyle::kWui),
      size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),
 
      teams_list_(

=== modified file 'src/editor/ui_menus/main_menu_random_map.cc'
--- src/editor/ui_menus/main_menu_random_map.cc	2019-04-24 07:09:29 +0000
+++ src/editor/ui_menus/main_menu_random_map.cc	2019-05-03 19:28:13 +0000
@@ -32,6 +32,7 @@
 #include "editor/editorinteractive.h"
 #include "editor/map_generator.h"
 #include "graphic/font_handler.h"
+#include "graphic/text_layout.h"
 #include "logic/editor_game_base.h"
 #include "logic/map.h"
 #include "logic/map_objects/world/world.h"
@@ -51,7 +52,7 @@
      // UI elements
      margin_(4),
      box_width_(get_inner_w() - 2 * margin_),
-     label_height_(text_height() + 2),
+     label_height_(text_height(UI::FontStyle::kLabel) + 2),
      box_(this, margin_, margin_, UI::Box::Vertical, 0, 0, margin_),
      // Size
      width_(&box_,
@@ -108,8 +109,8 @@
      resource_amount_(2),
      world_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
      resources_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
-     world_label_(&world_box_, 0, 0, _("Climate:")),
-     resources_label_(&resources_box_, 0, 0, _("Resources:")),
+     world_label_(&world_box_, 0, 0, 0, 0, _("Climate:")),
+     resources_label_(&resources_box_, 0, 0, 0, 0, _("Resources:")),
      world_(&world_box_,
             "world",
             0,
@@ -171,7 +172,7 @@
                 UI::SpinBox::Type::kSmall,
                 5),
      mountains_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
-     mountains_label_(&mountains_box_, 0, 0, _("Mountains:")),
+     mountains_label_(&mountains_box_, 0, 0, 0, 0, _("Mountains:")),
      mountains_(&mountains_box_,
                 0,
                 0,
@@ -182,22 +183,18 @@
      island_mode_(&box_, Vector2i::zero(), _("Island mode")),
      // Geeky stuff
      map_number_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
-     map_number_label_(&map_number_box_, 0, 0, _("Random number:")),
+     map_number_label_(&map_number_box_, 0, 0, 0, 0, _("Random number:")),
      map_number_edit_(&map_number_box_,
                       0,
                       0,
                       box_width_ - 2 * margin_ - map_number_label_.get_w(),
-                      0,
-                      2,
                       UI::PanelStyle::kWui),
      map_id_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
-     map_id_label_(&map_id_box_, 0, 0, _("Map ID:")),
+     map_id_label_(&map_id_box_, 0, 0, 0, 0, _("Map ID:")),
      map_id_edit_(&map_id_box_,
                   0,
                   0,
                   box_width_ - 2 * margin_ - map_id_label_.get_w(),
-                  0,
-                  2,
                   UI::PanelStyle::kWui),
      // Buttons
      button_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),

=== modified file 'src/editor/ui_menus/main_menu_save_map.cc'
--- src/editor/ui_menus/main_menu_save_map.cc	2019-03-18 21:10:56 +0000
+++ src/editor/ui_menus/main_menu_save_map.cc	2019-05-03 19:28:13 +0000
@@ -83,7 +83,7 @@
 
 	editbox_ = new UI::EditBox(
 	   this, editbox_label_.get_x() + editbox_label_.get_w() + padding_, editbox_label_.get_y(),
-	   tablew_ - editbox_label_.get_w() - padding_ + 1, buth_, 2, UI::PanelStyle::kWui);
+	   tablew_ - editbox_label_.get_w() - padding_ + 1, UI::PanelStyle::kWui);
 	editbox_->set_text(parent.egbase().map().get_name());
 
 	editbox_->changed.connect(boost::bind(&MainMenuSaveMap::edit_box_changed, this));

=== modified file 'src/editor/ui_menus/main_menu_save_map_make_directory.cc'
--- src/editor/ui_menus/main_menu_save_map_make_directory.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_save_map_make_directory.cc	2019-05-03 19:28:13 +0000
@@ -41,7 +41,7 @@
            get_inner_h() - 3 * padding_ - buth_,
            padding_ / 2),
      label_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, buth_, _("Enter Directory Name:")),
-     edit_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, 0, 4, UI::PanelStyle::kWui),
+     edit_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, UI::PanelStyle::kWui),
      ok_button_(this,
                 "ok",
                 UI::g_fh->fontset()->is_rtl() ? padding_ : get_inner_w() - butw_ - padding_,

=== modified file 'src/editor/ui_menus/player_menu.cc'
--- src/editor/ui_menus/player_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/player_menu.cc	2019-05-03 19:28:13 +0000
@@ -160,13 +160,11 @@
 		UI::Box* row = new UI::Box(&box_, 0, 0, UI::Box::Horizontal);
 
 		// Name
-		UI::EditBox* plr_name = new UI::EditBox(row, 0, 0, 0, 0, kMargin, UI::PanelStyle::kWui);
+		UI::EditBox* plr_name = new UI::EditBox(row, 0, 0, 0, UI::PanelStyle::kWui);
 		if (map_has_player) {
 			plr_name->set_text(map.get_scenario_player_name(p));
 		}
 		plr_name->changed.connect(boost::bind(&EditorPlayerMenu::name_changed, this, p - 1));
-		row->add(plr_name, UI::Box::Resizing::kFillSpace);
-		row->add_space(kMargin);
 
 		// Tribe
 		UI::Dropdown<std::string>* plr_tribe =
@@ -189,8 +187,6 @@
 		      "");
 		plr_tribe->selected.connect(
 		   boost::bind(&EditorPlayerMenu::player_tribe_clicked, boost::ref(*this), p - 1));
-		row->add(plr_tribe);
-		row->add_space(kMargin);
 
 		// Starting position
 		const Image* player_image =
@@ -204,8 +200,17 @@
 		   player_image, _("Set this player’s starting position"));
 		plr_position->sigclicked.connect(
 		   boost::bind(&EditorPlayerMenu::set_starting_pos_clicked, boost::ref(*this), p));
+
+		// Add the elements to the row
+		row->add(plr_name, UI::Box::Resizing::kFillSpace);
+		row->add_space(kMargin);
+
+		row->add(plr_tribe);
+		row->add_space(kMargin);
+
 		row->add(plr_position);
 
+		// Add the row itself
 		box_.add(row, UI::Box::Resizing::kFullSize);
 		box_.add_space(kMargin);
 		row->set_visible(map_has_player);
@@ -227,7 +232,7 @@
 	assert(!rows_.empty());
 	const Widelands::PlayerNumber nr_players = eia().egbase().map().get_nrplayers();
 	box_.set_size(310, no_of_players_.get_h() + kMargin +
-	                      nr_players * (rows_.front()->tribe->get_h() + kMargin));
+	                      nr_players * (rows_.front()->name->get_h() + kMargin));
 	set_inner_size(box_.get_w() + 2 * kMargin, box_.get_h() + 2 * kMargin);
 }
 
@@ -319,10 +324,10 @@
 	// Signal player position states via button states
 	iterate_player_numbers(pn, map->get_nrplayers()) {
 		if (pn == row) {
-			rows_.at(pn - 1)->position->set_background_style(UI::ButtonStyle::kWuiPrimary);
+			rows_.at(pn - 1)->position->set_style(UI::ButtonStyle::kWuiPrimary);
 			rows_.at(pn - 1)->position->set_perm_pressed(true);
 		} else {
-			rows_.at(pn - 1)->position->set_background_style(UI::ButtonStyle::kWuiSecondary);
+			rows_.at(pn - 1)->position->set_style(UI::ButtonStyle::kWuiSecondary);
 			rows_.at(pn - 1)->position->set_perm_pressed(map->get_starting_pos(pn) !=
 			                                             Widelands::Coords::null());
 		}

=== modified file 'src/editor/ui_menus/tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/tool_change_resources_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_change_resources_options_menu.cc	2019-05-03 19:28:13 +0000
@@ -74,7 +74,7 @@
              UI::SpinBox::Units::kNone,
              UI::SpinBox::Type::kSmall),
      resources_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, 1),
-     cur_selection_(&box_, 0, 0, "", UI::Align::kCenter) {
+     cur_selection_(&box_, 0, 0, 0, 0, "", UI::Align::kCenter) {
 	// Configure spin boxes
 	change_by_.set_tooltip(
 	   /** TRANSLATORS: Editor change rseources access keys. **/

=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt	2019-04-25 06:31:33 +0000
+++ src/graphic/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -1,3 +1,4 @@
+add_subdirectory(styles)
 add_subdirectory(text)
 
 # TODO(sirver): Separate this directory into a base directory and one
@@ -5,20 +6,12 @@
 
 # Align and color
 
-
-wl_library(graphic_styles
-  SRCS
-    panel_styles.cc
-    panel_styles.h
-  DEPENDS
-    graphic_color
-    graphic_surface
-)
-
 wl_library(graphic_align
   SRCS
     align.h
     align.cc
+  DEPENDS
+    base_geometry
 )
 
 wl_library(graphic_color
@@ -260,12 +253,6 @@
     graphic_text
 )
 
-wl_library(graphic_text_constants
-  SRCS
-    text_constants.h
-    text_constants.cc
-)
-
 wl_library(graphic_text_layout
   SRCS
     text_layout.cc
@@ -273,10 +260,9 @@
   DEPENDS
     graphic # TODO(Gunchleoc): For text_width safety only - rewrite that function
     graphic_align
-    graphic_color
     graphic_surface
+    graphic_styles
     graphic_text
-    graphic_text_constants
     graphic_fonthandler
     graphic_styles
 )
@@ -295,7 +281,6 @@
     graphic_color
     graphic_fonthandler
     graphic_text
-    graphic_text_constants
     graphic_text_layout
 )
 
@@ -334,7 +319,6 @@
     graphic_render_queue
     graphic_styles
     graphic_surface
-    graphic_text_layout
     io_filesystem
     io_stream
     logic_constants
@@ -346,3 +330,4 @@
     scripting_lua_table
     sound
 )
+

=== modified file 'src/graphic/align.cc'
--- src/graphic/align.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/align.cc	2019-05-03 19:28:13 +0000
@@ -19,4 +19,51 @@
 
 #include "graphic/align.h"
 
-// Dummy
+namespace UI {
+
+/**
+ * Align pt horizontally to match align based on width w.
+ *
+ * When correcting for align, we never move from pixel boundaries to
+ * sub-pixels, because this might lead from pixel-perfect rendering to
+ * subsampled rendering - this can lead to blurry texts. That is why we
+ * never do float divisions in this function.
+ */
+void correct_for_align(Align align, uint32_t w, Vector2i* pt) {
+	if (align == Align::kCenter) {
+		pt->x -= w / 2;
+	} else if (align == Align::kRight) {
+		pt->x -= w;
+	}
+}
+
+/**
+ * Adjust the y coordinate in 'point 'pt' to vertically center an element with height 'h'.
+ */
+void center_vertically(uint32_t h, Vector2i* pt) {
+	pt->y -= h / 2;
+}
+
+
+/**
+ * This mirrors the horizontal alignment for RTL languages.
+ *
+ * Do not store this value as it is based on the global font setting.
+ */
+Align mirror_alignment(Align alignment, bool is_rtl) {
+	if (is_rtl) {
+		switch (alignment) {
+		case Align::kLeft:
+			alignment = Align::kRight;
+			break;
+		case Align::kRight:
+			alignment = Align::kLeft;
+			break;
+		case Align::kCenter:
+			break;
+		}
+	}
+	return alignment;
+}
+
+} // namespace UI

=== modified file 'src/graphic/align.h'
--- src/graphic/align.h	2019-02-23 11:00:49 +0000
+++ src/graphic/align.h	2019-05-03 19:28:13 +0000
@@ -20,6 +20,10 @@
 #ifndef WL_GRAPHIC_ALIGN_H
 #define WL_GRAPHIC_ALIGN_H
 
+#include <string>
+
+#include "base/vector.h"
+
 namespace UI {
 
 // TODO(GunChleoc): Step 1: Clean up superfluous usages of kLeft/kTop, especially with dalls to
@@ -33,5 +37,9 @@
 	kTop = kLeft,
 	kBottom = kRight,
 };
+
+void center_vertically(uint32_t h, Vector2i* pt);
+void correct_for_align(Align, uint32_t w, Vector2i* pt);
+Align mirror_alignment(Align alignment, bool is_rtl);
 }  // namespace UI
 #endif  // end of include guard: WL_GRAPHIC_ALIGN_H

=== modified file 'src/graphic/font_handler.cc'
--- src/graphic/font_handler.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/font_handler.cc	2019-05-03 19:28:13 +0000
@@ -87,7 +87,7 @@
 		const std::string hash = boost::lexical_cast<std::string>(w) + text;
 		std::shared_ptr<const RenderedText> rendered_text = render_cache_->get(hash);
 		if (rendered_text == nullptr) {
-			rendered_text = render_cache_->insert(hash, rt_renderer_->render(text, w));
+			rendered_text = render_cache_->insert(hash, rt_renderer_->render(text, w, fontset()->is_rtl()));
 		}
 		return rendered_text;
 	}

=== modified file 'src/graphic/graphic.cc'
--- src/graphic/graphic.cc	2019-02-28 08:02:18 +0000
+++ src/graphic/graphic.cc	2019-05-03 19:28:13 +0000
@@ -35,7 +35,6 @@
 #include "graphic/render_queue.h"
 #include "graphic/rendertarget.h"
 #include "graphic/screen.h"
-#include "graphic/text_layout.h"
 #include "graphic/texture.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "io/streamwrite.h"

=== removed file 'src/graphic/panel_styles.cc'
--- src/graphic/panel_styles.cc	2017-06-12 11:07:47 +0000
+++ src/graphic/panel_styles.cc	1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-// Dummy to make CMake happy

=== modified file 'src/graphic/rendertarget.cc'
--- src/graphic/rendertarget.cc	2019-04-24 06:32:02 +0000
+++ src/graphic/rendertarget.cc	2019-05-03 19:28:13 +0000
@@ -20,10 +20,10 @@
 #include "graphic/rendertarget.h"
 
 #include "base/macros.h"
+#include "graphic/align.h"
 #include "graphic/animation.h"
 #include "graphic/graphic.h"
 #include "graphic/surface.h"
-#include "graphic/text_layout.h"
 
 /**
  * Build a render target for the given surface.

=== modified file 'src/graphic/style_manager.cc'
--- src/graphic/style_manager.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/style_manager.cc	2019-05-03 19:28:13 +0000
@@ -21,21 +21,53 @@
 
 #include <memory>
 
+#include <boost/format.hpp>
+
 #include "base/scoped_timer.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
 #include "scripting/lua_interface.h"
 
 namespace {
-// Read image filename and RGB color from LuaTable
-UI::PanelStyleInfo* read_style(const LuaTable& table) {
+// Read RGB color from LuaTable
+RGBColor read_rgb_color(const LuaTable& table) {
+	std::vector<int> rgbcolor = table.array_entries<int>();
+	if (rgbcolor.size() != 3) {
+		throw wexception("Expected 3 entries for RGB color, but got %" PRIuS ".", rgbcolor.size());
+	}
+	return RGBColor(rgbcolor[0], rgbcolor[1], rgbcolor[2]);
+}
+
+UI::FontStyleInfo* read_font_style(const LuaTable& parent_table, const std::string& table_key) {
+	std::unique_ptr<LuaTable> style_table = parent_table.get_table(table_key);
+	const int size = style_table->get_int("size");
+	if (size < 1) {
+		throw wexception("Font size %d too small for %s, must be at least 1!", size, table_key.c_str());
+	}
+	return new UI::FontStyleInfo(
+				style_table->get_string("face"),
+				read_rgb_color(*style_table->get_table("color")),
+				size,
+				style_table->has_key<std::string>("bold") ? style_table->get_bool("bold") : false,
+				style_table->has_key<std::string>("italic") ? style_table->get_bool("italic") : false,
+				style_table->has_key<std::string>("underline") ? style_table->get_bool("underline") : false,
+				style_table->has_key<std::string>("shadow") ? style_table->get_bool("shadow") : false);
+}
+
+// Read image filename and RGBA color from LuaTable
+UI::PanelStyleInfo* read_panel_style(const LuaTable& table) {
 	const std::string image = table.get_string("image");
 	std::vector<int> rgbcolor = table.get_table("color")->array_entries<int>();
 	if (rgbcolor.size() != 3) {
 		throw wexception("Expected 3 entries for RGB color, but got %" PRIuS ".", rgbcolor.size());
 	}
 	return new UI::PanelStyleInfo(image.empty() ? nullptr : g_gr->images().get(image),
-	                              RGBAColor(rgbcolor[0], rgbcolor[1], rgbcolor[2], 0));
+	                              RGBAColor(rgbcolor[0], rgbcolor[1], rgbcolor[2], 0),
+			table.has_key<std::string>("margin") ? table.get_int("margin") : 0);
+}
+
+UI::TextPanelStyleInfo* read_text_panel_style(const LuaTable& table) {
+	return new UI::TextPanelStyleInfo(read_font_style(table, "font"), read_panel_style(*table.get_table("background")));
 }
 
 // Stupid completeness check - enum classes weren't meant for iterating, so we just compare the size
@@ -59,45 +91,34 @@
 	dropdownstyles_.clear();
 	scrollbarstyles_.clear();
 
-	log("Style Manager: Loading %sinit.lua ... ", kTemplateDir.c_str());
-
 	LuaInterface lua;
 	std::unique_ptr<LuaTable> table(lua.run_script(kTemplateDir + "init.lua"));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading button styles ... ");
-
 	// Buttons
 	std::unique_ptr<LuaTable> element_table = table->get_table("buttons");
 	std::unique_ptr<LuaTable> style_table = element_table->get_table("fsmenu");
-	add_button_style(UI::ButtonStyle::kFsMenuMenu, *style_table->get_table("menu").get());
-	add_button_style(UI::ButtonStyle::kFsMenuPrimary, *style_table->get_table("primary").get());
-	add_button_style(UI::ButtonStyle::kFsMenuSecondary, *style_table->get_table("secondary").get());
+	add_button_style(UI::ButtonStyle::kFsMenuMenu, *style_table->get_table("menu"));
+	add_button_style(UI::ButtonStyle::kFsMenuPrimary, *style_table->get_table("primary"));
+	add_button_style(UI::ButtonStyle::kFsMenuSecondary, *style_table->get_table("secondary"));
 	style_table = element_table->get_table("wui");
-	add_button_style(UI::ButtonStyle::kWuiMenu, *style_table->get_table("menu").get());
-	add_button_style(UI::ButtonStyle::kWuiPrimary, *style_table->get_table("primary").get());
-	add_button_style(UI::ButtonStyle::kWuiSecondary, *style_table->get_table("secondary").get());
+	add_button_style(UI::ButtonStyle::kWuiMenu, *style_table->get_table("menu"));
+	add_button_style(UI::ButtonStyle::kWuiPrimary, *style_table->get_table("primary"));
+	add_button_style(UI::ButtonStyle::kWuiSecondary, *style_table->get_table("secondary"));
 	add_button_style(
-	   UI::ButtonStyle::kWuiBuildingStats, *style_table->get_table("building_stats").get());
+	   UI::ButtonStyle::kWuiBuildingStats, *style_table->get_table("building_stats"));
 	check_completeness(
 	   "buttons", buttonstyles_.size(), static_cast<size_t>(UI::ButtonStyle::kWuiBuildingStats));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading slider styles ... ");
-
 	// Sliders
 	element_table = table->get_table("sliders");
 	style_table = element_table->get_table("fsmenu");
-	add_slider_style(UI::SliderStyle::kFsMenu, *style_table->get_table("menu").get());
+	add_slider_style(UI::SliderStyle::kFsMenu, *style_table->get_table("menu"));
 	style_table = element_table->get_table("wui");
-	add_slider_style(UI::SliderStyle::kWuiLight, *style_table->get_table("light").get());
-	add_slider_style(UI::SliderStyle::kWuiDark, *style_table->get_table("dark").get());
+	add_slider_style(UI::SliderStyle::kWuiLight, *style_table->get_table("light"));
+	add_slider_style(UI::SliderStyle::kWuiDark, *style_table->get_table("dark"));
 	check_completeness(
 	   "sliders", sliderstyles_.size(), static_cast<size_t>(UI::SliderStyle::kWuiDark));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading tabpanel styles ... ");
-
 	// Tabpanels
 	element_table = table->get_table("tabpanels");
 	style_table = element_table->get_table("fsmenu");
@@ -108,21 +129,13 @@
 	check_completeness(
 	   "tabpanels", tabpanelstyles_.size(), static_cast<size_t>(UI::TabPanelStyle::kWuiDark));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading editbox styles ... ");
-
 	// Editboxes
 	element_table = table->get_table("editboxes");
-	style_table = element_table->get_table("fsmenu");
-	add_style(UI::PanelStyle::kFsMenu, *style_table->get_table("menu").get(), &editboxstyles_);
-	style_table = element_table->get_table("wui");
-	add_style(UI::PanelStyle::kWui, *style_table->get_table("menu").get(), &editboxstyles_);
+	add_editbox_style(UI::PanelStyle::kFsMenu, *element_table->get_table("fsmenu"));
+	add_editbox_style(UI::PanelStyle::kWui, *element_table->get_table("wui"));
 	check_completeness(
 	   "editboxes", editboxstyles_.size(), static_cast<size_t>(UI::PanelStyle::kWui));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading dropdown styles ... ");
-
 	// Dropdowns
 	element_table = table->get_table("dropdowns");
 	style_table = element_table->get_table("fsmenu");
@@ -132,9 +145,6 @@
 	check_completeness(
 	   "dropdowns", dropdownstyles_.size(), static_cast<size_t>(UI::PanelStyle::kWui));
 
-	log("took %ums\n", timer.ms_since_last_query());
-	log("Style Manager: Reading scrollbar styles ... ");
-
 	// Scrollbars
 	element_table = table->get_table("scrollbars");
 	style_table = element_table->get_table("fsmenu");
@@ -144,18 +154,78 @@
 	check_completeness(
 	   "scrollbars", scrollbarstyles_.size(), static_cast<size_t>(UI::PanelStyle::kWui));
 
-	log("took %ums\n", timer.ms_since_last_query());
+	// Building statistics etc. for map objects
+	set_building_statistics_style(*table->get_table("building_statistics"));
+
+	// Progress bars
+	element_table = table->get_table("progressbar");
+	add_progressbar_style(UI::PanelStyle::kFsMenu, *element_table->get_table("fsmenu"));
+	add_progressbar_style(UI::PanelStyle::kWui, *element_table->get_table("wui"));
+	check_completeness(
+	   "progressbars", progressbar_styles_.size(), static_cast<size_t>(UI::PanelStyle::kWui));
+
+	// Table and listselect
+	element_table = table->get_table("tables");
+	add_table_style(UI::PanelStyle::kFsMenu, *element_table->get_table("fsmenu"));
+	add_table_style(UI::PanelStyle::kWui, *element_table->get_table("wui"));
+	check_completeness(
+	   "tables", table_styles_.size(), static_cast<size_t>(UI::PanelStyle::kWui));
+
+	// Statistics plot
+	set_statistics_plot_style(*table->get_table("statistics_plot"));
+
+	// Ware info in warehouses, construction actions etc.
+	element_table = table->get_table("wareinfo");
+	add_ware_info_style(UI::WareInfoStyle::kNormal, *element_table->get_table("normal"));
+	add_ware_info_style(UI::WareInfoStyle::kHighlight, *element_table->get_table("highlight"));
+	check_completeness(
+	   "wareinfos", ware_info_styles_.size(), static_cast<size_t>(UI::WareInfoStyle::kHighlight));
+
+	// Special elements
+	minimum_font_size_ = table->get_int("minimum_font_size");
+	if (minimum_font_size_ < 1) {
+		throw wexception("Font size too small for minimum_font_size, must be at least 1!");
+	}
+	minimap_icon_frame_ = read_rgb_color(*table->get_table("minimap_icon_frame"));
+
+	// Fonts
+	element_table = table->get_table("fonts");
+	add_font_style(UI::FontStyle::kChatMessage, *element_table, "chat_message");
+	add_font_style(UI::FontStyle::kChatPlayername, *element_table, "chat_playername");
+	add_font_style(UI::FontStyle::kChatServer, *element_table, "chat_server");
+	add_font_style(UI::FontStyle::kChatTimestamp, *element_table, "chat_timestamp");
+	add_font_style(UI::FontStyle::kChatWhisper, *element_table, "chat_whisper");
+	add_font_style(UI::FontStyle::kFsGameSetupHeadings, *element_table, "fsmenu_game_setup_headings");
+	add_font_style(UI::FontStyle::kFsGameSetupIrcClient, *element_table, "fsmenu_game_setup_irc_client");
+	add_font_style(UI::FontStyle::kFsGameSetupMapname, *element_table, "fsmenu_game_setup_mapname");
+	add_font_style(UI::FontStyle::kFsMenuGameTip, *element_table, "fsmenu_gametip");
+	add_font_style(UI::FontStyle::kFsMenuInfoPanelHeading, *element_table, "fsmenu_info_panel_heading");
+	add_font_style(UI::FontStyle::kFsMenuInfoPanelParagraph, *element_table, "fsmenu_info_panel_paragraph");
+	add_font_style(UI::FontStyle::kFsMenuIntro, *element_table, "fsmenu_intro");
+	add_font_style(UI::FontStyle::kFsMenuTitle, *element_table, "fsmenu_title");
+	add_font_style(UI::FontStyle::kFsMenuTranslationInfo, *element_table, "fsmenu_translation_info");
+	add_font_style(UI::FontStyle::kLabel, *element_table, "label");
+	add_font_style(UI::FontStyle::kTooltipHeader, *element_table, "tooltip_header");
+	add_font_style(UI::FontStyle::kTooltip, *element_table, "tooltip");
+	add_font_style(UI::FontStyle::kWarning, *element_table, "warning");
+	add_font_style(UI::FontStyle::kWuiGameSpeedAndCoordinates, *element_table, "wui_game_speed_and_coordinates");
+	add_font_style(UI::FontStyle::kWuiInfoPanelHeading, *element_table, "wui_info_panel_heading");
+	add_font_style(UI::FontStyle::kWuiInfoPanelParagraph, *element_table, "wui_info_panel_paragraph");
+	add_font_style(UI::FontStyle::kWuiMessageHeading, *element_table, "wui_message_heading");
+	add_font_style(UI::FontStyle::kWuiMessageParagraph, *element_table, "wui_message_paragraph");
+	add_font_style(UI::FontStyle::kWuiWindowTitle, *element_table, "wui_window_title");
+	check_completeness("fonts", fontstyles_.size(), static_cast<size_t>(UI::FontStyle::kWuiWindowTitle));
 }
 
 // Return functions for the styles
-const UI::PanelStyleInfo* StyleManager::button_style(UI::ButtonStyle style) const {
+const UI::ButtonStyleInfo& StyleManager::button_style(UI::ButtonStyle style) const {
 	assert(buttonstyles_.count(style) == 1);
-	return buttonstyles_.at(style).get();
+	return *buttonstyles_.at(style);
 }
 
-const UI::PanelStyleInfo* StyleManager::slider_style(UI::SliderStyle style) const {
+const UI::TextPanelStyleInfo& StyleManager::slider_style(UI::SliderStyle style) const {
 	assert(sliderstyles_.count(style) == 1);
-	return sliderstyles_.at(style).get();
+	return *sliderstyles_.at(style);
 }
 
 const UI::PanelStyleInfo* StyleManager::tabpanel_style(UI::TabPanelStyle style) const {
@@ -163,9 +233,9 @@
 	return tabpanelstyles_.at(style).get();
 }
 
-const UI::PanelStyleInfo* StyleManager::editbox_style(UI::PanelStyle style) const {
+const UI::TextPanelStyleInfo& StyleManager::editbox_style(UI::PanelStyle style) const {
 	assert(editboxstyles_.count(style) == 1);
-	return editboxstyles_.at(style).get();
+	return *editboxstyles_.at(style);
 }
 
 const UI::PanelStyleInfo* StyleManager::dropdown_style(UI::PanelStyle style) const {
@@ -178,22 +248,142 @@
 	return scrollbarstyles_.at(style).get();
 }
 
+const UI::BuildingStatisticsStyleInfo& StyleManager::building_statistics_style() const {
+	return *building_statistics_style_;
+}
+
+const UI::ProgressbarStyleInfo& StyleManager::progressbar_style(UI::PanelStyle style) const {
+	assert(progressbar_styles_.count(style) == 1);
+	return *progressbar_styles_.at(style);
+}
+
+const UI::StatisticsPlotStyleInfo& StyleManager::statistics_plot_style() const {
+	return *statistics_plot_style_;
+}
+
+const UI::TableStyleInfo& StyleManager::table_style(UI::PanelStyle style) const {
+	assert(table_styles_.count(style) == 1);
+	return *table_styles_.at(style);
+}
+
+const UI::WareInfoStyleInfo& StyleManager::ware_info_style(UI::WareInfoStyle style) const {
+	assert(ware_info_styles_.count(style) == 1);
+	return *ware_info_styles_.at(style);
+}
+
+const UI::FontStyleInfo& StyleManager::font_style(UI::FontStyle style) const {
+	return *fontstyles_.at(style);
+}
+
+int StyleManager::minimum_font_size() const {
+	return minimum_font_size_;
+}
+
+const RGBColor& StyleManager::minimap_icon_frame() const {
+	return minimap_icon_frame_;
+}
+
+std::string StyleManager::color_tag(const std::string& text, const RGBColor& color) {
+	static boost::format f("<font color=%s>%s</font>");
+	f % color.hex_value();
+	f % text;
+	return f.str();
+}
+
 // Fill the maps
 void StyleManager::add_button_style(UI::ButtonStyle style, const LuaTable& table) {
 	buttonstyles_.insert(
-	   std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_style(table))));
+				std::make_pair(
+					style,
+					std::unique_ptr<const UI::ButtonStyleInfo>(
+						new UI::ButtonStyleInfo(
+							read_text_panel_style(*table.get_table("enabled")),
+							read_text_panel_style(*table.get_table("disabled"))))));
 }
 
 void StyleManager::add_slider_style(UI::SliderStyle style, const LuaTable& table) {
 	sliderstyles_.insert(
-	   std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_style(table))));
-}
+	   std::make_pair(style, std::unique_ptr<UI::TextPanelStyleInfo>(read_text_panel_style(table))));
+}
+
+void StyleManager::add_editbox_style(UI::PanelStyle style, const LuaTable& table) {
+	editboxstyles_.insert(
+	   std::make_pair(style, std::unique_ptr<UI::TextPanelStyleInfo>(read_text_panel_style(table))));
+}
+
 
 void StyleManager::add_tabpanel_style(UI::TabPanelStyle style, const LuaTable& table) {
 	tabpanelstyles_.insert(
-	   std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_style(table))));
+	   std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_panel_style(table))));
+}
+
+void StyleManager::add_progressbar_style(UI::PanelStyle style, const LuaTable& table) {
+	std::unique_ptr<LuaTable> color_table = table.get_table("background_colors");
+	progressbar_styles_.insert(std::make_pair(
+								   style,
+								   std::unique_ptr<const UI::ProgressbarStyleInfo>(
+									   new UI::ProgressbarStyleInfo(
+										   read_font_style(table, "font"),
+										   read_rgb_color(*color_table->get_table("low")),
+										   read_rgb_color(*color_table->get_table("medium")),
+										   read_rgb_color(*color_table->get_table("high"))))));
+}
+
+void StyleManager::add_table_style(UI::PanelStyle style, const LuaTable& table) {
+	table_styles_.insert(std::make_pair(style,
+										std::unique_ptr<const UI::TableStyleInfo>(
+											new UI::TableStyleInfo(
+												read_font_style(table, "enabled"),
+												read_font_style(table, "disabled")))));
+}
+
+void StyleManager::set_statistics_plot_style(const LuaTable& table) {
+	std::unique_ptr<LuaTable> fonts_table = table.get_table("fonts");
+	std::unique_ptr<LuaTable> colors_table = table.get_table("colors");
+	statistics_plot_style_.reset(new UI::StatisticsPlotStyleInfo(
+				read_font_style(*fonts_table, "x_tick"),
+				read_font_style(*fonts_table, "y_min_value"),
+				read_font_style(*fonts_table, "y_max_value"),
+				read_rgb_color(*colors_table->get_table("axis_line")),
+				read_rgb_color(*colors_table->get_table("zero_line"))));
+}
+
+void StyleManager::set_building_statistics_style(const LuaTable& table) {
+	std::unique_ptr<LuaTable> window_table = table.get_table("statistics_window");
+	std::unique_ptr<LuaTable> colors_table = table.get_table("colors");
+	std::unique_ptr<LuaTable> fonts_table = window_table->get_table("fonts");
+	building_statistics_style_.reset(new UI::BuildingStatisticsStyleInfo(
+								read_font_style(*fonts_table, "button_font"),
+								read_font_style(*fonts_table, "details_font"),
+								window_table->get_int("editbox_margin"),
+								read_font_style(table, "census_font"),
+								read_font_style(table, "statistics_font"),
+								read_rgb_color(*colors_table->get_table("construction")),
+								read_rgb_color(*colors_table->get_table("neutral")),
+								read_rgb_color(*colors_table->get_table("low")),
+								read_rgb_color(*colors_table->get_table("medium")),
+								read_rgb_color(*colors_table->get_table("high"))));
+}
+
+void StyleManager::add_ware_info_style(UI::WareInfoStyle style, const LuaTable& table) {
+	std::unique_ptr<LuaTable> fonts_table = table.get_table("fonts");
+	std::unique_ptr<LuaTable> colors_table = table.get_table("colors");
+	ware_info_styles_.insert(
+				std::make_pair(style,
+							   std::unique_ptr<const UI::WareInfoStyleInfo>(
+								   new UI::WareInfoStyleInfo(
+									   read_font_style(*fonts_table, "header"),
+									   read_font_style(*fonts_table, "info"),
+									   g_gr->images().get(table.get_string("icon_background_image")),
+									   read_rgb_color(*colors_table->get_table("icon_frame")),
+									   read_rgb_color(*colors_table->get_table("icon_background")),
+									   read_rgb_color(*colors_table->get_table("info_background"))))));
 }
 
 void StyleManager::add_style(UI::PanelStyle style, const LuaTable& table, PanelStyleMap* map) {
-	map->insert(std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_style(table))));
+	map->insert(std::make_pair(style, std::unique_ptr<UI::PanelStyleInfo>(read_panel_style(table))));
+}
+
+void StyleManager::add_font_style(UI::FontStyle font_key, const LuaTable& table, const std::string& table_key) {
+	fontstyles_.emplace(std::make_pair(font_key, std::unique_ptr<UI::FontStyleInfo>(read_font_style(table, table_key))));
 }

=== modified file 'src/graphic/style_manager.h'
--- src/graphic/style_manager.h	2019-02-23 11:00:49 +0000
+++ src/graphic/style_manager.h	2019-05-03 19:28:13 +0000
@@ -23,7 +23,15 @@
 #include <map>
 #include <memory>
 
-#include "graphic/panel_styles.h"
+#include "graphic/styles/building_statistics_style.h"
+#include "graphic/styles/button_style.h"
+#include "graphic/styles/font_style.h"
+#include "graphic/styles/panel_styles.h"
+#include "graphic/styles/progress_bar_style.h"
+#include "graphic/styles/statistics_plot_style.h"
+#include "graphic/styles/table_style.h"
+#include "graphic/styles/text_panel_style.h"
+#include "graphic/styles/ware_info_style.h"
 #include "scripting/lua_table.h"
 
 static const std::string kTemplateDir = "templates/default/";
@@ -36,27 +44,54 @@
 	// Late initialization, because Graphics needs to load the image files first.
 	void init();
 
-	const UI::PanelStyleInfo* button_style(UI::ButtonStyle) const;
-	const UI::PanelStyleInfo* slider_style(UI::SliderStyle) const;
+	const UI::BuildingStatisticsStyleInfo& building_statistics_style() const;
+	const UI::ButtonStyleInfo& button_style(UI::ButtonStyle) const;
+	const UI::TextPanelStyleInfo& slider_style(UI::SliderStyle) const;
 	const UI::PanelStyleInfo* tabpanel_style(UI::TabPanelStyle) const;
-	const UI::PanelStyleInfo* editbox_style(UI::PanelStyle) const;
+	const UI::TextPanelStyleInfo& editbox_style(UI::PanelStyle) const;
 	const UI::PanelStyleInfo* dropdown_style(UI::PanelStyle) const;
 	const UI::PanelStyleInfo* scrollbar_style(UI::PanelStyle) const;
+	const UI::ProgressbarStyleInfo& progressbar_style(UI::PanelStyle) const;
+	const UI::StatisticsPlotStyleInfo& statistics_plot_style() const;
+	const UI::TableStyleInfo& table_style(UI::PanelStyle) const;
+	const UI::WareInfoStyleInfo& ware_info_style(UI::WareInfoStyle) const;
+	const UI::FontStyleInfo& font_style(UI::FontStyle style) const;
+
+	// Special elements
+	int minimum_font_size() const;
+	const RGBColor& minimap_icon_frame() const;
+	static std::string color_tag(const std::string& text, const RGBColor& color);
 
 private:
 	using PanelStyleMap = std::map<UI::PanelStyle, std::unique_ptr<const UI::PanelStyleInfo>>;
 	void add_button_style(UI::ButtonStyle style, const LuaTable& table);
 	void add_slider_style(UI::SliderStyle style, const LuaTable& table);
+	void add_editbox_style(UI::PanelStyle style, const LuaTable& table);
 	void add_tabpanel_style(UI::TabPanelStyle style, const LuaTable& table);
+	void add_progressbar_style(UI::PanelStyle style, const LuaTable& table);
+	void add_table_style(UI::PanelStyle style, const LuaTable& table);
+	void set_statistics_plot_style(const LuaTable& table);
+	void set_building_statistics_style(const LuaTable& table);
+	void add_ware_info_style(UI::WareInfoStyle style, const LuaTable& table);
 	void add_style(UI::PanelStyle style, const LuaTable& table, PanelStyleMap* map);
+	void add_font_style(UI::FontStyle font, const LuaTable& table, const std::string& key);
 
-	std::map<UI::ButtonStyle, std::unique_ptr<const UI::PanelStyleInfo>> buttonstyles_;
-	std::map<UI::SliderStyle, std::unique_ptr<const UI::PanelStyleInfo>> sliderstyles_;
+	std::map<UI::ButtonStyle, std::unique_ptr<const UI::ButtonStyleInfo>> buttonstyles_;
+	std::map<UI::PanelStyle, std::unique_ptr<const UI::TextPanelStyleInfo>> editboxstyles_;
+	std::map<UI::SliderStyle, std::unique_ptr<const UI::TextPanelStyleInfo>> sliderstyles_;
 	std::map<UI::TabPanelStyle, std::unique_ptr<const UI::PanelStyleInfo>> tabpanelstyles_;
-	PanelStyleMap editboxstyles_;
 	PanelStyleMap dropdownstyles_;
 	PanelStyleMap scrollbarstyles_;
 
+	int minimum_font_size_;
+	RGBColor minimap_icon_frame_;
+	std::map<UI::FontStyle, std::unique_ptr<const UI::FontStyleInfo>> fontstyles_;
+	std::unique_ptr<const UI::BuildingStatisticsStyleInfo> building_statistics_style_;
+	std::map<UI::PanelStyle, std::unique_ptr<const UI::ProgressbarStyleInfo>> progressbar_styles_;
+	std::unique_ptr<const UI::StatisticsPlotStyleInfo> statistics_plot_style_;
+	std::map<UI::PanelStyle, std::unique_ptr<const UI::TableStyleInfo>> table_styles_;
+	std::map<UI::WareInfoStyle, std::unique_ptr<const UI::WareInfoStyleInfo>> ware_info_styles_;
+
 	DISALLOW_COPY_AND_ASSIGN(StyleManager);
 };
 

=== added directory 'src/graphic/styles'
=== added file 'src/graphic/styles/CMakeLists.txt'
--- src/graphic/styles/CMakeLists.txt	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -0,0 +1,17 @@
+wl_library(graphic_styles
+  SRCS
+    building_statistics_style.h
+    button_style.h
+    font_style.cc
+    font_style.h
+    panel_styles.h
+    progress_bar_style.h
+    text_panel_style.h
+    statistics_plot_style.h
+    table_style.h
+    ware_info_style.h
+  DEPENDS
+    base_exceptions
+    graphic_color
+    graphic_surface
+)

=== added file 'src/graphic/styles/building_statistics_style.h'
--- src/graphic/styles/building_statistics_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/building_statistics_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_BUILDING_STATISTICS_STYLE_H
+#define WL_GRAPHIC_STYLES_BUILDING_STATISTICS_STYLE_H
+
+#include <memory>
+
+#include "graphic/color.h"
+#include "graphic/styles/font_style.h"
+
+namespace UI {
+
+struct BuildingStatisticsStyleInfo {
+	explicit BuildingStatisticsStyleInfo(UI::FontStyleInfo* init_building_statistics_button_font,
+								UI::FontStyleInfo* init_building_statistics_details_font,
+								int init_editbox_margin,
+								UI::FontStyleInfo* init_census,
+								UI::FontStyleInfo* init_statistics,
+								const RGBColor& init_construction_color,
+								const RGBColor& init_neutral_color,
+								const RGBColor& init_low_color,
+								const RGBColor& init_medium_color,
+								const RGBColor& init_high_color) :
+		building_statistics_button_font_(init_building_statistics_button_font),
+		building_statistics_details_font_(init_building_statistics_details_font),
+		editbox_margin_(init_editbox_margin),
+		census_font_(init_census),
+		statistics_font_(init_statistics),
+		construction_color_(init_construction_color),
+		neutral_color_(init_neutral_color),
+		low_color_(init_low_color),
+		medium_color_(init_medium_color),
+		high_color_(init_high_color) {}
+
+	const UI::FontStyleInfo& building_statistics_button_font() const {
+		return *building_statistics_button_font_.get();
+	}
+	const UI::FontStyleInfo& building_statistics_details_font() const {
+		return *building_statistics_details_font_.get();
+	}
+	int editbox_margin() const {
+		return editbox_margin_;
+	}
+
+	const UI::FontStyleInfo& census_font() const {
+		return *census_font_.get();
+	}
+	const UI::FontStyleInfo& statistics_font() const {
+		return *statistics_font_.get();
+	}
+	const RGBColor& construction_color() const {
+		return construction_color_;
+	}
+	const RGBColor& neutral_color() const {
+		return neutral_color_;
+	}
+	const RGBColor& low_color() const {
+		return low_color_;
+	}
+	const RGBColor& medium_color() const {
+		return medium_color_;
+	}
+	const RGBColor& high_color() const {
+		return high_color_;
+	}
+
+private:
+	std::unique_ptr<const UI::FontStyleInfo> building_statistics_button_font_;
+	std::unique_ptr<const UI::FontStyleInfo> building_statistics_details_font_;
+	int editbox_margin_;
+	std::unique_ptr<const UI::FontStyleInfo> census_font_;
+	std::unique_ptr<const UI::FontStyleInfo> statistics_font_;
+	const RGBColor construction_color_;
+	const RGBColor neutral_color_;
+	const RGBColor low_color_;
+	const RGBColor medium_color_;
+	const RGBColor high_color_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_BUILDING_STATISTICS_STYLE_H

=== added file 'src/graphic/styles/button_style.h'
--- src/graphic/styles/button_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/button_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_BUTTON_STYLE_H
+#define WL_GRAPHIC_STYLES_BUTTON_STYLE_H
+
+#include <memory>
+
+#include "graphic/styles/font_style.h"
+#include "graphic/styles/panel_styles.h"
+#include "graphic/styles/text_panel_style.h"
+
+namespace UI {
+
+enum class ButtonStyle {
+	kFsMenuMenu,
+	kFsMenuPrimary,
+	kFsMenuSecondary,
+	kWuiMenu,
+	kWuiPrimary,
+	kWuiSecondary,
+	kWuiBuildingStats
+};
+
+struct ButtonStyleInfo {
+	ButtonStyleInfo(const UI::TextPanelStyleInfo* init_enabled, const UI::TextPanelStyleInfo* init_disabled) :
+		enabled_(init_enabled),
+		disabled_(init_disabled) {
+	}
+	ButtonStyleInfo(const ButtonStyleInfo& other) :
+		enabled_(new UI::TextPanelStyleInfo(other.enabled())),
+		disabled_(new UI::TextPanelStyleInfo(other.disabled())) {
+	}
+
+	const UI::TextPanelStyleInfo& enabled() const {
+		return *enabled_.get();
+	}
+	const UI::TextPanelStyleInfo& disabled() const {
+		return *disabled_.get();
+	}
+
+private:
+	std::unique_ptr<const UI::TextPanelStyleInfo> enabled_;
+	std::unique_ptr<const UI::TextPanelStyleInfo> disabled_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_BUTTON_STYLE_H

=== added file 'src/graphic/styles/font_style.cc'
--- src/graphic/styles/font_style.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/font_style.cc	2019-05-03 19:28:13 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/styles/font_style.h"
+
+#include <boost/format.hpp>
+
+#include "base/log.h"
+#include "base/wexception.h"
+
+namespace UI {
+
+FontStyleInfo::FontStyleInfo(const std::string& init_face, const RGBColor& init_color, int init_size,
+							 bool init_bold, bool init_italic, bool init_underline, bool init_shadow) :
+	face_(string_to_face(init_face)),
+	color_(init_color),
+	size_(init_size),
+	bold_(init_bold),
+	italic_(init_italic),
+	underline_(init_underline),
+	shadow_(init_shadow) {
+}
+
+FontStyleInfo::FontStyleInfo(const FontStyleInfo& other) :
+	face_(other.face()),
+	color_(other.color()),
+	size_(other.size()),
+	bold_(other.bold()),
+	italic_(other.italic()),
+	underline_(other.underline()),
+	shadow_(other.shadow())
+{}
+
+const std::string FontStyleInfo::face_to_string() const {
+	switch (face_) {
+	case Face::kSans:
+		return "sans";
+	case Face::kSerif:
+		return "serif";
+	case Face::kCondensed:
+		return "condensed";
+	}
+	return "sans";
+}
+
+FontStyleInfo::Face FontStyleInfo::string_to_face(const std::string& init_face) {
+	FontStyleInfo::Face result;
+	if (init_face == "sans") {
+		result = Face::kSans;
+	} else if (init_face == "serif") {
+		result = Face::kSerif;
+	} else if (init_face == "condensed") {
+		result = Face::kCondensed;
+	} else {
+		throw wexception("Unknown font face '%s', expected 'sans', 'serif' or 'condensed'", init_face.c_str());
+	}
+	return result;
+}
+
+std::string FontStyleInfo::as_font_tag(const std::string& text) const {
+	static boost::format f("<font face=%s size=%d color=%s%s>%s</font>");
+	std::string optionals = "";
+	if (bold_) {
+		optionals += " bold=1";
+	}
+	if (italic_) {
+		optionals += " italic=1";
+	}
+	if (shadow_) {
+		optionals += " shadow=1";
+	}
+	if (underline_) {
+		optionals += " underline=1";
+	}
+	f % face_to_string();
+	f % size_;
+	f % color_.hex_value();
+	f % optionals;
+	f % text;
+	return f.str();
+}
+
+FontStyleInfo::Face FontStyleInfo::face() const {
+	return face_;
+}
+void FontStyleInfo::make_condensed() {
+	face_ = Face::kCondensed;
+}
+const RGBColor& FontStyleInfo::color() const {
+	return color_;
+}
+void FontStyleInfo::set_color(const RGBColor& new_color) {
+	color_ = new_color;
+}
+int FontStyleInfo::size() const {
+	return size_;
+}
+void FontStyleInfo::set_size(int new_size) {
+	size_ = new_size;
+}
+bool FontStyleInfo::bold() const {
+	return bold_;
+}
+bool FontStyleInfo::italic() const {
+	return italic_;
+}
+bool FontStyleInfo::underline() const {
+	return underline_;
+}
+bool FontStyleInfo::shadow() const {
+	return shadow_;
+}
+
+} // namespace UI

=== added file 'src/graphic/styles/font_style.h'
--- src/graphic/styles/font_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/font_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_FONT_STYLE_H
+#define WL_GRAPHIC_STYLES_FONT_STYLE_H
+
+#include <string>
+
+#include "graphic/color.h"
+
+namespace UI {
+enum class FontStyle {
+	kChatMessage,
+   kChatPlayername,
+   kChatServer,
+   kChatTimestamp,
+   kChatWhisper,
+   kFsGameSetupHeadings,
+   kFsGameSetupIrcClient,
+   kFsGameSetupMapname,
+   kFsMenuGameTip,
+   kFsMenuInfoPanelHeading,
+   kFsMenuInfoPanelParagraph,
+   kFsMenuIntro,
+	kFsMenuTitle,
+	kFsMenuTranslationInfo,
+   kLabel,
+	kTooltipHeader,
+   kTooltip,
+   kWarning,
+   kWuiGameSpeedAndCoordinates,
+   kWuiInfoPanelHeading,
+   kWuiInfoPanelParagraph,
+   kWuiMessageHeading,
+   kWuiMessageParagraph,
+   kWuiWindowTitle
+};
+
+struct FontStyleInfo {
+	enum class Face { kSans, kSerif, kCondensed };
+
+	explicit FontStyleInfo(const std::string& init_face, const RGBColor& init_color, int init_size,
+						   bool init_bold, bool init_italic, bool init_underline, bool init_shadow);
+	explicit FontStyleInfo(const FontStyleInfo& other);
+	FontStyleInfo& operator=(const FontStyleInfo& other) = default;
+
+	std::string as_font_tag(const std::string& text) const;
+
+	Face face() const;
+	void make_condensed();
+
+	const RGBColor& color() const;
+	void set_color(const RGBColor& new_color);
+
+	int size() const;
+	void set_size(int new_size);
+
+	bool bold() const;
+	bool italic() const;
+	bool underline() const;
+	bool shadow() const;
+
+private:
+	static Face string_to_face(const std::string& face_);
+	const std::string face_to_string() const;
+
+	Face face_;
+	RGBColor color_;
+	int size_;
+	const bool bold_;
+	const bool italic_;
+	const bool underline_;
+	const bool shadow_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_FONT_STYLE_H

=== renamed file 'src/graphic/panel_styles.h' => 'src/graphic/styles/panel_styles.h'
--- src/graphic/panel_styles.h	2019-02-23 11:00:49 +0000
+++ src/graphic/styles/panel_styles.h	2019-05-03 19:28:13 +0000
@@ -17,41 +17,47 @@
  *
  */
 
-#ifndef WL_GRAPHIC_PANEL_STYLES_H
-#define WL_GRAPHIC_PANEL_STYLES_H
+#ifndef WL_GRAPHIC_STYLES_PANEL_STYLES_H
+#define WL_GRAPHIC_STYLES_PANEL_STYLES_H
+
+#include <map>
+#include <memory>
 
 #include "graphic/color.h"
+#include "graphic/styles/font_style.h"
 #include "graphic/image.h"
 
 namespace UI {
 
-// Buttons
-enum class ButtonStyle {
-	kFsMenuMenu,
-	kFsMenuPrimary,
-	kFsMenuSecondary,
-	kWuiMenu,
-	kWuiPrimary,
-	kWuiSecondary,
-	kWuiBuildingStats
-};
-enum class SliderStyle { kFsMenu, kWuiLight, kWuiDark };
-
 // Backgrounds
 enum class PanelStyle { kFsMenu, kWui };
 enum class TabPanelStyle { kFsMenu, kWuiLight, kWuiDark };
 
 struct PanelStyleInfo {
-	PanelStyleInfo(const Image* init_image, const RGBAColor& init_color)
-	   : image(init_image), color(init_color) {
-	}
-	PanelStyleInfo() : PanelStyleInfo(nullptr, RGBAColor(0, 0, 0, 0)) {
-	}
-
-	const Image* image;
-	const RGBAColor color;
+	PanelStyleInfo(const Image* init_image, const RGBAColor& init_color, int init_margin)
+	   : margin_(init_margin), image_(init_image), color_(init_color) {
+	}
+	PanelStyleInfo(const PanelStyleInfo& other)
+	   : image_(other.image()), color_(other.color()) {
+	}
+
+	const RGBAColor& color() const {
+		return color_;
+	}
+	const Image* image() const {
+		return image_;
+	}
+
+	int margin() const {
+		return margin_;
+	}
+
+private:
+	int margin_;
+	const Image* image_;
+	RGBAColor color_;
 };
 
 }  // namespace UI
 
-#endif  // end of include guard: WL_GRAPHIC_PANEL_STYLES_H
+#endif  // end of include guard: WL_GRAPHIC_STYLES_PANEL_STYLES_H

=== added file 'src/graphic/styles/progress_bar_style.h'
--- src/graphic/styles/progress_bar_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/progress_bar_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_PROGRESS_BAR_STYLE_H
+#define WL_GRAPHIC_STYLES_PROGRESS_BAR_STYLE_H
+
+#include <memory>
+
+#include "graphic/color.h"
+#include "graphic/styles/font_style.h"
+
+namespace UI {
+
+struct ProgressbarStyleInfo {
+	explicit ProgressbarStyleInfo(UI::FontStyleInfo* init_font,
+								  const RGBColor& init_low_color,
+								  const RGBColor& init_medium_color,
+								  const RGBColor& init_high_color) :
+		font_(init_font),
+		low_color_(init_low_color),
+		medium_color_(init_medium_color),
+		high_color_(init_high_color) {}
+	explicit ProgressbarStyleInfo(const ProgressbarStyleInfo& other):
+		font_(new UI::FontStyleInfo(other.font())),
+		low_color_(other.low_color()),
+		medium_color_(other.medium_color()),
+		high_color_(other.high_color())
+	{
+	}
+
+	const UI::FontStyleInfo& font() const {
+		return *font_.get();
+	}
+	const RGBColor& low_color() const {
+		return low_color_;
+	}
+	const RGBColor& medium_color() const {
+		return medium_color_;
+	}
+	const RGBColor& high_color() const {
+		return high_color_;
+	}
+
+private:
+	std::unique_ptr<const UI::FontStyleInfo> font_;
+	const RGBColor low_color_;
+	const RGBColor medium_color_;
+	const RGBColor high_color_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_PROGRESS_BAR_STYLE_H

=== added file 'src/graphic/styles/statistics_plot_style.h'
--- src/graphic/styles/statistics_plot_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/statistics_plot_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_STATISTICS_PLOT_STYLE_H
+#define WL_GRAPHIC_STYLES_STATISTICS_PLOT_STYLE_H
+
+#include <memory>
+
+#include "graphic/color.h"
+#include "graphic/styles/font_style.h"
+
+namespace UI {
+
+struct StatisticsPlotStyleInfo {
+	explicit StatisticsPlotStyleInfo(UI::FontStyleInfo* init_x_tick_font,
+									 UI::FontStyleInfo* init_y_min_value_font,
+									 UI::FontStyleInfo* init_y_max_value_font,
+									 const RGBColor& init_axis_line_color,
+									 const RGBColor& init_zero_line_color) :
+		x_tick_font_(init_x_tick_font),
+		y_min_value_font_(init_y_min_value_font),
+		y_max_value_font_(init_y_max_value_font),
+		axis_line_color_(init_axis_line_color),
+		zero_line_color_(init_zero_line_color) {}
+
+	const UI::FontStyleInfo& x_tick_font() const {
+		return *x_tick_font_.get();
+	}
+	const UI::FontStyleInfo& y_min_value_font() const {
+		return *y_min_value_font_.get();
+	}
+	const UI::FontStyleInfo& y_max_value_font() const {
+		return *y_max_value_font_.get();
+	}
+	const RGBColor& axis_line_color() const {
+		return axis_line_color_;
+	}
+	const RGBColor& zero_line_color() const {
+		return zero_line_color_;
+	}
+
+private:
+	std::unique_ptr<const UI::FontStyleInfo> x_tick_font_;
+	std::unique_ptr<const UI::FontStyleInfo> y_min_value_font_;
+	std::unique_ptr<const UI::FontStyleInfo> y_max_value_font_;
+	const RGBColor axis_line_color_;
+	const RGBColor zero_line_color_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_STATISTICS_PLOT_STYLE_H

=== added file 'src/graphic/styles/table_style.h'
--- src/graphic/styles/table_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/table_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_TABLE_STYLE_H
+#define WL_GRAPHIC_STYLES_TABLE_STYLE_H
+
+#include <memory>
+
+#include "graphic/styles/font_style.h"
+
+namespace UI {
+
+struct TableStyleInfo {
+	explicit TableStyleInfo(UI::FontStyleInfo* init_enabled, UI::FontStyleInfo* init_disabled) :
+		enabled_(init_enabled), disabled_(init_disabled) {}
+
+	const UI::FontStyleInfo& enabled() const {
+		return *enabled_.get();
+	}
+	const UI::FontStyleInfo& disabled() const {
+		return *disabled_.get();
+	}
+
+private:
+	std::unique_ptr<const UI::FontStyleInfo> enabled_;
+	std::unique_ptr<const UI::FontStyleInfo> disabled_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_TABLE_STYLE_H

=== added file 'src/graphic/styles/text_panel_style.h'
--- src/graphic/styles/text_panel_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/text_panel_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_TEXT_PANEL_STYLE_H
+#define WL_GRAPHIC_STYLES_TEXT_PANEL_STYLE_H
+
+#include <memory>
+
+#include "graphic/styles/font_style.h"
+#include "graphic/styles/panel_styles.h"
+
+namespace UI {
+
+enum class SliderStyle { kFsMenu, kWuiLight, kWuiDark };
+
+struct TextPanelStyleInfo {
+	explicit TextPanelStyleInfo(const UI::FontStyleInfo* init_font, const UI::PanelStyleInfo* init_background) :
+		background_(init_background),
+		font_(init_font) {
+	}
+	explicit TextPanelStyleInfo(const TextPanelStyleInfo& other) :
+		background_(new UI::PanelStyleInfo(other.background())),
+		font_(new UI::FontStyleInfo(other.font())) {
+	}
+	TextPanelStyleInfo& operator=(const TextPanelStyleInfo& other) = default;
+
+	const UI::FontStyleInfo& font() const {
+		return *font_.get();
+	}
+	void set_font(const UI::FontStyleInfo& new_font)  {
+		font_.reset(new UI::FontStyleInfo(new_font));
+	}
+
+	const UI::PanelStyleInfo& background() const {
+		return *background_.get();
+	}
+
+private:
+	std::unique_ptr<const UI::PanelStyleInfo> background_;
+	std::unique_ptr<const UI::FontStyleInfo> font_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_TEXT_PANEL_STYLE_H

=== added file 'src/graphic/styles/ware_info_style.h'
--- src/graphic/styles/ware_info_style.h	1970-01-01 00:00:00 +0000
+++ src/graphic/styles/ware_info_style.h	2019-05-03 19:28:13 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_STYLES_WARE_INFO_STYLE_H
+#define WL_GRAPHIC_STYLES_WARE_INFO_STYLE_H
+
+#include <memory>
+
+#include "graphic/color.h"
+#include "graphic/styles/font_style.h"
+#include "graphic/image.h"
+
+namespace UI {
+
+enum class WareInfoStyle {
+	kNormal,
+	kHighlight
+};
+
+struct WareInfoStyleInfo {
+	explicit WareInfoStyleInfo(UI::FontStyleInfo* init_header_font,
+							   UI::FontStyleInfo* init_info_font,
+							   const Image* init_icon_background_image,
+							   const RGBColor& init_icon_frame,
+							   const RGBColor& init_icon_background,
+							   const RGBColor& init_info_background) :
+		header_font_(init_header_font),
+		info_font_(init_info_font),
+		icon_background_image_(init_icon_background_image),
+		icon_frame_(init_icon_frame),
+		icon_background_(init_icon_background),
+		info_background_(init_info_background) {}
+
+	const UI::FontStyleInfo& header_font() const {
+		return *header_font_.get();
+	}
+	const UI::FontStyleInfo& info_font() const {
+		return *info_font_.get();
+	}
+	const Image* icon_background_image() const {
+		return icon_background_image_;
+	}
+	const RGBColor& icon_frame() const {
+		return icon_frame_;
+	}
+	const RGBColor& icon_background() const {
+		return icon_background_;
+	}
+	const RGBColor& info_background() const {
+		return info_background_;
+	}
+
+private:
+	std::unique_ptr<const UI::FontStyleInfo> header_font_;
+	std::unique_ptr<const UI::FontStyleInfo> info_font_;
+	const Image* icon_background_image_;
+	const RGBColor icon_frame_;
+	const RGBColor icon_background_;
+	const RGBColor info_background_;
+};
+
+}  // namespace UI
+
+#endif  // end of include guard: WL_GRAPHIC_STYLES_WARE_INFO_STYLE_H

=== modified file 'src/graphic/text/CMakeLists.txt'
--- src/graphic/text/CMakeLists.txt	2018-03-02 06:01:51 +0000
+++ src/graphic/text/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -36,12 +36,12 @@
     graphic
     graphic_align
     graphic_color
+    graphic_fonthandler
     graphic_image_cache
     graphic_image_io
     graphic_playercolor
     graphic_sdl_utils
     graphic_surface
-    graphic_text_layout
     io_fileread
     io_filesystem
     scripting_lua_interface

=== modified file 'src/graphic/text/font_set.cc'
--- src/graphic/text/font_set.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/text/font_set.cc	2019-05-03 19:28:13 +0000
@@ -27,6 +27,7 @@
 
 #include "base/i18n.h"
 #include "base/log.h"
+#include "graphic/text/bidi.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "scripting/lua_interface.h"
 #include "scripting/lua_table.h"

=== modified file 'src/graphic/text/font_set.h'
--- src/graphic/text/font_set.h	2019-02-23 11:00:49 +0000
+++ src/graphic/text/font_set.h	2019-05-03 19:28:13 +0000
@@ -25,6 +25,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "graphic/align.h"
 #include "scripting/lua_table.h"
 
 namespace UI {
@@ -32,8 +33,6 @@
 // Contains font information for a locale
 struct FontSet {
 
-	enum class Face { kSans, kSerif, kCondensed };
-
 	static constexpr const char* kFallbackFont = "DejaVu/DejaVuSans.ttf";
 
 	/// Create a fontset from i18n/fonts.lua
@@ -62,6 +61,7 @@
 	// Returns true iff the fontset's script is written from right to left.
 	bool is_rtl() const;
 
+
 private:
 	/// Parses font information for the given fontset name from Lua.
 	/// The fontset definitions are in i18n/fonts.lua

=== modified file 'src/graphic/text/rendered_text.cc'
--- src/graphic/text/rendered_text.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/text/rendered_text.cc	2019-05-03 19:28:13 +0000
@@ -22,7 +22,6 @@
 #include <memory>
 
 #include "graphic/graphic.h"
-#include "graphic/text_layout.h"
 
 namespace UI {
 // RenderedRect

=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/text/rt_render.cc	2019-05-03 19:28:13 +0000
@@ -47,7 +47,6 @@
 #include "graphic/text/rt_parse.h"
 #include "graphic/text/sdl_ttf_font.h"
 #include "graphic/text/textstream.h"
-#include "graphic/text_layout.h"
 #include "graphic/texture.h"
 #include "io/filesystem/filesystem_exceptions.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -56,6 +55,17 @@
 
 static const uint16_t INFINITE_WIDTH = 65535;  // 2^16-1
 
+/**
+ * This function replaces some HTML entities in strings, e.g. %nbsp;.
+ * It is used by the renderer after the tags have been parsed.
+ */
+void replace_entities(std::string* text) {
+	boost::replace_all(*text, "&gt;", ">");
+	boost::replace_all(*text, "&lt;", "<");
+	boost::replace_all(*text, "&nbsp;", " ");
+	boost::replace_all(*text, "&amp;", "&");  // Must be performed last
+}
+
 // Helper Stuff
 struct Borders {
 	Borders() {
@@ -92,6 +102,7 @@
 	uint8_t spacing;
 	UI::Align halign;
 	UI::Align valign;
+	const bool is_rtl;
 	std::string reference;
 };
 
@@ -1095,7 +1106,7 @@
 			word = ts.till_any_or_end(" \t\n\r");
 			ns.fontset = i18n::find_fontset(word.c_str(), fontsets_);
 			if (!word.empty()) {
-				replace_entities(&word);
+				RT::replace_entities(&word);
 				bool word_is_bidi = i18n::has_rtl_character(word.c_str());
 				word = i18n::make_ligatures(word.c_str());
 				if (word_is_bidi || i18n::has_rtl_character(previous_word.c_str())) {
@@ -1138,7 +1149,7 @@
 			word = ts.till_any_or_end(" \t\n\r");
 			ns.fontset = i18n::find_fontset(word.c_str(), fontsets_);
 			if (!word.empty()) {
-				replace_entities(&word);
+				RT::replace_entities(&word);
 				word = i18n::make_ligatures(word.c_str());
 				if (i18n::has_script_character(word.c_str(), UI::FontSets::Selector::kCJK)) {
 					std::vector<std::string> units = i18n::split_cjk_word(word.c_str());
@@ -1223,7 +1234,7 @@
 				nodestyle_.halign = UI::Align::kLeft;
 			}
 		}
-		nodestyle_.halign = mirror_alignment(nodestyle_.halign);
+		nodestyle_.halign = mirror_alignment(nodestyle_.halign, nodestyle_.is_rtl);
 		if (a.has("valign")) {
 			const std::string align = a["valign"].get_string();
 			if (align == "bottom") {
@@ -1696,7 +1707,7 @@
 }
 
 std::shared_ptr<RenderNode>
-Renderer::layout(const std::string& text, uint16_t width, const TagSet& allowed_tags) {
+Renderer::layout(const std::string& text, uint16_t width, bool is_rtl, const TagSet& allowed_tags) {
 	std::unique_ptr<Tag> rt(parser_->parse(text, allowed_tags));
 
 	if (!width) {
@@ -1716,6 +1727,7 @@
 	                           0,
 	                           UI::Align::kLeft,
 	                           UI::Align::kTop,
+							   is_rtl,
 	                           ""};
 
 	RTTagHandler rtrn(
@@ -1730,8 +1742,8 @@
 }
 
 std::shared_ptr<const UI::RenderedText>
-Renderer::render(const std::string& text, uint16_t width, const TagSet& allowed_tags) {
-	std::shared_ptr<RenderNode> node(layout(text, width, allowed_tags));
+Renderer::render(const std::string& text, uint16_t width, bool is_rtl, const TagSet& allowed_tags) {
+	std::shared_ptr<RenderNode> node(layout(text, width, is_rtl, allowed_tags));
 	return std::shared_ptr<const UI::RenderedText>(node->render(texture_cache_));
 }
 }  // namespace RT

=== modified file 'src/graphic/text/rt_render.h'
--- src/graphic/text/rt_render.h	2019-02-23 11:00:49 +0000
+++ src/graphic/text/rt_render.h	2019-05-03 19:28:13 +0000
@@ -70,11 +70,11 @@
 	// Render the given string in the given width. Restricts the allowed tags to
 	// the ones in TagSet.
 	std::shared_ptr<const UI::RenderedText>
-	render(const std::string&, uint16_t width, const TagSet& tagset = TagSet());
+	render(const std::string&, uint16_t width, bool is_rtl, const TagSet& tagset = TagSet());
 
 private:
 	std::shared_ptr<RenderNode>
-	layout(const std::string& text, uint16_t width, const TagSet& allowed_tags);
+	layout(const std::string& text, uint16_t width, bool is_rtl, const TagSet& allowed_tags);
 
 	std::unique_ptr<FontCache> font_cache_;
 	std::unique_ptr<Parser> parser_;

=== removed file 'src/graphic/text_constants.cc'
--- src/graphic/text_constants.cc	2017-03-04 12:37:17 +0000
+++ src/graphic/text_constants.cc	1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-// Dummy to make CMake happy

=== removed file 'src/graphic/text_constants.h'
--- src/graphic/text_constants.h	2019-02-23 11:00:49 +0000
+++ src/graphic/text_constants.h	1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2006-2019 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef WL_GRAPHIC_TEXT_CONSTANTS_H
-#define WL_GRAPHIC_TEXT_CONSTANTS_H
-
-// Basic constants for often used text attributes.
-
-/// Font Sizes
-#define UI_FONT_SIZE_BIG 22
-#define UI_FONT_SIZE_SMALL 14
-#define UI_FONT_SIZE_MESSAGE 12
-#define UI_FONT_SIZE_ULTRASMALL 10
-constexpr int kMinimumFontSize = 6;
-constexpr int kLineMargin = 1;
-
-/// Font colors
-
-/// Global UI font color
-#define UI_FONT_CLR_FG RGBColor(255, 255, 0)
-#define UI_FONT_CLR_DISABLED RGBColor(127, 127, 127)
-#define UI_FONT_CLR_WARNING RGBColor(255, 22, 22)
-
-/// Tooltip font color
-#define UI_FONT_TOOLTIP_CLR RGBColor(255, 255, 0)
-
-/// Colors for good/ok/bad
-#define UI_FONT_CLR_BRIGHT RGBColor(255, 250, 170)
-#define UI_FONT_CLR_DARK RGBColor(163, 144, 19)
-#define UI_FONT_CLR_BAD RGBColor(187, 0, 0)
-#define UI_FONT_CLR_OK RGBColor(255, 225, 30)
-#define UI_FONT_CLR_GOOD RGBColor(0, 187, 0)
-
-#endif  // end of include guard: WL_GRAPHIC_TEXT_CONSTANTS_H

=== modified file 'src/graphic/text_layout.cc'
--- src/graphic/text_layout.cc	2019-04-18 16:50:35 +0000
+++ src/graphic/text_layout.cc	2019-05-03 19:28:13 +0000
@@ -19,18 +19,14 @@
 
 #include "graphic/text_layout.h"
 
-#include <map>
-
-#include <SDL_ttf.h>
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
 
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/image.h"
-#include "graphic/text/bidi.h"
+#include "graphic/style_manager.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 
 namespace {
 bool is_paragraph(const std::string& text) {
@@ -40,8 +36,35 @@
 bool is_div(const std::string& text) {
 	return boost::starts_with(text, "<div");
 }
+
+std::string as_richtext_paragraph(const std::string& text, UI::Align align) {
+	std::string alignment = "left";
+	switch (align) {
+	case UI::Align::kCenter:
+		alignment = "center";
+		break;
+	case UI::Align::kRight:
+		alignment = "right";
+		break;
+	case UI::Align::kLeft:
+		alignment = "left";
+		break;
+	}
+
+	static boost::format f("<rt><p align=%s>%s</p></rt>");
+	f % alignment;
+	f % text;
+	return f.str();
+}
 }  // namespace
 
+int text_width(const std::string& text, const UI::FontStyleInfo& style, float scale) {
+	UI::FontStyleInfo info(style);
+	info.set_size(info.size() * scale - UI::g_fh->fontset()->size_offset());
+	return UI::g_fh
+	   ->render(as_editor_richtext_paragraph(text, info))->width();
+}
+
 void replace_entities(std::string* text) {
 	boost::replace_all(*text, "&gt;", ">");
 	boost::replace_all(*text, "&lt;", "<");
@@ -49,21 +72,18 @@
 	boost::replace_all(*text, "&amp;", "&");  // Must be performed last
 }
 
-int text_width(const std::string& text, int ptsize) {
-	return UI::g_fh
-	   ->render(as_editorfont(
-	      text.substr(0, g_gr->max_texture_size_for_font_rendering() / text_height() - 1),
-	      ptsize - UI::g_fh->fontset()->size_offset()))
-	   ->width();
-}
-
-int text_height(int ptsize, UI::FontSet::Face face) {
-	return UI::g_fh
-	   ->render(as_aligned(UI::g_fh->fontset()->representative_character(), UI::Align::kLeft,
-	                       ptsize - UI::g_fh->fontset()->size_offset(), RGBColor(0, 0, 0), face))
+int text_height(const UI::FontStyleInfo& style, float scale) {
+	UI::FontStyleInfo info(style);
+	info.set_size(info.size() * scale - UI::g_fh->fontset()->size_offset());
+	return UI::g_fh
+	   ->render(as_richtext_paragraph(UI::g_fh->fontset()->representative_character(), info))
 	   ->height();
 }
 
+int text_height(UI::FontStyle style, float scale) {
+	return text_height(g_gr->styles().font_style(style), scale);
+}
+
 std::string richtext_escape(const std::string& given_text) {
 	std::string text = given_text;
 	boost::replace_all(text, "&", "&amp;");  // Must be performed first
@@ -72,83 +92,14 @@
 	return text;
 }
 
-std::string as_game_tip(const std::string& txt) {
-	static boost::format f(
-	   "<rt><p align=center><font color=21211b face=serif size=16>%s</font></p></rt>");
-	f % txt;
-	return f.str();
-}
-
-std::string
-as_uifont(const std::string& txt, int size, const RGBColor& clr, UI::FontSet::Face face) {
-	return as_aligned(txt, UI::Align::kLeft, size, clr, face);
-}
-
-std::string
-as_condensed(const std::string& text, UI::Align align, int ptsize, const RGBColor& clr) {
-	return as_aligned(text, align, ptsize, clr, UI::FontSet::Face::kCondensed);
-}
-
-std::string as_editorfont(const std::string& text, int ptsize, const RGBColor& clr) {
-	// UI Text is always bold due to historic reasons
-	static boost::format f(
-	   "<rt keep_spaces=1><p><font face=sans size=%i bold=1 shadow=1 color=%s>%s</font></p></rt>");
-	f % ptsize;
-	f % clr.hex_value();
-	f % richtext_escape(text);
-	return f.str();
-}
-
-std::string as_aligned(const std::string& txt,
-                       UI::Align align,
-                       int ptsize,
-                       const RGBColor& clr,
-                       UI::FontSet::Face face) {
-	std::string alignment = "left";
-	switch (align) {
-	case UI::Align::kCenter:
-		alignment = "center";
-		break;
-	case UI::Align::kRight:
-		alignment = "right";
-		break;
-	case UI::Align::kLeft:
-		alignment = "left";
-		break;
-	}
-
-	std::string font_face = "sans";
-
-	switch (face) {
-	case UI::FontSet::Face::kCondensed:
-		font_face = "condensed";
-		break;
-	case UI::FontSet::Face::kSerif:
-		font_face = "serif";
-		break;
-	case UI::FontSet::Face::kSans:
-		font_face = "sans";
-		break;
-	}
-
-	// UI Text is always bold due to historic reasons
-	static boost::format f(
-	   "<rt><p align=%s><font face=%s size=%i bold=1 shadow=1 color=%s>%s</font></p></rt>");
-	f % alignment;
-	f % font_face;
-	f % ptsize;
-	f % clr.hex_value();
-	f % txt;
-	return f.str();
-}
-
 /// Bullet list item
-std::string as_listitem(const std::string& txt, int ptsize, const RGBColor& clr) {
+std::string as_listitem(const std::string& txt, UI::FontStyle style) {
 	static boost::format f("<div width=100%%><div><p><font size=%d "
 	                       "color=%s>•</font></p></div><div><p><space gap=6></p></div><div "
 	                       "width=*><p><font size=%d color=%s>%s<vspace "
 	                       "gap=6></font></p></div></div>");
-	f % ptsize % clr.hex_value() % ptsize % clr.hex_value() % txt;
+	const UI::FontStyleInfo& font_style = g_gr->styles().font_style(style);
+	f % font_style.size() % font_style.color().hex_value() % font_style.size() % font_style.color().hex_value() % txt;
 	return f.str();
 }
 
@@ -158,33 +109,78 @@
 	return f.str();
 }
 
-std::string as_tooltip(const std::string& txt) {
-	static boost::format f("<rt><p><font face=sans size=%i bold=1 color=%s>%s</font></p></rt>");
-
-	f % UI_FONT_SIZE_SMALL;
-	f % UI_FONT_TOOLTIP_CLR.hex_value();
-	f % txt;
-	return f.str();
-}
-
-std::string as_waresinfo(const std::string& txt) {
-	static boost::format f("<rt><p><font face=condensed size=10 bold=0 color=%s>%s</font></p></rt>");
-	f % UI_FONT_TOOLTIP_CLR.hex_value();
-	f % txt;
-	return f.str();
+std::string as_richtext_paragraph(const std::string& text, UI::FontStyle style, UI::Align align) {
+	return as_richtext_paragraph(text, g_gr->styles().font_style(style), align);
+}
+
+std::string as_richtext_paragraph(const std::string& text, const UI::FontStyleInfo& style, UI::Align align) {
+	return as_richtext_paragraph(style.as_font_tag(text), align);
+}
+
+std::string as_editor_richtext_paragraph(const std::string& text, const UI::FontStyleInfo& style) {
+	static boost::format f("<rt keep_spaces=1><p>%s</p></rt>");
+	f % style.as_font_tag(text);
+	return f.str();
+}
+
+std::string as_game_tip(const std::string& txt) {
+	static boost::format f("<rt><p align=center>%s</p></rt>");
+	f % g_gr->styles().font_style(UI::FontStyle::kFsMenuGameTip).as_font_tag(txt);
+	return f.str();
+}
+
+std::string as_mapobject_message(const std::string& image_filename, int width, const std::string& txt, const RGBColor* player_color) {
+	static boost::format f_color("<div padding_r=10><p><img width=%d src=%s color=%s></p></div>"
+						   "<div width=*><p>%s</p></div>");
+	static boost::format f_nocolor("<div padding_r=10><p><img width=%d src=%s></p></div>"
+						   "<div width=*><p>%s</p></div>");
+	if (player_color != nullptr) {
+		f_color % width;
+		f_color % image_filename;
+		f_color % player_color->hex_value();
+		f_color % g_gr->styles().font_style(UI::FontStyle::kWuiMessageParagraph).as_font_tag(txt);
+		return f_color.str();
+	} else {
+		f_nocolor % width;
+		f_nocolor % image_filename;
+		f_nocolor % g_gr->styles().font_style(UI::FontStyle::kWuiMessageParagraph).as_font_tag(txt);
+		return f_nocolor.str();
+	}
 }
 
 std::string as_message(const std::string& heading, const std::string& body) {
 	return (
 	   (boost::format(
-	       "<rt><p><font size=18 bold=1 color=D1D1D1>%s<br></font></p><vspace gap=6>%s</rt>") %
-	    heading %
+	       "<rt><p>%s<br></p><vspace gap=6>%s</rt>") %
+	    g_gr->styles().font_style(UI::FontStyle::kWuiMessageHeading).as_font_tag(heading) %
 	    (is_paragraph(body) || is_div(body) ?
 	        body :
-	        (boost::format("<p><font size=%d>%s</font></p>") % UI_FONT_SIZE_MESSAGE % body).str()))
+	        (boost::format("<p>%s</p>") %
+	         g_gr->styles().font_style(UI::FontStyle::kWuiMessageParagraph).as_font_tag(body))
+	           .str()))
 	      .str());
 }
 
+std::shared_ptr<const UI::RenderedText> autofit_text(const std::string& text,
+																	  const UI::FontStyleInfo& font_info,
+																	  int width) {
+	std::shared_ptr<const UI::RenderedText> rendered_text =
+	   UI::g_fh->render(as_richtext_paragraph(text, font_info));
+
+	// Autoshrink if it doesn't fit
+	if (width > 0 && rendered_text->width() > width) {
+		const int minimum_size = g_gr->styles().minimum_font_size();
+		// We take a copy, because we are changing values during the autofit.
+		UI::FontStyleInfo temp_font_info(font_info);
+		temp_font_info.make_condensed();
+		while (rendered_text->width() > width && temp_font_info.size() >= minimum_size) {
+			rendered_text = UI::g_fh->render(as_richtext_paragraph(text, temp_font_info));
+			temp_font_info.set_size(temp_font_info.size() - 1);
+		}
+	}
+	return rendered_text;
+}
+
 std::string as_heading_with_content(const std::string& header,
                                     const std::string& content,
                                     UI::PanelStyle style,
@@ -192,18 +188,16 @@
                                     bool noescape) {
 	switch (style) {
 	case UI::PanelStyle::kFsMenu:
-		return (boost::format(
-		           "<p><font size=%i bold=1 shadow=1>%s%s <font color=D1D1D1>%s</font></font></p>") %
-		        UI_FONT_SIZE_SMALL % (is_first ? "" : "<vspace gap=9>") %
-		        (noescape ? header : richtext_escape(header)) %
-		        (noescape ? content : richtext_escape(content)))
+		return (boost::format("<p>%s%s %s</p>") %
+		         (is_first ? "" : "<vspace gap=9>") %
+		        g_gr->styles().font_style(UI::FontStyle::kFsMenuInfoPanelHeading).as_font_tag(noescape ? header : richtext_escape(header)) %
+		        g_gr->styles().font_style(UI::FontStyle::kFsMenuInfoPanelParagraph).as_font_tag(noescape ? content : richtext_escape(content)))
 		   .str();
 	case UI::PanelStyle::kWui:
-		return (boost::format(
-		           "<p><font size=%i>%s<font bold=1 color=D1D1D1>%s</font> %s</font></p>") %
-		        UI_FONT_SIZE_SMALL % (is_first ? "" : "<vspace gap=6>") %
-		        (noescape ? header : richtext_escape(header)) %
-		        (noescape ? content : richtext_escape(content)))
+		return (boost::format("<p>%s%s %s</p>") %
+		        (is_first ? "" : "<vspace gap=6>") %
+		        g_gr->styles().font_style(UI::FontStyle::kWuiInfoPanelHeading).as_font_tag(noescape ? header : richtext_escape(header)) %
+		        g_gr->styles().font_style(UI::FontStyle::kWuiInfoPanelParagraph).as_font_tag(noescape ? content : richtext_escape(content)))
 		   .str();
 	}
 	NEVER_HERE();
@@ -212,12 +206,16 @@
 std::string as_heading(const std::string& txt, UI::PanelStyle style, bool is_first) {
 	switch (style) {
 	case UI::PanelStyle::kFsMenu:
-		return (boost::format("<p><font size=%i bold=1 shadow=1>%s%s</font></p>") %
-		        UI_FONT_SIZE_SMALL % (is_first ? "" : "<vspace gap=9>") % richtext_escape(txt))
+		return (boost::format("<p>%s%s</p>") % (is_first ? "" : "<vspace gap=9>") %
+		        g_gr->styles()
+		           .font_style(UI::FontStyle::kFsMenuInfoPanelHeading)
+		           .as_font_tag(richtext_escape(txt)))
 		   .str();
 	case UI::PanelStyle::kWui:
-		return (boost::format("<p><font size=%i bold=1 color=D1D1D1>%s%s</font></p>") %
-		        UI_FONT_SIZE_SMALL % (is_first ? "" : "<vspace gap=6>") % richtext_escape(txt))
+		return (boost::format("<p>%s%s</p>") % (is_first ? "" : "<vspace gap=6>") %
+		        g_gr->styles()
+		           .font_style(UI::FontStyle::kWuiInfoPanelHeading)
+		           .as_font_tag(richtext_escape(txt)))
 		   .str();
 	}
 	NEVER_HERE();
@@ -226,78 +224,17 @@
 std::string as_content(const std::string& txt, UI::PanelStyle style) {
 	switch (style) {
 	case UI::PanelStyle::kFsMenu:
-		return (boost::format("<p><font size=%i color=D1D1D1 shadow=1><vspace gap=2>%s</font></p>") %
-		        UI_FONT_SIZE_SMALL % richtext_escape(txt))
+		return (boost::format("<p><vspace gap=2>%s</p>") %
+		        g_gr->styles()
+		           .font_style(UI::FontStyle::kFsMenuInfoPanelParagraph)
+		           .as_font_tag(richtext_escape(txt)))
 		   .str();
 	case UI::PanelStyle::kWui:
-		return (boost::format("<p><font size=%i><vspace gap=2>%s</font></p>") %
-		        (UI_FONT_SIZE_SMALL - 2) % richtext_escape(txt))
+		return (boost::format("<p><vspace gap=2>%s</p>") %
+		        g_gr->styles()
+		           .font_style(UI::FontStyle::kWuiInfoPanelParagraph)
+		           .as_font_tag(richtext_escape(txt)))
 		   .str();
 	}
 	NEVER_HERE();
 }
-
-std::shared_ptr<const UI::RenderedText>
-autofit_ui_text(const std::string& text, int width, RGBColor color, int fontsize) {
-	std::shared_ptr<const UI::RenderedText> result =
-	   UI::g_fh->render(as_uifont(richtext_escape(text), fontsize, color));
-	if (width > 0) {  // Autofit
-		for (; result->width() > width && fontsize >= kMinimumFontSize; --fontsize) {
-			result = UI::g_fh->render(
-			   as_condensed(richtext_escape(text), UI::Align::kLeft, fontsize, color));
-		}
-	}
-	return result;
-}
-
-namespace UI {
-
-/**
- * This mirrors the horizontal alignment for RTL languages.
- *
- * Do not store this value as it is based on the global font setting.
- *
- * If 'checkme' is not empty, mirror the alignment if the first 20 characters contain an RTL
- * character. Otherwise, mirror if the current fontset is RTL.
- */
-Align mirror_alignment(Align alignment, const std::string& checkme) {
-	bool do_swap_alignment = checkme.empty() ? UI::g_fh->fontset()->is_rtl() :
-	                                           i18n::has_rtl_character(checkme.c_str(), 20);
-	if (do_swap_alignment) {
-		switch (alignment) {
-		case Align::kLeft:
-			alignment = Align::kRight;
-			break;
-		case Align::kRight:
-			alignment = Align::kLeft;
-			break;
-		case Align::kCenter:
-			break;
-		}
-	}
-	return alignment;
-}
-
-/**
- * Align pt horizontally to match align based on width w.
- *
- * When correcting for align, we never move from pixel boundaries to
- * sub-pixels, because this might lead from pixel-perfect rendering to
- * subsampled rendering - this can lead to blurry texts. That is why we
- * never do float divisions in this function.
- */
-void correct_for_align(Align align, uint32_t w, Vector2i* pt) {
-
-	if (align == Align::kCenter)
-		pt->x -= w / 2;
-	else if (align == Align::kRight)
-		pt->x -= w;
-}
-
-/**
- * Adjust the y coordinate in 'point 'pt' to vertically center an element with height 'h'.
- */
-void center_vertically(uint32_t h, Vector2i* pt) {
-	pt->y -= h / 2;
-}
-}  // namespace UI

=== modified file 'src/graphic/text_layout.h'
--- src/graphic/text_layout.h	2019-04-18 16:50:35 +0000
+++ src/graphic/text_layout.h	2019-05-03 19:28:13 +0000
@@ -23,12 +23,13 @@
 #include <string>
 
 #include "graphic/align.h"
+#include "graphic/styles/font_style.h"
+#include "graphic/styles/panel_styles.h"
+#include "graphic/text/rendered_text.h"
 #include "graphic/color.h"
 #include "graphic/font_handler.h"
 #include "graphic/image.h"
-#include "graphic/panel_styles.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 
 /**
  * This function replaces some HTML entities in strings, e.g. %nbsp;.
@@ -37,16 +38,17 @@
 void replace_entities(std::string* text);
 
 /**
- * Returns the exact width of the text rendered as editorfont for the given font size.
- * This function is inefficient; only call when we need the exact width.
- */
-int text_width(const std::string& text, int ptsize = UI_FONT_SIZE_SMALL);
+  * Returns the exact width of the text rendered as editorfont for the given font size.
+  * This function is inefficient; only call when we need the exact width.
+  */
+int text_width(const std::string& text, const UI::FontStyleInfo& style, float scale = 1.0f);
 
 /**
- * Returns the exact height of the text rendered for the given font size and face.
- * This function is inefficient; only call when we need the exact height.
- */
-int text_height(int ptsize = UI_FONT_SIZE_SMALL, UI::FontSet::Face face = UI::FontSet::Face::kSans);
+  * Returns the exact height of the text rendered for the given font size and face.
+  * This function is inefficient; only call when we need the exact height.
+  */
+int text_height(const UI::FontStyleInfo& style, float scale = 1.0f);
+int text_height(UI::FontStyle style, float scale = 1.0f);
 
 /**
  * Checks it the given string is RichText or not. Does not do validity checking.
@@ -60,42 +62,34 @@
  */
 std::string richtext_escape(const std::string& given_text);
 
+std::string as_richtext(const std::string&);
+
 /**
  * Convenience functions to convert simple text into a valid block
  * of rich text which can be rendered.
  */
-std::string as_uifont(const std::string&,
-                      int ptsize = UI_FONT_SIZE_SMALL,
-                      const RGBColor& clr = UI_FONT_CLR_FG,
-                      UI::FontSet::Face face = UI::FontSet::Face::kSans);
-
-// Same as as_aligned, but with the condensed font preselected.
-std::string as_condensed(const std::string& text,
-                         UI::Align align = UI::Align::kLeft,
-                         int ptsize = UI_FONT_SIZE_SMALL,
-                         const RGBColor& clr = UI_FONT_CLR_FG);
-
-std::string as_editorfont(const std::string& text,
-                          int ptsize = UI_FONT_SIZE_SMALL,
-                          const RGBColor& clr = UI_FONT_CLR_FG);
-
-std::string as_aligned(const std::string& txt,
-                       UI::Align align,
-                       int ptsize = UI_FONT_SIZE_SMALL,
-                       const RGBColor& clr = UI_FONT_CLR_FG,
-                       UI::FontSet::Face face = UI::FontSet::Face::kSans);
-
-std::string as_listitem(const std::string&,
-                        int ptsize = UI_FONT_SIZE_SMALL,
-                        const RGBColor& clr = UI_FONT_CLR_FG);
-
-std::string as_richtext(const std::string&);
-std::string as_tooltip(const std::string&);
-std::string as_waresinfo(const std::string&);
+std::string as_richtext_paragraph(const std::string& text, UI::FontStyle style, UI::Align align = UI::Align::kLeft);
+std::string as_richtext_paragraph(const std::string& text, const UI::FontStyleInfo& style, UI::Align align = UI::Align::kLeft);
+std::string as_editor_richtext_paragraph(const std::string& text, const UI::FontStyleInfo& style);
+
+std::string as_listitem(const std::string&, UI::FontStyle style);
+
 std::string as_game_tip(const std::string&);
+std::string as_mapobject_message(const std::string& image_filename, int width, const std::string& txt, const RGBColor* player_color = nullptr);
 std::string as_message(const std::string& heading, const std::string& body);
 
 /**
+
+  * Render 'text' with the given font style. If 'width' > 0 and the rendered image is too
+  * wide, it will first use the condensed font face and then make the text
+  * smaller until it fits 'width'. The resulting font size will not go below
+  * 'StyleManager::minimum_font_size()'.
+  */
+std::shared_ptr<const UI::RenderedText> autofit_text(const std::string& text,
+																	  const UI::FontStyleInfo& font_info,
+																	  int width);
+
+/**
  * 'is_first' omits the vertical gap before the line.
  * 'noescape' is needed for error message formatting and does not call richtext_escape. */
 std::string as_heading_with_content(const std::string& header,
@@ -112,24 +106,4 @@
 /// Paragraph in menu info texts
 std::string as_content(const std::string& txt, UI::PanelStyle style);
 
-/**
- * Render 'text' as ui_font. If 'width' > 0 and the rendered image is too
- * wide, it will first use the condensed font face and then make the text
- * smaller until it fits 'width'. The resulting font size will not go below
- * 'kMinimumFontSize'.
- */
-std::shared_ptr<const UI::RenderedText> autofit_ui_text(const std::string& text,
-                                                        int width = 0,
-                                                        RGBColor color = UI_FONT_CLR_FG,
-                                                        int fontsize = UI_FONT_SIZE_SMALL);
-
-namespace UI {
-
-Align mirror_alignment(Align alignment, const std::string& checkme = "");
-
-void center_vertically(uint32_t h, Vector2i* pt);
-void correct_for_align(Align, uint32_t w, Vector2i* pt);
-
-}  // namespace UI
-
 #endif  // end of include guard: WL_GRAPHIC_TEXT_LAYOUT_H

=== modified file 'src/graphic/wordwrap.cc'
--- src/graphic/wordwrap.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/wordwrap.cc	2019-05-03 19:28:13 +0000
@@ -36,6 +36,30 @@
 #include "graphic/text/font_io.h"
 #include "graphic/text_layout.h"
 
+namespace {
+std::string as_editorfont(const std::string& text, int ptsize, const RGBColor& clr) {
+	// UI Text is always bold due to historic reasons
+	static boost::format f(
+	   "<rt keep_spaces=1><p><font face=sans size=%i bold=1 shadow=1 color=%s>%s</font></p></rt>");
+	f % ptsize;
+	f % clr.hex_value();
+	f % richtext_escape(text);
+	return f.str();
+}
+
+int text_width(const std::string& text, int ptsize) {
+	RGBColor color(0, 0, 0);
+	return UI::g_fh->render(as_editorfont(text, ptsize - UI::g_fh->fontset()->size_offset(), color))
+	   ->width();
+}
+
+int text_height(int ptsize) {
+	RGBColor font_color(0, 0, 0);
+	const UI::FontStyleInfo font_info("sans", font_color, ptsize, false, false, false, false);
+	return UI::g_fh->render(as_richtext_paragraph(UI::g_fh->fontset()->representative_character(), font_info))->height();
+}
+} // namespace
+
 namespace UI {
 
 WordWrap::WordWrap(int fontsize, const RGBColor& color, uint32_t gwrapwidth)
@@ -299,7 +323,7 @@
 
 	++where.y;
 
-	Align alignment = mirror_alignment(align);
+	Align alignment = mirror_alignment(align, g_fh->fontset()->is_rtl());
 
 	const int fontheight = text_height(fontsize_);
 	for (uint32_t line = 0; line < lines_.size(); ++line, where.y += fontheight) {

=== modified file 'src/graphic/wordwrap.h'
--- src/graphic/wordwrap.h	2019-02-23 11:00:49 +0000
+++ src/graphic/wordwrap.h	2019-05-03 19:28:13 +0000
@@ -27,8 +27,8 @@
 #include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/color.h"
+#include "graphic/graphic.h"
 #include "graphic/text/sdl_ttf_font.h"
-#include "graphic/text_constants.h"
 
 class RenderTarget;
 
@@ -38,9 +38,9 @@
  * Helper struct that provides word wrapping and related functionality.
  */
 struct WordWrap {
-	WordWrap(int fontsize = UI_FONT_SIZE_SMALL,
-	         const RGBColor& color = UI_FONT_CLR_FG,
-	         uint32_t wrapwidth = std::numeric_limits<uint32_t>::max());
+	static constexpr int kLineMargin = 1;
+
+	explicit WordWrap(int fontsize, const RGBColor& color, uint32_t wrapwidth);
 
 	void set_wrapwidth(uint32_t wrapwidth);
 

=== modified file 'src/io/filesystem/filesystem.cc'
--- src/io/filesystem/filesystem.cc	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/filesystem.cc	2019-05-03 19:28:13 +0000
@@ -205,7 +205,7 @@
 	   (boost::format(pgettext("illegal_filename_characters", "%s at the start of the filename")) %
 	    richtext_escape(i18n::localize_list(starting_characters, i18n::ConcatenateWith::OR)))
 	      .str(),
-	   UI_FONT_SIZE_MESSAGE));
+	   UI::FontStyle::kWuiMessageParagraph));
 
 	const std::string illegal(as_listitem(
 	   /** TRANSLATORS: Tooltip entry for characters in illegal filenames.
@@ -213,7 +213,7 @@
 	   (boost::format(pgettext("illegal_filename_characters", "%s anywhere in the filename")) %
 	    richtext_escape(i18n::localize_list(illegal_filename_characters, i18n::ConcatenateWith::OR)))
 	      .str(),
-	   UI_FONT_SIZE_MESSAGE));
+	   UI::FontStyle::kWuiMessageParagraph));
 
 	return (boost::format("%s%s%s") %
 	        /** TRANSLATORS: Tooltip header for characters in illegal filenames.

=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt	2019-04-24 06:01:37 +0000
+++ src/logic/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -273,7 +273,6 @@
     graphic_image_io
     graphic_playercolor
     graphic_surface
-    graphic_text_constants
     graphic_text_layout
     helper
     io_fileread

=== modified file 'src/logic/map_objects/immovable.cc'
--- src/logic/map_objects/immovable.cc	2019-04-24 06:01:37 +0000
+++ src/logic/map_objects/immovable.cc	2019-05-03 19:28:13 +0000
@@ -32,7 +32,6 @@
 #include "config.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
 #include "helper.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
@@ -516,9 +515,7 @@
 
 	// Additionally, if statistics are enabled, draw a progression string
 	do_draw_info(draw_text, descr().descname(),
-	             (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_DARK.hex_value() %
-	              (boost::format(_("%i%% built")) % (100 * done / total)).str())
-	                .str(),
+	             g_gr->styles().color_tag((boost::format(_("%i%% built")) % (100 * done / total)).str(), g_gr->styles().building_statistics_style().construction_color()),
 	             point_on_dst, scale, dst);
 }
 

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2019-03-03 08:31:25 +0000
+++ src/logic/map_objects/map_object.cc	2019-05-03 19:28:13 +0000
@@ -32,6 +32,7 @@
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/style_manager.h"
 #include "graphic/text_layout.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
@@ -486,20 +487,25 @@
 	if (scale < 1.f) {
 		return;
 	}
-	const int font_size = scale * UI_FONT_SIZE_SMALL;
+
+	UI::FontStyleInfo census_font(g_gr->styles().building_statistics_style().census_font());
+	census_font.set_size(scale * census_font.size());
 
 	// We always render this so we can have a stable position for the statistics string.
 	std::shared_ptr<const UI::RenderedText> rendered_census =
-	   UI::g_fh->render(as_condensed(census, UI::Align::kCenter, font_size), 120 * scale);
+			UI::g_fh->render(as_richtext_paragraph(census, census_font, UI::Align::kCenter), 120 * scale);
 	Vector2i position = field_on_dst.cast<int>() - Vector2i(0, 48) * scale;
 	if ((draw_text & TextToDraw::kCensus) != TextToDraw::kNone) {
 		rendered_census->draw(*dst, position, UI::Align::kCenter);
 	}
 
 	if ((draw_text & TextToDraw::kStatistics) != TextToDraw::kNone && !statictics.empty()) {
+		UI::FontStyleInfo statistics_font(g_gr->styles().building_statistics_style().statistics_font());
+		statistics_font.set_size(scale * statistics_font.size());
+
 		std::shared_ptr<const UI::RenderedText> rendered_statistics =
-		   UI::g_fh->render(as_condensed(statictics, UI::Align::kCenter, font_size));
-		position.y += rendered_census->height() + text_height(font_size) / 4;
+		   UI::g_fh->render(as_richtext_paragraph(statictics, statistics_font, UI::Align::kCenter));
+		position.y += rendered_census->height() + text_height(statistics_font) / 4;
 		rendered_statistics->draw(*dst, position, UI::Align::kCenter);
 	}
 }

=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc	2019-04-24 06:01:37 +0000
+++ src/logic/map_objects/tribes/building.cc	2019-05-03 19:28:13 +0000
@@ -33,7 +33,7 @@
 #include "economy/input_queue.h"
 #include "economy/request.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
+#include "graphic/text_layout.h"
 #include "io/filesystem/filesystem.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game.h"
@@ -774,13 +774,11 @@
                             bool link_to_building_lifetime,
                             uint32_t throttle_time,
                             uint32_t throttle_radius) {
-	const std::string& img = descr().representative_image_filename();
-	const int width = descr().representative_image()->width();
 	const std::string rt_description =
-	   (boost::format("<div padding_r=10><p><img width=%d src=%s color=%s></p></div>"
-	                  "<div width=*><p><font size=%d>%s</font></p></div>") %
-	    width % img % owner().get_playercolor().hex_value() % UI_FONT_SIZE_MESSAGE % description)
-	      .str();
+			as_mapobject_message(descr().representative_image_filename(),
+								 descr().representative_image()->width(),
+								 description,
+								 &owner().get_playercolor());
 
 	std::unique_ptr<Message> msg(new Message(msgtype, game.get_gametime(), title, icon_filename,
 	                                         heading, rt_description, get_position(),

=== modified file 'src/logic/map_objects/tribes/constructionsite.cc'
--- src/logic/map_objects/tribes/constructionsite.cc	2019-04-24 06:01:37 +0000
+++ src/logic/map_objects/tribes/constructionsite.cc	2019-05-03 19:28:13 +0000
@@ -30,7 +30,6 @@
 #include "graphic/animation.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/game.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
@@ -110,9 +109,7 @@
 
 void ConstructionSite::update_statistics_string(std::string* s) {
 	unsigned int percent = (get_built_per64k() * 100) >> 16;
-	*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_DARK.hex_value() %
-	      (boost::format(_("%i%% built")) % percent))
-	        .str();
+	*s = g_gr->styles().color_tag((boost::format(_("%i%% built")) % percent).str(), g_gr->styles().building_statistics_style().construction_color());
 }
 
 /*

=== modified file 'src/logic/map_objects/tribes/dismantlesite.cc'
--- src/logic/map_objects/tribes/dismantlesite.cc	2019-04-24 06:01:37 +0000
+++ src/logic/map_objects/tribes/dismantlesite.cc	2019-05-03 19:28:13 +0000
@@ -29,7 +29,6 @@
 #include "economy/wares_queue.h"
 #include "graphic/animation.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/game.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
@@ -103,9 +102,7 @@
 */
 void DismantleSite::update_statistics_string(std::string* s) {
 	unsigned int percent = (get_built_per64k() * 100) >> 16;
-	*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_DARK.hex_value() %
-	      (boost::format(_("%u%% dismantled")) % percent))
-	        .str();
+	*s = g_gr->styles().color_tag((boost::format(_("%u%% dismantled")) % percent).str(), g_gr->styles().building_statistics_style().construction_color());
 }
 
 /*

=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
--- src/logic/map_objects/tribes/militarysite.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/militarysite.cc	2019-05-03 19:28:13 +0000
@@ -30,7 +30,6 @@
 #include "base/macros.h"
 #include "economy/flag.h"
 #include "economy/request.h"
-#include "graphic/text_constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/findbob.h"
 #include "logic/game.h"
@@ -394,10 +393,9 @@
 			        .str();
 		}
 	}
-	*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_OK.hex_value() %
-	      // Line break to make Codecheck happy.
-	      *s)
-	        .str();
+	*s = g_gr->styles().color_tag(
+				// Line break to make Codecheck happy.
+				*s, g_gr->styles().building_statistics_style().medium_color());
 }
 
 bool MilitarySite::init(EditorGameBase& egbase) {

=== modified file 'src/logic/map_objects/tribes/productionsite.cc'
--- src/logic/map_objects/tribes/productionsite.cc	2019-04-09 17:16:11 +0000
+++ src/logic/map_objects/tribes/productionsite.cc	2019-05-03 19:28:13 +0000
@@ -32,7 +32,6 @@
 #include "economy/ware_instance.h"
 #include "economy/wares_queue.h"
 #include "economy/workers_queue.h"
-#include "graphic/text_constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
@@ -290,23 +289,17 @@
 		nr_workers += working_positions_[--i].worker ? 1 : 0;
 
 	if (nr_workers == 0) {
-		*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD.hex_value() %
-		      _("(not occupied)"))
-		        .str();
+		*s = g_gr->styles().color_tag(_("(not occupied)"), g_gr->styles().building_statistics_style().low_color());
 		return;
 	}
 
 	if (uint32_t const nr_requests = nr_working_positions - nr_workers) {
-		*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD.hex_value() %
-		      ngettext("Worker missing", "Workers missing", nr_requests))
-		        .str();
+		*s = g_gr->styles().color_tag(ngettext("Worker missing", "Workers missing", nr_requests), g_gr->styles().building_statistics_style().low_color());
 		return;
 	}
 
 	if (is_stopped_) {
-		*s = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BRIGHT.hex_value() %
-		      _("(stopped)"))
-		        .str();
+		*s = g_gr->styles().color_tag(_("(stopped)"), g_gr->styles().building_statistics_style().neutral_color());
 		return;
 	}
 	*s = statistics_string_on_changed_statistics_;
@@ -396,34 +389,32 @@
 
 	const unsigned int lastPercOk = (lastOk * 100) / (STATISTICS_VECTOR_LENGTH / 2);
 
-	std::string color;
-	if (percOk < 33)
-		color = UI_FONT_CLR_BAD.hex_value();
-	else if (percOk < 66)
-		color = UI_FONT_CLR_OK.hex_value();
-	else
-		color = UI_FONT_CLR_GOOD.hex_value();
 	const std::string perc_str =
-	   (boost::format("<font color=%s>%s</font>") % color % (boost::format(_("%i%%")) % percOk))
-	      .str();
-
-	std::string trend;
-	if (lastPercOk > percOk) {
-		trend_ = Trend::kRising;
-		color = UI_FONT_CLR_GOOD.hex_value();
-		trend = "+";
-	} else if (lastPercOk < percOk) {
-		trend_ = Trend::kFalling;
-		color = UI_FONT_CLR_BAD.hex_value();
-		trend = "-";
-	} else {
-		trend_ = Trend::kUnchanged;
-		color = UI_FONT_CLR_BRIGHT.hex_value();
-		trend = "=";
-	}
-	const std::string trend_str = (boost::format("<font color=%s>%s</font>") % color % trend).str();
+			g_gr->styles().color_tag((boost::format(_("%i%%")) % percOk).str(),
+									  (percOk < 33) ? g_gr->styles().building_statistics_style().low_color() :
+															(percOk < 66) ?
+																g_gr->styles().building_statistics_style().medium_color() :
+																g_gr->styles().building_statistics_style().high_color());
 
 	if (0 < percOk && percOk < 100) {
+		RGBColor color = g_gr->styles().building_statistics_style().high_color();
+		std::string trend;
+		if (lastPercOk > percOk) {
+			trend_ = Trend::kRising;
+			color = g_gr->styles().building_statistics_style().high_color();
+			trend = "+";
+		} else if (lastPercOk < percOk) {
+			trend_ = Trend::kFalling;
+			color = g_gr->styles().building_statistics_style().low_color();
+			trend = "-";
+		} else {
+			trend_ = Trend::kUnchanged;
+			color = g_gr->styles().building_statistics_style().neutral_color();
+			trend = "=";
+		}
+
+		const std::string trend_str = g_gr->styles().color_tag((boost::format(_("%i%%")) % trend).str(), color);
+
 		// TODO(GunChleoc): We might need to reverse the order here for RTL languages
 		statistics_string_on_changed_statistics_ =
 		   (boost::format("%s\u2009%s") % perc_str % trend_str).str();

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2019-04-26 20:38:39 +0000
+++ src/logic/map_objects/tribes/ship.cc	2019-05-03 19:28:13 +0000
@@ -31,7 +31,7 @@
 #include "economy/portdock.h"
 #include "economy/wares_queue.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
+#include "graphic/text_layout.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
 #include "logic/findbob.h"
@@ -1061,9 +1061,7 @@
 		case (ShipStates::kSinkAnimation):
 			break;
 		}
-		statistics_string = (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_OK.hex_value() %
-		                     statistics_string)
-		                       .str();
+		statistics_string = g_gr->styles().color_tag(statistics_string, g_gr->styles().building_statistics_style().medium_color());
 	}
 
 	do_draw_info(draw_text, shipname_, statistics_string, calc_drawpos(egbase, point_on_dst, scale),
@@ -1128,10 +1126,7 @@
                         const std::string& description,
                         const std::string& picture) {
 	const std::string rt_description =
-	   (boost::format("<div padding_r=10><p><img src=%s></p></div>"
-	                  "<div width=*><p><font size=%d>%s</font></p></div>") %
-	    picture % UI_FONT_SIZE_MESSAGE % description)
-	      .str();
+			as_mapobject_message(picture, g_gr->images().get(picture)->width(), description);
 
 	get_owner()->add_message(game, std::unique_ptr<Message>(new Message(
 	                                  Message::Type::kSeafaring, game.get_gametime(), title, picture,

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2019-04-27 13:24:29 +0000
+++ src/logic/map_objects/tribes/worker.cc	2019-05-03 19:28:13 +0000
@@ -33,8 +33,9 @@
 #include "economy/portdock.h"
 #include "economy/road.h"
 #include "economy/transfer.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
+#include "graphic/text_layout.h"
 #include "helper.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
@@ -973,13 +974,10 @@
 
 		// Geologist also sends a message notifying the player
 		if (rdescr && rdescr->detectable() && position.field->get_resources_amount()) {
-			const int width = g_gr->images().get(rdescr->representative_image())->width();
-			const std::string message =
-			   (boost::format("<div padding_r=10><p><img width=%d src=%s></p></div>"
-			                  "<div width=*><p><font size=%d>%s</font></p></div>") %
-			    width % ri.descr().representative_image_filename() % UI_FONT_SIZE_MESSAGE %
-			    _("A geologist found resources."))
-			      .str();
+			const std::string rt_description =
+					as_mapobject_message(ri.descr().representative_image_filename(),
+										 g_gr->images().get(rdescr->representative_image())->width(),
+										 _("A geologist found resources."));
 
 			//  We should add a message to the player's message queue - but only,
 			//  if there is not already a similar one in list.
@@ -987,7 +985,7 @@
 			   game,
 			   std::unique_ptr<Message>(new Message(Message::Type::kGeologists, game.get_gametime(),
 			                                        rdescr->descname(), rdescr->representative_image(),
-			                                        rdescr->descname(), message, position, serial_,
+			                                        rdescr->descname(), rt_description, position, serial_,
 			                                        rdescr->name())),
 			   rdescr->timeout_ms(), rdescr->timeout_radius());
 		}

=== modified file 'src/ui_basic/CMakeLists.txt'
--- src/ui_basic/CMakeLists.txt	2019-04-09 04:51:44 +0000
+++ src/ui_basic/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -67,7 +67,6 @@
     graphic_styles
     graphic_surface
     graphic_text
-    graphic_text_constants
     graphic_text_layout
     graphic_wordwrap
     io_filesystem

=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/button.cc	2019-05-03 19:28:13 +0000
@@ -24,7 +24,6 @@
 #include "graphic/image.h"
 #include "graphic/rendertarget.h"
 #include "graphic/style_manager.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "ui_basic/mouse_constants.h"
 
@@ -58,7 +57,7 @@
      time_nextact_(0),
      title_(title_text),
      title_image_(title_image),
-     background_style_(g_gr->styles().button_style(init_style)) {
+     style_(&g_gr->styles().button_style(init_style)) {
 	set_thinks(false);
 	// Don't allow focus
 	assert(!get_can_focus());
@@ -89,7 +88,7 @@
             UI::Button::ImageMode::kShrink) {
 	// Automatically resize for font height and give it a margin.
 	if (h < 1) {
-		int new_height = text_height() + 4;
+		const int new_height = text_height(g_gr->styles().button_style(init_style).enabled().font()) + 4;
 		set_desired_size(w, new_height);
 		set_size(w, new_height);
 	}
@@ -170,8 +169,10 @@
 	const bool is_monochrome =
 	   !enabled_ && static_cast<int>(disable_style_ & ButtonDisableStyle::kMonochrome);
 
+	const UI::TextPanelStyleInfo& style = is_monochrome ? style_->disabled() : style_->enabled();
+
 	// Draw the background
-	draw_background(dst, *background_style_);
+	draw_background(dst, style.background());
 
 	if (is_flat && highlighted_)
 		dst.brighten_rect(Recti(0, 0, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
@@ -216,8 +217,11 @@
 	} else if (title_.length()) {
 		//  Otherwise draw title string centered
 		std::shared_ptr<const UI::RenderedText> rendered_text =
-		   autofit_ui_text(title_, get_inner_w() - 2 * kButtonImageMargin,
-		                   is_monochrome ? UI_FONT_CLR_DISABLED : UI_FONT_CLR_FG);
+				autofit_text(
+					richtext_escape(title_),
+					style.font(),
+					get_inner_w() - 2 * kButtonImageMargin);
+
 		// Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
 		rendered_text->draw(dst, Vector2i((get_w() - rendered_text->width()) / 2,
 		                                  (get_h() - rendered_text->height()) / 2));
@@ -363,8 +367,8 @@
 	                           UI::Button::VisualState::kRaised);
 }
 
-void Button::set_background_style(UI::ButtonStyle bstyle) {
-	background_style_ = g_gr->styles().button_style(bstyle);
+void Button::set_style(UI::ButtonStyle bstyle) {
+	style_ = &g_gr->styles().button_style(bstyle);
 }
 
 void Button::toggle() {

=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/button.h	2019-05-03 19:28:13 +0000
@@ -25,7 +25,7 @@
 #include <boost/signals2.hpp>
 
 #include "graphic/color.h"
-#include "graphic/text_layout.h"
+#include "graphic/styles/button_style.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -146,7 +146,7 @@
 	void set_perm_pressed(bool pressed);
 
 	/// Change the background style of the button.
-	void set_background_style(UI::ButtonStyle bstyle);
+	void set_style(UI::ButtonStyle bstyle);
 
 	/// Convenience function. Toggles between raised and permpressed style
 	void toggle();
@@ -172,7 +172,7 @@
 	std::string title_;         //  title string used when title_image_ == nullptr
 	const Image* title_image_;  //  custom icon on the button
 
-	const UI::PanelStyleInfo* background_style_;  // Background color and texture. Not owned.
+	const UI::ButtonStyleInfo* style_;  // Background color and texture. Not owned.
 };
 
 }  // namespace UI

=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/checkbox.cc	2019-05-03 19:28:13 +0000
@@ -80,7 +80,7 @@
 		}
 		rendered_text_ = label_text_.empty() ?
 		                    nullptr :
-		                    UI::g_fh->render(as_uifont(label_text_), text_width(get_w(), pic_width));
+		                    UI::g_fh->render(as_richtext_paragraph(label_text_, UI::FontStyle::kLabel), text_width(get_w(), pic_width));
 		if (rendered_text_.get()) {
 			w = std::max(rendered_text_->width() + kPadding + pic_width, w);
 			h = std::max(rendered_text_->height(), h);

=== modified file 'src/ui_basic/dropdown.cc'
--- src/ui_basic/dropdown.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/dropdown.cc	2019-05-03 19:28:13 +0000
@@ -29,18 +29,25 @@
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/text_layout.h"
 #include "ui_basic/mouse_constants.h"
 #include "ui_basic/tabpanel.h"
 #include "ui_basic/window.h"
 
 namespace {
-
-int base_height(int button_dimension) {
-	return std::max(
+int base_height(int button_dimension, UI::PanelStyle style) {
+	int result = std::max(
 	   button_dimension,
-	   UI::g_fh->render(as_uifont(UI::g_fh->fontset()->representative_character()))->height() + 2);
-}
-
+	   text_height(g_gr->styles().table_style(style).enabled()) + 2);
+	return result;
+}
+
+
+/*
+int BaseDropdown::base_height(int button_dimension) const {
+	return std::max(button_dimension, text_height(g_gr->styles().table_style(UI::PanelStyle::kWui).enabled()) + 2);
+}
+*/
 }  // namespace
 
 namespace UI {
@@ -61,13 +68,14 @@
                y,
                type == DropdownType::kPictorial ? button_dimension : w,
                // Height only to fit the button, so we can use this in Box layout.
-               base_height(button_dimension)),
+               base_height(button_dimension, style)),
      id_(next_id_++),
      max_list_height_(h - 2 * get_h()),
      list_width_(w),
      list_offset_x_(0),
      list_offset_y_(0),
      button_dimension_(button_dimension),
+	 base_height_(base_height(button_dimension, style)),
      mouse_tolerance_(50),
      button_box_(this, 0, 0, UI::Box::Horizontal, w, h),
      push_button_(type == DropdownType::kTextual ?
@@ -154,16 +162,16 @@
 }
 
 void BaseDropdown::set_height(int height) {
-	max_list_height_ = height - base_height(button_dimension_);
+	max_list_height_ = height - base_height_;
 	layout();
 }
 
 void BaseDropdown::set_max_items(int items) {
-	set_height(list_->get_lineheight() * items + base_height(button_dimension_));
+	set_height(list_->get_lineheight() * items + base_height_);
 }
 
 void BaseDropdown::layout() {
-	const int base_h = base_height(button_dimension_);
+	const int base_h = base_height_;
 	const int w = type_ == DropdownType::kPictorial ? button_dimension_ : get_w();
 	button_box_.set_size(w, base_h);
 	display_button_.set_desired_size(

=== modified file 'src/ui_basic/dropdown.h'
--- src/ui_basic/dropdown.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/dropdown.h	2019-05-03 19:28:13 +0000
@@ -179,7 +179,8 @@
 	int list_width_;
 	int list_offset_x_;
 	int list_offset_y_;
-	int button_dimension_;
+	const int button_dimension_;
+	const int base_height_;
 	const int mouse_tolerance_;  // Allow mouse outside the panel a bit before autocollapse
 	UI::Box button_box_;
 	UI::Button* push_button_;  // Only used in textual dropdowns

=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc	2019-04-09 16:43:49 +0000
+++ src/ui_basic/editbox.cc	2019-05-03 19:28:13 +0000
@@ -32,7 +32,6 @@
 #include "graphic/text/bidi.h"
 #include "graphic/text/font_set.h"
 #include "graphic/text/rt_errors.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "ui_basic/mouse_constants.h"
 
@@ -41,23 +40,30 @@
 namespace {
 
 constexpr int kMarginX = 4;
+constexpr int kLineMargin = 1;
 
 }  // namespace
 
 namespace UI {
 
 struct EditBoxImpl {
-	/**
-	 * Font used for rendering text.
-	 */
-	/*@{*/
-	std::string fontname;
-	uint32_t fontsize;
-	/*@}*/
+	explicit EditBoxImpl(const UI::TextPanelStyleInfo& init_style) :
+		background_style(&init_style.background()), font_style(&init_style.font()),
+		margin(init_style.background().margin()), font_scale(1.0f) {
+	}
 
 	/// Background color and texture
 	const UI::PanelStyleInfo* background_style;
 
+	/// Font style
+	const UI::FontStyleInfo* font_style;
+
+	/// Margin around the test
+	int margin;
+
+	/// Scale for font size
+	float font_scale;
+
 	/// Maximum number of characters in the input
 	uint32_t maxLength;
 
@@ -78,19 +84,13 @@
                  int32_t x,
                  int32_t y,
                  uint32_t w,
-                 uint32_t h,
-                 int margin_y,
-                 UI::PanelStyle style,
-                 int font_size)
-   : Panel(parent, x, y, w, h > 0 ? h : text_height(font_size) + 2 * margin_y),
-     m_(new EditBoxImpl),
+                 UI::PanelStyle style)
+   : Panel(parent, x, y, w,
+		   text_height(g_gr->styles().editbox_style(style).font())
+		   + 2 * g_gr->styles().editbox_style(style).background().margin()),
+	 m_(new EditBoxImpl(g_gr->styles().editbox_style(style))),
      history_active_(false),
      history_position_(-1) {
-	set_thinks(false);
-
-	m_->background_style = g_gr->styles().editbox_style(style);
-	m_->fontname = UI::g_fh->fontset()->sans();
-	m_->fontsize = font_size;
 
 	// Set alignment to the UI language's principal writing direction
 	m_->align = UI::g_fh->fontset()->is_rtl() ? UI::Align::kRight : UI::Align::kLeft;
@@ -99,6 +99,7 @@
 	// yes, use *signed* max as maximum length; just a small safe-guard.
 	set_max_length(std::numeric_limits<int32_t>::max());
 
+	set_thinks(false);
 	set_handle_mouse(true);
 	set_can_focus(true);
 	set_handle_textinput();
@@ -144,9 +145,9 @@
  * If the current string is longer than the new maximum length,
  * its end is cut off to fit into the maximum length.
  */
-void EditBox::set_max_length(uint32_t const n) {
+void EditBox::set_max_length(int const n) {
 	m_->maxLength =
-	   std::min(g_gr->max_texture_size_for_font_rendering() / text_height(), static_cast<int>(n));
+	   std::min(g_gr->max_texture_size_for_font_rendering() / text_height(*m_->font_style), n);
 
 	if (m_->text.size() > m_->maxLength) {
 		m_->text.erase(m_->text.begin() + m_->maxLength, m_->text.end());
@@ -157,6 +158,22 @@
 	}
 }
 
+void EditBox::set_font_scale(float scale) {
+	m_->font_scale = scale;
+}
+
+void EditBox::set_font_style(const UI::FontStyleInfo& style) {
+	m_->font_style = &style;
+	const int new_height = text_height(style) + 2 * m_->margin;
+	set_size(get_w(), new_height);
+	set_desired_size(get_w(), new_height);
+}
+
+void EditBox::set_font_style_and_margin(const UI::FontStyleInfo& style, int margin) {
+	m_->margin = margin;
+	set_font_style(style);
+}
+
 /**
  * The mouse was clicked on this editbox
  */
@@ -366,12 +383,13 @@
 	}
 
 	const int max_width = get_w() - 2 * kMarginX;
-
+	FontStyleInfo scaled_style(*m_->font_style);
+	scaled_style.set_size(scaled_style.size() * m_->font_scale);
 	std::shared_ptr<const UI::RenderedText> rendered_text =
-	   UI::g_fh->render(as_editorfont(m_->text, m_->fontsize));
+	   UI::g_fh->render(as_editor_richtext_paragraph(m_->text, scaled_style));
 
 	const int linewidth = rendered_text->width();
-	const int lineheight = m_->text.empty() ? text_height(m_->fontsize) : rendered_text->height();
+	const int lineheight = m_->text.empty() ? text_height(scaled_style) : rendered_text->height();
 
 	Vector2i point(kMarginX, get_h() / 2);
 	if (m_->align == UI::Align::kRight) {
@@ -406,9 +424,9 @@
 		// Draw the caret
 		std::string line_to_caret = m_->text.substr(0, m_->caret);
 		// TODO(GunChleoc): Arabic: Fix cursor position for BIDI text.
-		int caret_x = text_width(line_to_caret, m_->fontsize);
+		int caret_x = text_width(line_to_caret, *m_->font_style, m_->font_scale);
 
-		const uint16_t fontheight = text_height(m_->fontsize);
+		const uint16_t fontheight = text_height(*m_->font_style, m_->font_scale);
 
 		const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
 		Vector2i caretpt = Vector2i::zero();
@@ -424,8 +442,8 @@
 void EditBox::check_caret() {
 	std::string leftstr(m_->text, 0, m_->caret);
 	std::string rightstr(m_->text, m_->caret, std::string::npos);
-	int32_t leftw = text_width(leftstr, m_->fontsize);
-	int32_t rightw = text_width(rightstr, m_->fontsize);
+	int32_t leftw = text_width(leftstr, *m_->font_style, m_->font_scale);
+	int32_t rightw = text_width(rightstr, *m_->font_style, m_->font_scale);
 
 	int32_t caretpos = 0;
 

=== modified file 'src/ui_basic/editbox.h'
--- src/ui_basic/editbox.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/editbox.h	2019-05-03 19:28:13 +0000
@@ -26,6 +26,7 @@
 #include <boost/signals2.hpp>
 
 #include "graphic/align.h"
+#include "graphic/style_manager.h"
 #include "ui_basic/button.h"
 
 #define CHAT_HISTORY_SIZE 5
@@ -48,10 +49,7 @@
 	        int32_t x,
 	        int32_t y,
 	        uint32_t w,
-	        uint32_t h,
-	        int margin_y,
-	        UI::PanelStyle style,
-	        int font_size = UI_FONT_SIZE_SMALL);
+	        UI::PanelStyle style);
 	~EditBox() override;
 
 	boost::signals2::signal<void()> changed;
@@ -60,7 +58,10 @@
 
 	const std::string& text() const;
 	void set_text(const std::string&);
-	void set_max_length(uint32_t);
+	void set_max_length(int);
+	void set_font_scale(float scale);
+	void set_font_style(const UI::FontStyleInfo& style);
+	void set_font_style_and_margin(const UI::FontStyleInfo& style, int margin);
 
 	void activate_history(bool activate) {
 		history_active_ = activate;

=== modified file 'src/ui_basic/fullscreen_window.cc'
--- src/ui_basic/fullscreen_window.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/fullscreen_window.cc	2019-05-03 19:28:13 +0000
@@ -22,9 +22,9 @@
 #include <cstdio>
 #include <memory>
 
+#include "base/log.h"
 #include "graphic/rendertarget.h"
 #include "graphic/style_manager.h"
-#include "graphic/text_constants.h"
 
 /*
 ==============================================================================
@@ -177,12 +177,8 @@
 	}
 }
 
-int FullscreenWindow::fs_small() {
-	return UI_FONT_SIZE_SMALL * get_h() / 600;
-}
-
-int FullscreenWindow::fs_big() {
-	return UI_FONT_SIZE_BIG * get_h() / 600;
+float FullscreenWindow::scale_factor() const {
+	return std::max(1.0f, get_h() / 600.0f);
 }
 
 }  // namespace UI

=== modified file 'src/ui_basic/fullscreen_window.h'
--- src/ui_basic/fullscreen_window.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/fullscreen_window.h	2019-05-03 19:28:13 +0000
@@ -71,9 +71,8 @@
 	FullscreenWindow();
 	~FullscreenWindow() override;
 
-	/// \return the size for texts fitting to current resolution
-	int fs_small();
-	int fs_big();
+	/// \return the font size scale factor for fitting texts to current resolution
+	float scale_factor() const;
 
 protected:
 	void draw(RenderTarget&) override;

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/listselect.cc	2019-05-03 19:28:13 +0000
@@ -30,7 +30,6 @@
 #include "graphic/rendertarget.h"
 #include "graphic/style_manager.h"
 #include "graphic/text/bidi.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "ui_basic/mouse_constants.h"
 
@@ -54,16 +53,17 @@
                                UI::PanelStyle style,
                                const ListselectLayout selection_mode)
    : Panel(parent, x, y, w, h),
-     lineheight_(text_height() + kMargin),
      scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, style),
      scrollpos_(0),
      selection_(no_selection_index()),
      last_click_time_(-10000),
      last_selection_(no_selection_index()),
      selection_mode_(selection_mode),
+	  font_style_(&g_gr->styles().table_style(style).enabled()),
      background_style_(selection_mode == ListselectLayout::kDropdown ?
                           g_gr->styles().dropdown_style(style) :
-                          nullptr) {
+								  nullptr),
+	  lineheight_(text_height(*font_style_) + kMargin) {
 	set_thinks(false);
 
 	scrollbar_.moved.connect(boost::bind(&BaseListselect::set_scrollpos, this, _1));
@@ -297,7 +297,7 @@
 		for (size_t i = 0; i < entry_records_.size(); ++i) {
 			const EntryRecord& er = *entry_records_[i];
 			std::shared_ptr<const UI::RenderedText> rendered_text = UI::g_fh->render(
-			   as_uifont(richtext_escape(er.name), UI_FONT_SIZE_SMALL, UI_FONT_CLR_FG));
+			   as_richtext_paragraph(richtext_escape(er.name), *font_style_));
 			int picw = max_pic_width_ ? max_pic_width_ + 10 : 0;
 			int difference = rendered_text->width() + picw + 8 - get_eff_w();
 			if (difference > 0) {
@@ -342,7 +342,7 @@
 
 		const EntryRecord& er = *entry_records_[idx];
 		std::shared_ptr<const UI::RenderedText> rendered_text =
-		   UI::g_fh->render(as_uifont(richtext_escape(er.name), UI_FONT_SIZE_SMALL, UI_FONT_CLR_FG));
+		   UI::g_fh->render(as_richtext_paragraph(richtext_escape(er.name), *font_style_));
 
 		int lineheight = std::max(get_lineheight(), rendered_text->height());
 

=== modified file 'src/ui_basic/listselect.h'
--- src/ui_basic/listselect.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/listselect.h	2019-05-03 19:28:13 +0000
@@ -26,6 +26,7 @@
 #include <boost/signals2.hpp>
 
 #include "graphic/color.h"
+#include "graphic/styles/font_style.h"
 #include "ui_basic/panel.h"
 #include "ui_basic/scrollbar.h"
 
@@ -139,7 +140,6 @@
 	using EntryRecordDeque = std::deque<EntryRecord*>;
 
 	int max_pic_width_;
-	int lineheight_;
 	EntryRecordDeque entry_records_;
 	Scrollbar scrollbar_;
 	uint32_t scrollpos_;  //  in pixels
@@ -148,7 +148,9 @@
 	uint32_t last_selection_;  // for double clicks
 	ListselectLayout selection_mode_;
 	const Image* check_pic_;
+	const FontStyleInfo* font_style_;
 	const UI::PanelStyleInfo* background_style_;  // Background color and texture. Not owned.
+	int lineheight_;
 	std::string current_tooltip_;
 };
 

=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/messagebox.cc	2019-05-03 19:28:13 +0000
@@ -22,6 +22,7 @@
 #include "base/i18n.h"
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
+#include "graphic/text_layout.h"
 #include "ui_basic/window.h"
 
 namespace UI {
@@ -44,19 +45,21 @@
 	// Make sure that there is space for buttons + message, but not too tall
 	const int maxheight = std::min(260, std::max(outerheight * 2 / 3, 200));
 
+	const UI::FontStyle font_style = UI::FontStyle::kLabel;
+
 	const int margin = 5;
 	int width, height = 0;
 	{
 		std::shared_ptr<const UI::RenderedText> temp_rendered_text =
-		   g_fh->render(as_uifont(text), maxwidth);
+		   g_fh->render(as_richtext_paragraph(text, font_style), maxwidth);
 		width = temp_rendered_text->width();
 		height = temp_rendered_text->height();
 	}
 
 	// Stupid heuristic to avoid excessively long lines
-	if (height < 2 * UI_FONT_SIZE_SMALL) {
+	if (height < 2 * text_height(font_style)) {
 		std::shared_ptr<const UI::RenderedText> temp_rendered_text =
-		   g_fh->render(as_uifont(text), maxwidth / 2);
+		   g_fh->render(as_richtext_paragraph(text, font_style), maxwidth / 2);
 		width = temp_rendered_text->width();
 		height = temp_rendered_text->height();
 	}

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/multilineeditbox.cc	2019-05-03 19:28:13 +0000
@@ -41,8 +41,8 @@
 	/// The text in the edit box
 	std::string text;
 
-	/// Background color and texture
-	const UI::PanelStyleInfo* background_style;
+	/// Background color and texture + font style
+	const UI::TextPanelStyleInfo& style;
 
 	/// Position of the cursor inside the text.
 	/// 0 indicates that the cursor is before the first character,
@@ -60,7 +60,7 @@
 	WordWrap ww;
 	/*@}*/
 
-	Data(MultilineEditbox&, const UI::PanelStyleInfo* style);
+	Data(MultilineEditbox&, const TextPanelStyleInfo& style);
 	void refresh_ww();
 
 	void update();
@@ -81,7 +81,7 @@
 
 /**
  * Initialize an editbox that supports multiline strings.
- */
+*/
 MultilineEditbox::MultilineEditbox(
    Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, UI::PanelStyle style)
    : Panel(parent, x, y, w, h), d_(new Data(*this, g_gr->styles().editbox_style(style))) {
@@ -91,17 +91,18 @@
 	set_handle_textinput();
 }
 
-MultilineEditbox::Data::Data(MultilineEditbox& o, const UI::PanelStyleInfo* style)
+MultilineEditbox::Data::Data(MultilineEditbox& o, const UI::TextPanelStyleInfo& init_style)
    : scrollbar(
         &o, o.get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, o.get_h(), UI::PanelStyle::kWui),
-     background_style(style),
+	  style(init_style),
      cursor_pos(0),
-     lineheight(text_height()),
+     lineheight(text_height(style.font())),
      maxbytes(std::min(g_gr->max_texture_size_for_font_rendering() *
                           g_gr->max_texture_size_for_font_rendering() /
-                          (text_height() * text_height()),
+                          (text_height(style.font()) * text_height(style.font())),
                        std::numeric_limits<int32_t>::max())),
      ww_valid(false),
+	  ww(style.font().size(), style.font().color(), o.get_w()),
      owner(o) {
 	scrollbar.moved.connect(boost::bind(&MultilineEditbox::scrollpos_changed, &o, _1));
 
@@ -413,7 +414,7 @@
  * Redraw the Editbox
  */
 void MultilineEditbox::draw(RenderTarget& dst) {
-	draw_background(dst, *d_->background_style);
+	draw_background(dst, d_->style.background());
 
 	// Draw border.
 	if (get_w() >= 4 && get_h() >= 4) {
@@ -437,7 +438,6 @@
 	d_->refresh_ww();
 
 	d_->ww.set_draw_caret(has_focus());
-
 	d_->ww.draw(dst, Vector2i(0, -int32_t(d_->scrollbar.get_scrollpos())), UI::Align::kLeft,
 	            has_focus() ? d_->cursor_pos : std::numeric_limits<uint32_t>::max());
 }

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/multilinetextarea.cc	2019-05-03 19:28:13 +0000
@@ -23,9 +23,10 @@
 #include <boost/bind.hpp>
 
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/text/bidi.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 
 namespace UI {
@@ -44,19 +45,30 @@
                                      MultilineTextarea::ScrollMode scroll_mode)
    : Panel(parent, x, y, w, h),
      text_(text),
-     color_(UI_FONT_CLR_FG),
+	  style_(&g_gr->styles().font_style(FontStyle::kLabel)),
+	  font_scale_(1.0f),
      align_(align),
      scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, style, false) {
 	set_thinks(false);
 
 	scrollbar_.moved.connect(boost::bind(&MultilineTextarea::scrollpos_changed, this, _1));
 
-	scrollbar_.set_singlestepsize(text_height());
+	scrollbar_.set_singlestepsize(text_height(*style_, font_scale_));
 	scrollbar_.set_steps(1);
 	set_scrollmode(scroll_mode);
 	assert(scrollmode_ == MultilineTextarea::ScrollMode::kNoScrolling || Scrollbar::kSize <= w);
 }
 
+void MultilineTextarea::set_style(const UI::FontStyleInfo& style) {
+	style_ = &style;
+	recompute();
+}
+void MultilineTextarea::set_font_scale(float scale) {
+	font_scale_ = scale;
+	scrollbar_.set_singlestepsize(text_height(*style_, font_scale_));
+	recompute();
+}
+
 /**
  * Replace the current text with a new one.
  * Fix up scrolling state if necessary.
@@ -66,11 +78,6 @@
 	recompute();
 }
 
-void MultilineTextarea::set_color(RGBColor fg) {
-	color_ = fg;
-	recompute();
-}
-
 /**
  * Recompute the text rendering or rich-text layouting,
  * and adjust scrollbar settings accordingly.
@@ -129,7 +136,7 @@
 	// Take care of the scrollbar
 	scrollbar_.set_pos(Vector2i(get_w() - Scrollbar::kSize, 0));
 	scrollbar_.set_size(Scrollbar::kSize, get_h());
-	scrollbar_.set_pagesize(get_h() - 2 * UI_FONT_SIZE_BIG);
+	scrollbar_.set_pagesize(get_h() - 2 * style_->size() * font_scale_);
 }
 
 /**
@@ -140,7 +147,7 @@
 		return;
 	}
 	int anchor = 0;
-	Align alignment = mirror_alignment(align_, text_);
+	Align alignment = mirror_alignment(align_, i18n::has_rtl_character(text_.c_str(), 20));
 	switch (alignment) {
 	// TODO(Arty): We might want to revisit this after the font renderer can handle long strings
 	// without whitespaces differently.
@@ -192,7 +199,10 @@
 	// TODO(GunChleoc): Revisit this once the old font renderer is completely gone.
 	boost::replace_all(temp, "\n\n", "<br>&nbsp;<br>");
 	boost::replace_all(temp, "\n", "<br>");
-	return as_aligned(temp, align_, UI_FONT_SIZE_SMALL, color_);
+
+	FontStyleInfo scaled_style(*style_);
+	scaled_style.set_size(std::max(g_gr->styles().minimum_font_size(), static_cast<int>(std::ceil(scaled_style.size() * font_scale_))));
+	return as_richtext_paragraph(temp, scaled_style, align_);
 }
 
 }  // namespace UI

=== modified file 'src/ui_basic/multilinetextarea.h'
--- src/ui_basic/multilinetextarea.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/multilinetextarea.h	2019-05-03 19:28:13 +0000
@@ -23,13 +23,12 @@
 #include <memory>
 
 #include "graphic/align.h"
-#include "graphic/color.h"
+#include "graphic/styles/panel_styles.h"
 #include "graphic/text_layout.h"
 #include "ui_basic/panel.h"
 #include "ui_basic/scrollbar.h"
 
 namespace UI {
-struct Scrollbar;
 
 /**
  * This defines an area, where a text can easily be printed.
@@ -65,7 +64,8 @@
 		return scrollbar_.is_enabled() ? get_w() - Scrollbar::kSize : get_w();
 	}
 
-	void set_color(RGBColor fg);
+	void set_style(const FontStyleInfo& style);
+	void set_font_scale(float scale);
 
 	// Drawing and event handlers
 	void draw(RenderTarget&) override;
@@ -88,10 +88,13 @@
 	 * turns '\\n' into '<br>' tags as needed, then creates the richtext style wrappers.
 	 */
 	std::string make_richtext();
-
 	std::string text_;
-	std::shared_ptr<const UI::RenderedText> rendered_text_;
-	RGBColor color_;
+
+  std::shared_ptr<const UI::RenderedText> rendered_text_;
+
+  const FontStyleInfo* style_;
+  float font_scale_;
+
 	const Align align_;
 
 	Scrollbar scrollbar_;

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2019-04-24 06:01:37 +0000
+++ src/ui_basic/panel.cc	2019-05-03 19:28:13 +0000
@@ -24,7 +24,6 @@
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "profile/profile.h"
 #include "sound/sound_handler.h"
@@ -458,12 +457,12 @@
 	draw_background(dst, Recti(0, 0, get_w(), get_h()), info);
 }
 void Panel::draw_background(RenderTarget& dst, Recti rect, const UI::PanelStyleInfo& info) {
-	if (info.image != nullptr) {
+	if (info.image() != nullptr) {
 		dst.fill_rect(rect, RGBAColor(0, 0, 0, 255));
-		dst.tile(rect, info.image, Vector2i(get_x(), get_y()));
+		dst.tile(rect, info.image(), Vector2i(get_x(), get_y()));
 	}
-	if (info.color != RGBAColor(0, 0, 0, 0)) {
-		dst.fill_rect(rect, info.color, BlendMode::UseAlpha);
+	if (info.color() != RGBAColor(0, 0, 0, 0)) {
+		dst.fill_rect(rect, info.color(), BlendMode::UseAlpha);
 	}
 }
 
@@ -1082,7 +1081,7 @@
 	RenderTarget& dst = *g_gr->get_render_target();
 	std::string text_to_render = text;
 	if (!is_richtext(text_to_render)) {
-		text_to_render = as_tooltip(text_to_render);
+		text_to_render = as_richtext_paragraph(text_to_render, UI::FontStyle::kTooltip);
 	}
 
 	constexpr uint32_t kTipWidthMax = 360;

=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h	2019-03-17 11:44:04 +0000
+++ src/ui_basic/panel.h	2019-05-03 19:28:13 +0000
@@ -33,7 +33,7 @@
 #include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/font_handler.h"
-#include "graphic/panel_styles.h"
+#include "graphic/styles/panel_styles.h"
 #include "sound/constants.h"
 
 class RenderTarget;

=== modified file 'src/ui_basic/progressbar.cc'
--- src/ui_basic/progressbar.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/progressbar.cc	2019-05-03 19:28:13 +0000
@@ -24,6 +24,7 @@
 #include <boost/format.hpp>
 
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "graphic/text_layout.h"
 
@@ -37,7 +38,7 @@
                          int32_t const w,
                          int32_t const h,
                          uint32_t const orientation)
-   : Panel(parent, x, y, w, h), orientation_(orientation), state_(0), total_(100) {
+   : Panel(parent, x, y, w, h), orientation_(orientation), state_(0), total_(100), style_(g_gr->styles().progressbar_style(UI::PanelStyle::kWui)) {
 }
 
 /**
@@ -66,9 +67,9 @@
 	assert(0 <= fraction);
 	assert(fraction <= 1);
 
-	const RGBColor color = fraction <= 0.33f ?
-	                          RGBColor(255, 0, 0) :
-	                          fraction <= 0.67f ? RGBColor(255, 255, 0) : RGBColor(0, 255, 0);
+	const RGBColor& color = fraction <= 0.33f ? style_.low_color() : fraction <= 0.67f ?
+	                                           style_.medium_color() :
+	                                           style_.high_color();
 
 	// Draw the actual bar
 	if (orientation_ == Horizontal) {
@@ -85,11 +86,8 @@
 	}
 
 	// Print the state in percent without decimal points.
-	const std::string progress_text = (boost::format("<font color=%s>%u%%</font>") %
-	                                   UI_FONT_CLR_BRIGHT.hex_value() % floorf(fraction * 100.f))
-	                                     .str();
 	std::shared_ptr<const UI::RenderedText> rendered_text =
-	   UI::g_fh->render(as_uifont(progress_text));
+	   UI::g_fh->render(as_richtext_paragraph((boost::format("%u%%") % floorf(fraction * 100.f)).str(), style_.font()));
 	Vector2i pos(get_w() / 2, get_h() / 2);
 	UI::center_vertically(rendered_text->height(), &pos);
 	rendered_text->draw(dst, pos, UI::Align::kCenter);

=== modified file 'src/ui_basic/progressbar.h'
--- src/ui_basic/progressbar.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/progressbar.h	2019-05-03 19:28:13 +0000
@@ -20,6 +20,7 @@
 #ifndef WL_UI_BASIC_PROGRESSBAR_H
 #define WL_UI_BASIC_PROGRESSBAR_H
 
+#include "graphic/style_manager.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -58,6 +59,7 @@
 	uint32_t orientation_;
 	uint32_t state_;  ///< state_ is [0..total_]
 	uint32_t total_;  ///< maximum progress
+	const UI::ProgressbarStyleInfo& style_;
 };
 }  // namespace UI
 

=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/progresswindow.cc	2019-05-03 19:28:13 +0000
@@ -28,14 +28,10 @@
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "io/filesystem/layered_filesystem.h"
 
 namespace {
-
-#define PROGRESS_FONT_COLOR_FG RGBColor(128, 128, 255)
-#define PROGRESS_FONT_COLOR_BG RGBColor(64, 64, 0)
 #define PROGRESS_STATUS_RECT_PADDING 2
 #define PROGRESS_STATUS_BORDER_X 2
 #define PROGRESS_STATUS_BORDER_Y 2
@@ -46,7 +42,7 @@
 namespace UI {
 
 ProgressWindow::ProgressWindow(const std::string& background)
-   : UI::FullscreenWindow(), label_center_(Vector2i::zero()) {
+   : UI::FullscreenWindow(), label_center_(Vector2i::zero()), style_(g_gr->styles().progressbar_style(UI::PanelStyle::kFsMenu)) {
 	set_background(background);
 	step(_("Loading…"));
 }
@@ -63,7 +59,7 @@
 	label_center_.x = get_w() / 2;
 	label_center_.y = get_h() * PROGRESS_LABEL_POSITION_Y / 100;
 
-	const uint32_t h = text_height();
+	const uint32_t h = text_height(style_.font());
 
 	label_rectangle_.x = get_w() / 4;
 	label_rectangle_.w = get_w() / 2;
@@ -76,7 +72,9 @@
 	border_rect.w += 2 * PROGRESS_STATUS_BORDER_X;
 	border_rect.h += 2 * PROGRESS_STATUS_BORDER_Y;
 
-	rt.draw_rect(border_rect, PROGRESS_FONT_COLOR_FG);
+	rt.draw_rect(border_rect, style_.font().color());
+	// TODO(GunChleoc): this should depend on actual progress. Add a total steps variable and reuse the Progressbar class.
+	rt.fill_rect(label_rectangle_, style_.medium_color());
 }
 
 /// Set a picture to render in the background
@@ -97,9 +95,8 @@
 	// always repaint the background first
 	draw(rt);
 
-	rt.fill_rect(label_rectangle_, PROGRESS_FONT_COLOR_BG);
 	std::shared_ptr<const UI::RenderedText> rendered_text =
-	   UI::g_fh->render(as_uifont(description, UI_FONT_SIZE_SMALL, PROGRESS_FONT_COLOR_FG));
+	   UI::g_fh->render(as_richtext_paragraph(description, style_.font()));
 	UI::center_vertically(rendered_text->height(), &label_center_);
 	rendered_text->draw(rt, label_center_, UI::Align::kCenter);
 

=== modified file 'src/ui_basic/progresswindow.h'
--- src/ui_basic/progresswindow.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/progresswindow.h	2019-05-03 19:28:13 +0000
@@ -67,6 +67,7 @@
 	Recti label_rectangle_;
 	VisualizationArray visualizations_;
 	std::string background_;
+	const UI::ProgressbarStyleInfo& style_;
 
 	void draw(RenderTarget&) override;
 	void update(bool repaint);

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2019-03-16 07:46:10 +0000
+++ src/ui_basic/slider.cc	2019-05-03 19:28:13 +0000
@@ -72,7 +72,7 @@
      highlighted_(false),
      pressed_(false),
      enabled_(enabled),
-     cursor_style_(g_gr->styles().slider_style(style)),
+     cursor_style_(&g_gr->styles().slider_style(style).background()),
      x_gap_(x_gap),
      y_gap_(y_gap),
      bar_size_(bar_size),
@@ -487,22 +487,23 @@
                                const uint32_t w,
                                const uint32_t h,
                                const std::vector<std::string>& labels_in,
-                               uint32_t value_,
-                               SliderStyle style,
+                               uint32_t init_value,
+                               SliderStyle init_style,
                                const std::string& tooltip_text,
                                const uint32_t cursor_size,
                                const bool enabled)
    : Panel(parent, x, y, w, h, tooltip_text),
+	  style(g_gr->styles().slider_style(init_style)),
      slider(this,
             // here, we take into account the h_gap introduced by HorizontalSlider
             w / (2 * labels_in.size()) - cursor_size / 2,
             0,
             w - (w / labels_in.size()) + cursor_size,
-            h - text_height(UI_FONT_SIZE_SMALL - 2, UI::FontSet::Face::kCondensed) - 2,
+            h - text_height(style.font()) - 2,
             0,
             labels_in.size() - 1,
-            value_,
-            style,
+            init_value,
+            init_style,
             tooltip_text,
             cursor_size,
             enabled),
@@ -524,7 +525,7 @@
 
 	for (uint32_t i = 0; i < labels.size(); i++) {
 		std::shared_ptr<const UI::RenderedText> rendered_text =
-		   UI::g_fh->render(as_condensed(labels[i], UI::Align::kCenter, UI_FONT_SIZE_SMALL - 2));
+		   UI::g_fh->render(as_richtext_paragraph(labels[i], style.font()));
 		rendered_text->draw(
 		   dst, Vector2i(gap_1 + i * gap_n, get_h() - rendered_text->height()), UI::Align::kCenter);
 	}
@@ -542,7 +543,7 @@
 	assert(labels.size());
 	slider.set_pos(Vector2i(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
 	slider.set_size(w - (w / labels.size()) + slider.cursor_size_,
-	                h - text_height(UI_FONT_SIZE_SMALL - 2, UI::FontSet::Face::kCondensed) + 2);
+	                h - text_height(style.font()) + 2);
 	Panel::layout();
 }
 }  // namespace UI

=== modified file 'src/ui_basic/slider.h'
--- src/ui_basic/slider.h	2019-03-16 07:28:07 +0000
+++ src/ui_basic/slider.h	2019-05-03 19:28:13 +0000
@@ -21,6 +21,7 @@
 
 #include <boost/signals2.hpp>
 
+#include "graphic/styles/text_panel_style.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -236,6 +237,11 @@
 	void draw(RenderTarget& dst) override;
 	void layout() override;
 
+private:
+	// We need the style to initialize the slider, so it has to come first.
+	const UI::TextPanelStyleInfo& style;
+
+protected:
 	HorizontalSlider slider;
 
 private:

=== modified file 'src/ui_basic/spinbox.cc'
--- src/ui_basic/spinbox.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/spinbox.cc	2019-05-03 19:28:13 +0000
@@ -31,7 +31,6 @@
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "ui_basic/button.h"
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/textarea.h"

=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc	2019-04-18 16:50:35 +0000
+++ src/ui_basic/table.cc	2019-05-03 19:28:13 +0000
@@ -22,14 +22,13 @@
 #include <boost/bind.hpp>
 
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "graphic/text/bidi.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "graphic/texture.h"
 #include "ui_basic/mouse_constants.h"
-#include "ui_basic/scrollbar.h"
 
 namespace UI {
 
@@ -49,8 +48,9 @@
                     TableRows rowtype)
    : Panel(parent, x, y, w, h),
      total_width_(0),
-     headerheight_(text_height() + 4),
-     lineheight_(text_height()),
+	  lineheight_(text_height(g_gr->styles().table_style(style).enabled())),
+     headerheight_(lineheight_ + 4),
+	  style_(style),
      button_style_(style == UI::PanelStyle::kFsMenu ? UI::ButtonStyle::kFsMenuMenu :
                                                       UI::ButtonStyle::kWuiSecondary),
      scrollbar_(nullptr),
@@ -239,7 +239,7 @@
 		for (uint32_t i = 0, curx = 0; i < nr_columns; ++i) {
 			const Column& column = columns_[i];
 			const int curw = column.width;
-			Align alignment = mirror_alignment(column.alignment);
+			Align alignment = mirror_alignment(column.alignment, g_fh->fontset()->is_rtl());
 
 			const Image* entry_picture = er.get_picture(i);
 			const std::string& entry_string = er.get_string(i);
@@ -300,12 +300,19 @@
 				curx += curw;
 				continue;
 			}
-			std::shared_ptr<const UI::RenderedText> rendered_text = UI::g_fh->render(
-			   as_uifont(richtext_escape(entry_string), UI_FONT_SIZE_SMALL, er.get_color()));
+
+			const UI::FontStyleInfo& font_style =
+					er.font_style() != nullptr ?
+										   *er.font_style() :
+										   er.is_disabled() ?
+											   g_gr->styles().table_style(style_).disabled() :
+											   g_gr->styles().table_style(style_).enabled();
+			std::shared_ptr<const UI::RenderedText> rendered_text =
+			   UI::g_fh->render(as_richtext_paragraph(richtext_escape(entry_string), font_style));
 
 			// Fix text alignment for BiDi languages if the entry contains an RTL character. We want
 			// this always on, e.g. for mixed language savegame filenames.
-			alignment = mirror_alignment(column.alignment, entry_string);
+			alignment = mirror_alignment(column.alignment, i18n::has_rtl_character(entry_string.c_str(), 20));
 
 			// Position the text according to alignment
 			switch (alignment) {
@@ -718,7 +725,7 @@
 	return ea.get_string(column) < eb.get_string(column);
 }
 
-Table<void*>::EntryRecord::EntryRecord(void* const e) : entry_(e), clr(UI_FONT_CLR_FG) {
+Table<void*>::EntryRecord::EntryRecord(void* const e) : entry_(e), font_style_(nullptr), disabled_(false) {
 }
 
 void Table<void*>::EntryRecord::set_picture(uint8_t const col,

=== modified file 'src/ui_basic/table.h'
--- src/ui_basic/table.h	2019-04-18 16:50:35 +0000
+++ src/ui_basic/table.h	2019-05-03 19:28:13 +0000
@@ -29,12 +29,12 @@
 
 #include "graphic/align.h"
 #include "graphic/color.h"
+#include "graphic/styles/font_style.h"
 #include "ui_basic/button.h"
 #include "ui_basic/panel.h"
+#include "ui_basic/scrollbar.h"
 
 namespace UI {
-struct Scrollbar;
-struct Button;
 
 enum class TableRows { kSingle, kMulti, kSingleDescending, kMultiDescending };
 enum class TableColumnType { kFixed, kFlexible };
@@ -141,22 +141,32 @@
 		void* entry() const {
 			return entry_;
 		}
-		void set_color(const RGBColor& c) {
-			clr = c;
-		}
-		RGBColor get_color() const {
-			return clr;
+
+		void set_font_style(const UI::FontStyleInfo& style) {
+			font_style_ = &style;
+		}
+
+		const UI::FontStyleInfo* font_style() const {
+			return font_style_;
+		}
+
+		bool is_disabled() const {
+			return disabled_;
+		}
+		void set_disabled(bool disable) {
+			disabled_ = disable;
 		}
 
 	private:
 		friend class Table<void*>;
 		void* entry_;
-		RGBColor clr;
+		const UI::FontStyleInfo* font_style_;
 		struct Data {
 			const Image* d_picture;
 			std::string d_string;
 		};
 		std::vector<Data> data_;
+		bool disabled_;
 	};
 
 	Table(Panel* parent,
@@ -299,9 +309,10 @@
 
 	Columns columns_;
 	int total_width_;
+	int32_t lineheight_;
 	const uint32_t headerheight_;
-	int32_t lineheight_;
-	UI::ButtonStyle button_style_;
+	const UI::PanelStyle style_;
+	const UI::ButtonStyle button_style_;
 	Scrollbar* scrollbar_;
 	// A disabled button that will fill the space above the scroll bar
 	UI::Button* scrollbar_filler_button_;

=== modified file 'src/ui_basic/tabpanel.cc'
--- src/ui_basic/tabpanel.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/tabpanel.cc	2019-05-03 19:28:13 +0000
@@ -62,7 +62,7 @@
      tooltip(tooltip_text),
      panel(contents) {
 	if (!init_title.empty()) {
-		rendered_title = UI::g_fh->render(as_uifont(init_title));
+		rendered_title = UI::g_fh->render(as_richtext_paragraph(init_title, UI::FontStyle::kLabel));
 		set_size(std::max(kTabPanelButtonHeight, rendered_title->width() + 2 * kTabPanelTextMargin),
 		         kTabPanelButtonHeight);
 	}

=== modified file 'src/ui_basic/textarea.cc'
--- src/ui_basic/textarea.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/textarea.cc	2019-05-03 19:28:13 +0000
@@ -20,75 +20,68 @@
 #include "ui_basic/textarea.h"
 
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/text/bidi.h"
+#include "graphic/text_layout.h"
 
 namespace UI {
 
-Textarea::Textarea(Panel* parent, int32_t x, int32_t y, const std::string& text, Align align)
-   : Panel(parent, x, y, 0, 0), layoutmode_(AutoMove), align_(align) {
-	init();
-	set_text(text);
-}
-
-Textarea::Textarea(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, Align align)
-   : Panel(parent, x, y, w, h), layoutmode_(AutoMove), align_(align) {
-	init();
-}
-
 Textarea::Textarea(Panel* parent,
                    int32_t x,
                    int32_t y,
                    uint32_t w,
                    uint32_t h,
                    const std::string& text,
-                   Align align)
-   : Panel(parent, x, y, w, h), layoutmode_(AutoMove), align_(align) {
-	init();
-	set_text(text);
-}
-
-Textarea::Textarea(Panel* parent, const std::string& text, Align align)
-   : Panel(parent, 0, 0, 0, 0), layoutmode_(Layouted), align_(align) {
-	init();
-	set_text(text);
-}
-
-/**
- * Initialization tasks that are common to all constructors.
- */
-void Textarea::init() {
+                   Align align,
+				   const UI::FontStyleInfo& style,
+				   LayoutMode layout_mode)
+   : Panel(parent, x, y, w, h), layoutmode_(layout_mode), align_(align), style_(&style) {
 	fixed_width_ = 0;
 	set_handle_mouse(false);
 	set_thinks(false);
-	color_ = UI_FONT_CLR_FG;
-	fontsize_ = UI_FONT_SIZE_SMALL;
-	update();
-}
-
-void Textarea::set_color(RGBColor color) {
-	if (color_ != color) {
-		color_ = color;
-		update();
-	}
-}
-
-void Textarea::set_fontsize(int fontsize) {
-	if (fontsize_ != fontsize) {
-		fontsize_ = fontsize;
-		update();
-	}
+	font_scale_ = 1.0f;
+	update();
+	set_text(text);
+}
+
+Textarea::Textarea(Panel* parent,
+                   int32_t x,
+                   int32_t y,
+                   uint32_t w,
+                   uint32_t h,
+                   const std::string& text,
+                   Align align,
+				   const UI::FontStyleInfo& style)
+   : Textarea(parent, x, y, w, h, text, align, style, LayoutMode::AutoMove) {
+}
+
+Textarea::Textarea(Panel* parent, const std::string& text, Align align, const FontStyleInfo& style)
+   : Textarea(parent, 0, 0, 0, 0, text, align, style, LayoutMode::Layouted) {
+}
+
+void Textarea::set_style(const FontStyleInfo& style) {
+	style_ = &style;
+	update();
+}
+
+void Textarea::set_font_scale(float scale) {
+	font_scale_ = scale;
+	update();
 }
 
 void Textarea::update() {
-	if (layoutmode_ == AutoMove) {
+	if (layoutmode_ == LayoutMode::AutoMove) {
 		collapse();  // collapse() implicitly updates the size and position
 	}
 
-	rendered_text_ = autofit_ui_text(text_, fixed_width_, color_, fontsize_);
+	FontStyleInfo scaled_style(*style_);
+	scaled_style.set_size(std::max(g_gr->styles().minimum_font_size(), static_cast<int>(std::ceil(scaled_style.size() * font_scale_))));
+	rendered_text_ = autofit_text(richtext_escape(text_), scaled_style, fixed_width_);
 
-	if (layoutmode_ == AutoMove) {
+	if (layoutmode_ == LayoutMode::AutoMove) {
 		expand();
-	} else if (layoutmode_ == Layouted) {
+	} else if (layoutmode_ == LayoutMode::Layouted) {
 		update_desired_size();
 	}
 }
@@ -125,7 +118,7 @@
  */
 void Textarea::draw(RenderTarget& dst) {
 	if (!text_.empty()) {
-		Align alignment = mirror_alignment(align_, text_);
+		Align alignment = mirror_alignment(align_, i18n::has_rtl_character(text_.c_str(), 20));
 		Vector2i anchor((alignment == Align::kCenter) ?
 		                   get_w() / 2 :
 		                   (alignment == UI::Align::kRight) ? get_w() : 0,
@@ -195,7 +188,7 @@
 		h = rendered_text_->height();
 		// We want empty textareas to have height
 		if (text_.empty()) {
-			h = text_height(fontsize_);
+			h = text_height(*style_, font_scale_);
 		}
 	}
 	set_desired_size(w, h);

=== modified file 'src/ui_basic/textarea.h'
--- src/ui_basic/textarea.h	2019-02-23 11:00:49 +0000
+++ src/ui_basic/textarea.h	2019-05-03 19:28:13 +0000
@@ -21,7 +21,7 @@
 #define WL_UI_BASIC_TEXTAREA_H
 
 #include "graphic/align.h"
-#include "graphic/text_layout.h"
+#include "graphic/graphic.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -49,21 +49,17 @@
  * the latter provides scrollbars.
  */
 struct Textarea : public Panel {
-	Textarea(Panel* parent,
+public:
+	Textarea(Panel* const parent,
 	         int32_t x,
 	         int32_t y,
+	         uint32_t w,
+	         uint32_t h,
 	         const std::string& text = std::string(),
-	         Align align = UI::Align::kLeft);
-	Textarea(
-	   Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, Align align = UI::Align::kLeft);
-	Textarea(Panel* const parent,
-	         int32_t x,
-	         int32_t y,
-	         uint32_t w,
-	         uint32_t h,
-	         const std::string& text,
-	         Align align = UI::Align::kLeft);
-	Textarea(Panel* parent, const std::string& text = std::string(), Align align = UI::Align::kLeft);
+	         Align align = UI::Align::kLeft,
+			 const UI::FontStyleInfo& style = g_gr->styles().font_style(FontStyle::kLabel));
+	Textarea(Panel* parent, const std::string& text = std::string(), Align align = UI::Align::kLeft,
+			 const UI::FontStyleInfo& style = g_gr->styles().font_style(FontStyle::kLabel));
 
 	/**
 	 * If fixed_width > 0, the Textarea will not change its width.
@@ -78,27 +74,35 @@
 	// Drawing and event handlers
 	void draw(RenderTarget&) override;
 
-	void set_color(RGBColor color);
-	void set_fontsize(int fontsize);
+	void set_style(const UI::FontStyleInfo& style);
+	void set_font_scale(float scale);
 
 protected:
 	void update_desired_size() override;
 
 private:
-	enum LayoutMode { AutoMove, Layouted, Static };
-
-	void init();
+	enum class LayoutMode { AutoMove, Layouted };
+
+	Textarea(Panel* const parent,
+	         int32_t x,
+	         int32_t y,
+	         uint32_t w,
+	         uint32_t h,
+	         const std::string& text,
+	         Align align, const UI::FontStyleInfo& style, LayoutMode layout_mode);
+
 	void collapse();
 	void expand();
 	void update();
 
-	LayoutMode layoutmode_;
+	const LayoutMode layoutmode_;
+	const Align align_;
+
 	std::string text_;
 	std::shared_ptr<const UI::RenderedText> rendered_text_;
-	Align align_;
-	RGBColor color_;
-	int fontsize_;
 
+	const FontStyleInfo* style_;
+	float font_scale_;
 	int fixed_width_;
 };
 }  // namespace UI

=== modified file 'src/ui_basic/window.cc'
--- src/ui_basic/window.cc	2019-02-23 11:00:49 +0000
+++ src/ui_basic/window.cc	2019-05-03 19:28:13 +0000
@@ -278,7 +278,7 @@
 	if (!title_.empty()) {
 		// The title shouldn't be richtext, but we escape it just to make sure.
 		std::shared_ptr<const UI::RenderedText> text =
-		   autofit_ui_text(richtext_escape(title_), get_inner_w(), UI_FONT_CLR_FG, 13);
+			autofit_text(richtext_escape(title_), g_gr->styles().font_style(UI::FontStyle::kWuiWindowTitle), get_inner_w());
 
 		// Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
 		Vector2i pos(get_lborder() + get_inner_w() / 2, TP_B_PIXMAP_THICKNESS / 2);

=== modified file 'src/ui_fsmenu/CMakeLists.txt'
--- src/ui_fsmenu/CMakeLists.txt	2019-04-24 06:01:37 +0000
+++ src/ui_fsmenu/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -9,7 +9,6 @@
     graphic
     graphic_fonthandler
     graphic_text
-    graphic_text_constants
     graphic_text_layout
     helper
     io_filesystem
@@ -76,7 +75,6 @@
     singleplayer.h
   DEPENDS
     base_i18n
-    graphic_text_constants
     io_filesystem
     profile
     network
@@ -103,7 +101,6 @@
     base_i18n
     graphic
     graphic_playercolor
-    graphic_text_constants
     helper
     io_filesystem
     logic
@@ -145,7 +142,6 @@
     base_log
     graphic
     graphic_fonthandler
-    graphic_text_constants
     graphic_surface
     io_filesystem
     logic_filesystem_constants
@@ -173,7 +169,6 @@
     base_log
     base_macros
     graphic
-    graphic_text_constants
     network
     profile
     random

=== modified file 'src/ui_fsmenu/about.cc'
--- src/ui_fsmenu/about.cc	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/about.cc	2019-05-03 19:28:13 +0000
@@ -25,10 +25,9 @@
 
 FullscreenMenuAbout::FullscreenMenuAbout()
    : FullscreenMenuBase(),
-     title_(this, 0, 0, _("About Widelands"), UI::Align::kCenter),
+     title_(this, 0, 0, 0, 0, _("About Widelands"), UI::Align::kCenter, g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
      close_(this, "close", 0, 0, 0, 0, UI::ButtonStyle::kFsMenuPrimary, _("Close")),
      tabs_(this, UI::PanelStyle::kFsMenu, UI::TabPanelStyle::kFsMenu) {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 	tabs_.add_tab("txts/README.lua");
 	tabs_.add_tab("txts/LICENSE.lua");
 	tabs_.add_tab("txts/AUTHORS.lua");

=== modified file 'src/ui_fsmenu/campaign_select.cc'
--- src/ui_fsmenu/campaign_select.cc	2019-04-18 16:50:35 +0000
+++ src/ui_fsmenu/campaign_select.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/i18n.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
-#include "graphic/text_constants.h"
 #include "logic/filesystem_constants.h"
 #include "profile/profile.h"
 #include "scripting/lua_interface.h"
@@ -41,12 +40,12 @@
      table_(this, 0, 0, 0, 0, UI::PanelStyle::kFsMenu),
 
      // Main Title
-     title_(this, 0, 0, _("Choose a campaign"), UI::Align::kCenter),
+     title_(this, 0, 0, 0, 0, _("Choose a campaign"), UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
 
      // Campaign description
      campaign_details_(this),
      campaigns_(campvis) {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 	back_.set_tooltip(_("Return to the main menu"));
 	ok_.set_tooltip(_("Play this campaign"));
 
@@ -128,9 +127,7 @@
 		tableEntry.set_picture(0, campaign_data.difficulty_image);
 		tableEntry.set_string(1, campaign_data.tribename);
 		tableEntry.set_string(2, campaign_data.descname);
-		if (!campaign_data.visible) {
-			tableEntry.set_color(UI_FONT_CLR_DISABLED);
-		}
+		tableEntry.set_disabled(!campaign_data.visible);
 	}
 
 	if (table_.size()) {

=== modified file 'src/ui_fsmenu/campaigndetails.cc'
--- src/ui_fsmenu/campaigndetails.cc	2019-04-24 07:07:59 +0000
+++ src/ui_fsmenu/campaigndetails.cc	2019-05-03 19:28:13 +0000
@@ -21,7 +21,6 @@
 #include <boost/format.hpp>
 
 #include "base/i18n.h"
-#include "graphic/text_constants.h"
 #include "ui_basic/scrollbar.h"
 
 CampaignDetails::CampaignDetails(Panel* parent)

=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc	2019-04-24 06:01:37 +0000
+++ src/ui_fsmenu/internet_lobby.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/log.h"
 #include "base/macros.h"
 #include "graphic/graphic.h"
-#include "graphic/text_constants.h"
 #include "network/crypto.h"
 #include "network/gameclient.h"
 #include "network/gamehost.h"
@@ -56,15 +55,15 @@
      butw_(get_w() * 36 / 125),
      buth_(get_h() * 19 / 400),
      lisw_(get_w() * 623 / 1000),
-     fs_(fs_small()),
      prev_clientlist_len_(1000),
      new_client_fx_(SoundHandler::register_fx(SoundType::kChat, "sound/lobby_freshmen")),
 
      // Text labels
-     title(this, get_w() / 2, get_h() / 20, _("Metaserver Lobby"), UI::Align::kCenter),
-     clients_(this, get_w() * 4 / 125, get_h() * 15 / 100, _("Clients online:")),
-     opengames_(this, get_w() * 17 / 25, get_h() * 15 / 100, _("List of games:")),
-     servername_(this, get_w() * 17 / 25, get_h() * 63 / 100, _("Name of your server:")),
+     title(this, get_w() / 2, get_h() / 20, 0, 0, _("Metaserver Lobby"), UI::Align::kCenter,
+		   g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
+     clients_(this, get_w() * 4 / 125, get_h() * 15 / 100, 0, 0, _("Clients online:")),
+     opengames_(this, get_w() * 17 / 25, get_h() * 15 / 100, 0, 0, _("List of games:")),
+     servername_(this, get_w() * 17 / 25, get_h() * 63 / 100, 0, 0, _("Name of your server:")),
 
      // Buttons
      joingame_(this,
@@ -94,7 +93,7 @@
 
      // Edit boxes
      edit_servername_(
-        this, get_w() * 17 / 25, get_h() * 68 / 100, butw_, buth_, 2, UI::PanelStyle::kFsMenu, fs_),
+        this, get_w() * 17 / 25, get_h() * 68 / 100, butw_, UI::PanelStyle::kFsMenu),
 
      // List
      clientsonline_list_(
@@ -126,24 +125,28 @@
 	// Set the texts and style of UI elements
 	Section& s = g_options.pull_section("global");  //  for playername
 
-	title.set_fontsize(fs_big());
-	opengames_.set_fontsize(fs_);
-	clients_.set_fontsize(fs_);
-	servername_.set_fontsize(fs_);
+	title.set_font_scale(scale_factor());
+
+	opengames_.set_font_scale(scale_factor());
+	clients_.set_font_scale(scale_factor());
+	servername_.set_font_scale(scale_factor());
+
 	std::string server = s.get_string("servername", "");
+	edit_servername_.set_font_scale(scale_factor());
 	edit_servername_.set_text(server);
 	edit_servername_.changed.connect(
 	   boost::bind(&FullscreenMenuInternetLobby::change_servername, this));
 
-	// prepare the lists
-	std::string t_tip =
-	   (boost::format("%s%s%s%s%s%s%s%s%s%s") %
-	    "<rt padding=2><p align=center spacing=3><font bold=yes underline=yes>" % _("User Status") %
-	    "</font></p>" % "<p valign=bottom><img src=images/wui/overlays/roadb_green.png> " %
-	    _("Administrator") % "<br><img src=images/wui/overlays/roadb_yellow.png> " %
-	    _("Registered") % "<br><img src=images/wui/overlays/roadb_red.png> " % _("Unregistered") %
-	    "</p></rt>")
-	      .str();
+	// Prepare the lists
+	const std::string t_tip =
+	   (boost::format("<rt padding=2><p align=center spacing=3>%s</p>"
+					  "<p valign=bottom><img src=images/wui/overlays/roadb_green.png> %s"
+					  "<br><img src=images/wui/overlays/roadb_yellow.png> %s"
+					  "<br><img src=images/wui/overlays/roadb_red.png> %s</p></rt>") %
+		g_gr->styles().font_style(UI::FontStyle::kTooltipHeader).as_font_tag(_("User Status")) %
+	    g_gr->styles().font_style(UI::FontStyle::kTooltip).as_font_tag(_("Administrator")) %
+	    g_gr->styles().font_style(UI::FontStyle::kTooltip).as_font_tag(_("Registered")) %
+		g_gr->styles().font_style(UI::FontStyle::kTooltip).as_font_tag(_("Unregistered"))).str();
 	clientsonline_list_.add_column(22, "*", t_tip);
 	/** TRANSLATORS: Player Name */
 	clientsonline_list_.add_column((lisw_ - 22) * 3 / 8, pgettext("player", "Name"));
@@ -286,11 +289,11 @@
 				break;
 			case kClientSuperuser:
 				pic = g_gr->images().get("images/wui/overlays/roadb_green.png");
-				er.set_color(RGBColor(0, 255, 0));
 				er.set_picture(0, pic);
 				break;
 			case kClientIRC:
 				// No icon for IRC users
+				er.set_font_style(g_gr->styles().font_style(UI::FontStyle::kFsGameSetupIrcClient));
 				continue;
 			default:
 				continue;

=== modified file 'src/ui_fsmenu/internet_lobby.h'
--- src/ui_fsmenu/internet_lobby.h	2019-03-17 11:44:04 +0000
+++ src/ui_fsmenu/internet_lobby.h	2019-05-03 19:28:13 +0000
@@ -50,7 +50,6 @@
 	uint32_t butw_;
 	uint32_t buth_;
 	uint32_t lisw_;
-	uint32_t fs_;
 	uint32_t prev_clientlist_len_;
 	FxId new_client_fx_;
 	UI::Textarea title, clients_, opengames_;

=== modified file 'src/ui_fsmenu/intro.cc'
--- src/ui_fsmenu/intro.cc	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/intro.cc	2019-05-03 19:28:13 +0000
@@ -28,10 +28,12 @@
      message_(this,
               get_w() / 2,
               get_h() * 19 / 20,
+			  0,
+			  0,
               _("Press any key or click to continue…"),
-              UI::Align::kCenter) {
-	message_.set_fontsize(fs_small() * 6 / 5);
-	message_.set_color(RGBColor(192, 192, 128));
+              UI::Align::kCenter,
+			  g_gr->styles().font_style(UI::FontStyle::kFsMenuIntro)) {
+	message_.set_font_scale(scale_factor());
 	add_overlay_image("images/loadscreens/splash.jpg",
 	                  FullscreenWindow::Alignment(UI::Align::kCenter, UI::Align::kCenter));
 }

=== modified file 'src/ui_fsmenu/launch_game.cc'
--- src/ui_fsmenu/launch_game.cc	2019-04-27 11:21:21 +0000
+++ src/ui_fsmenu/launch_game.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/i18n.h"
 #include "base/warning.h"
 #include "base/wexception.h"
-#include "graphic/text_constants.h"
 #include "logic/game.h"
 #include "logic/game_controller.h"
 #include "logic/game_settings.h"
@@ -60,7 +59,8 @@
      ok_(this, "ok", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuPrimary, _("Start game")),
      back_(this, "back", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuSecondary, _("Back")),
      // Text labels
-     title_(this, get_w() / 2, get_h() / 25, "", UI::Align::kCenter),
+     title_(this, get_w() / 2, get_h() / 25, 0, 0, "", UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
      // Variables and objects used in the menu
      settings_(settings),
      ctrl_(ctrl),
@@ -75,7 +75,7 @@
 
 	lua_ = new LuaInterface();
 
-	title_.set_fontsize(fs_big());
+	title_.set_font_scale(scale_factor());
 }
 
 FullscreenMenuLaunchGame::~FullscreenMenuLaunchGame() {

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2019-04-26 11:33:10 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2019-05-03 19:28:13 +0000
@@ -27,7 +27,6 @@
 #include "base/warning.h"
 #include "graphic/graphic.h"
 #include "graphic/playercolor.h"
-#include "graphic/text_constants.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game.h"
 #include "logic/game_controller.h"
@@ -99,7 +98,6 @@
                                                  GameController* const ctrl)
    : FullscreenMenuLaunchGame(settings, ctrl),
      // Values for alignment and size
-     fs_(fs_small()),
      // TODO(GunChleoc): We still need to use these consistently. Just getting them in for now
      // so we can have the SuggestedTeamsBox
      padding_(4),
@@ -128,7 +126,8 @@
                   _("Show the help window")),
 
      // Text labels
-     mapname_(this, right_column_x_, get_h() * 3 / 20, std::string()),
+     mapname_(this, right_column_x_, get_h() * 3 / 20, 0, 0, std::string(), UI::Align::kLeft,
+			  g_gr->styles().font_style(UI::FontStyle::kFsGameSetupMapname)),
      clients_(this,
               // the width of the MultiPlayerSetupGroup is (get_w() * 53 / 80)
               get_w() * 3 / 80,
@@ -136,20 +135,26 @@
               get_w() * 19 / 80,
               get_h() / 10,
               _("Clients"),
-              UI::Align::kCenter),
+              UI::Align::kCenter,
+			  g_gr->styles().font_style(UI::FontStyle::kFsGameSetupHeadings)),
      players_(this,
               get_w() / 4,
               get_h() / 10,
               get_w() * 9 / 20,
               get_h() / 10,
               _("Players"),
-              UI::Align::kCenter),
-     map_(this, right_column_x_, get_h() / 10, butw_, get_h() / 10, _("Map"), UI::Align::kCenter),
+              UI::Align::kCenter,
+			  g_gr->styles().font_style(UI::FontStyle::kFsGameSetupHeadings)),
+     map_(this, right_column_x_, get_h() / 10, butw_, get_h() / 10, _("Map"), UI::Align::kCenter,
+		  g_gr->styles().font_style(UI::FontStyle::kFsGameSetupHeadings)),
      wincondition_type_(this,
                         right_column_x_ + (butw_ / 2),
                         get_h() * 10 / 20 - 1.5 * label_height_,
+						0,
+						0,
                         _("Type of game"),
-                        UI::Align::kCenter),
+                        UI::Align::kCenter,
+						g_gr->styles().font_style(UI::FontStyle::kFsGameSetupHeadings)),
 
      map_info_(this,
                right_column_x_,
@@ -178,15 +183,11 @@
 	help_button_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLaunchMPG::help_clicked, boost::ref(*this)));
 
-	mapname_.set_fontsize(fs_);
-	mapname_.set_color(RGBColor(255, 255, 127));
-	clients_.set_fontsize(fs_);
-	clients_.set_color(RGBColor(0, 255, 0));
-	players_.set_fontsize(fs_);
-	players_.set_color(RGBColor(0, 255, 0));
-	map_.set_fontsize(fs_);
-	map_.set_color(RGBColor(0, 255, 0));
-	wincondition_type_.set_color(RGBColor(0, 255, 0));
+	mapname_.set_font_scale(scale_factor());
+	clients_.set_font_scale(scale_factor());
+	players_.set_font_scale(scale_factor());
+	map_.set_font_scale(scale_factor());
+	wincondition_type_.set_font_scale(scale_factor());
 
 	mapname_.set_text(_("(no map)"));
 	map_info_.set_text(_("The host has not yet selected a map or saved game."));
@@ -385,13 +386,13 @@
 
 	if (settings.mapfilename != filename_proof_) {
 		if (!g_fs->file_exists(settings.mapfilename)) {
-			client_info_.set_color(UI_FONT_CLR_WARNING);
+			client_info_.set_style(g_gr->styles().font_style(UI::FontStyle::kWarning));
 			client_info_.set_text(
 			   _("The selected file can not be found. If it is not automatically "
 			     "transferred to you, please write to the host about this problem."));
 		} else {
 			// Reset font color
-			client_info_.set_color(UI_FONT_CLR_FG);
+			client_info_.set_style(g_gr->styles().font_style(UI::FontStyle::kLabel));
 
 			// Update local nr of players - needed for the client UI
 			nr_players_ = settings.players.size();

=== modified file 'src/ui_fsmenu/launch_mpg.h'
--- src/ui_fsmenu/launch_mpg.h	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/launch_mpg.h	2019-05-03 19:28:13 +0000
@@ -69,8 +69,6 @@
 	void load_map_info();
 	void help_clicked();
 
-	uint32_t fs_;
-
 	// TODO(GunChleoc): We still need to use these consistently. Just getting them in for now
 	// so we can have the SuggestedTeamsBox
 	int32_t const padding_;  // Common padding between panels

=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc	2019-04-26 11:33:10 +0000
+++ src/ui_fsmenu/launch_spg.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/i18n.h"
 #include "base/warning.h"
 #include "base/wexception.h"
-#include "graphic/text_constants.h"
 #include "helper.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game.h"
@@ -58,27 +57,37 @@
      mapname_(this,
               get_w() * 7 / 10 + butw_ / 2,
               get_h() * 53 / 200 - 15,
+			  0,
+			  0,
               std::string(),
               UI::Align::kCenter),
-     name_(this, get_w() * 1 / 25, get_h() * 53 / 200 - 15, _("Player’s name")),
+     name_(this, get_w() * 1 / 25, get_h() * 53 / 200 - 15, 0, 0, _("Player’s name")),
      type_(this,
            // (Element x) + (PlayerDescriptionGroup x)  + border
            ((get_w() * 16 / 25) * 35 / 125) + (get_w() / 25) + 2,
            get_h() * 53 / 200 - 15,
+		   0,
+		   0,
            _("Player’s type")),
      team_(
-        this, ((get_w() * 16 / 25) * 35 / 125) + (get_w() / 25) + 2, get_h() * 53 / 200, _("Team")),
+        this, ((get_w() * 16 / 25) * 35 / 125) + (get_w() / 25) + 2, get_h() * 53 / 200, 0, 0, _("Team")),
      tribe_(this,
             ((get_w() * 16 / 25) * 80 / 125) + (get_w() / 25) + 2,
             get_h() * 53 / 200 - 15,
+			0,
+			0,
             _("Player’s tribe")),
      init_(this,
            ((get_w() * 16 / 25) * 55 / 125) + (get_w() / 25) + 2,
            get_h() * 53 / 200,
+		   0,
+		   0,
            _("Start type")),
      wincondition_type_(this,
                         get_w() * 7 / 10 + (butw_ / 2),
                         get_h() * 7 / 20 + buth_,
+						0,
+						0,
                         _("Type of game"),
                         UI::Align::kCenter),
 
@@ -105,12 +114,13 @@
 	select_map_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLaunchSPG::select_map, boost::ref(*this)));
 
-	int smaller_fontsize = fs_small() * 4 / 5;
-	name_.set_fontsize(smaller_fontsize);
-	type_.set_fontsize(smaller_fontsize);
-	team_.set_fontsize(smaller_fontsize);
-	tribe_.set_fontsize(smaller_fontsize);
-	init_.set_fontsize(smaller_fontsize);
+	// We want to redesign this screen, so we won't bother defining a font size in the style manager.
+	const int small_scale_factor = scale_factor() * 4 / 5;
+	name_.set_font_scale(small_scale_factor);
+	type_.set_font_scale(small_scale_factor);
+	team_.set_font_scale(small_scale_factor);
+	tribe_.set_font_scale(small_scale_factor);
+	init_.set_font_scale(small_scale_factor);
 
 	uint32_t y = get_h() * 3 / 10 - buth_;
 	for (uint32_t i = 0; i < kMaxPlayers; ++i) {

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/loadgame.cc	2019-05-03 19:28:13 +0000
@@ -37,8 +37,11 @@
      title_(&main_box_,
             0,
             0,
+			0,
+			0,
             is_replay ? _("Choose a replay") : _("Choose a saved game"),
-            UI::Align::kCenter),
+            UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
 
      load_or_save_(&info_box_,
                    g,
@@ -112,7 +115,7 @@
 	FullscreenMenuLoadMapOrGame::layout();
 	main_box_.set_size(get_w() - 2 * tablex_, tabley_ + tableh_ + padding_);
 	main_box_.set_pos(Vector2i(tablex_, 0));
-	title_.set_fontsize(fs_big());
+	title_.set_font_scale(scale_factor());
 	load_or_save_.delete_button()->set_desired_size(butw_, buth_);
 	button_spacer_->set_desired_size(butw_, buth_ + 2 * padding_);
 	load_or_save_.table().set_desired_size(tablew_, tableh_);

=== modified file 'src/ui_fsmenu/main.cc'
--- src/ui_fsmenu/main.cc	2019-04-11 05:45:55 +0000
+++ src/ui_fsmenu/main.cc	2019-05-03 19:28:13 +0000
@@ -57,17 +57,21 @@
         this,
         0,
         0,
+		 0,
+		 0,
         /** TRANSLATORS: %1$s = version string, %2%s = "Debug" or "Release" */
         (boost::format(_("Version %1$s (%2$s)")) % build_id().c_str() % build_type().c_str()).str(),
         UI::Align::kRight),
      copyright(this,
                0,
                0,
+			   0,
+			   0,
                /** TRANSLATORS: Placeholders are the copyright years */
                (boost::format(_("(C) %1%-%2% by the Widelands Development Team")) %
                 kWidelandsCopyrightStart % kWidelandsCopyrightEnd)
                   .str()),
-     gpl(this, 0, 0, _("Licensed under the GNU General Public License V2.0")) {
+     gpl(this, 0, 0, 0, 0, _("Licensed under the GNU General Public License V2.0")) {
 	playtutorial.sigclicked.connect(
 	   boost::bind(&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
 	               FullscreenMenuBase::MenuTarget::kTutorial));

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2019-04-18 16:50:35 +0000
+++ src/ui_fsmenu/mapselect.cc	2019-05-03 19:28:13 +0000
@@ -47,7 +47,8 @@
      checkbox_padding_(UI::g_fh->fontset()->size_offset() > 0 ? 0 : 2 * padding_),
 
      // Main title
-     title_(this, 0, 0, _("Choose a map"), UI::Align::kCenter),
+     title_(this, 0, 0, 0, 0, _("Choose a map"), UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
      checkboxes_(this, 0, 0, UI::Box::Vertical, 0, 0, 2 * padding_),
      table_(this, tablex_, tabley_, tablew_, tableh_, UI::PanelStyle::kFsMenu),
      map_details_(this,
@@ -63,7 +64,6 @@
      ctrl_(ctrl),
      has_translated_mapname_(false) {
 	curdir_ = basedir_;
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 	if (settings_->settings().multiplayer) {
 		back_.set_tooltip(_("Return to the multiplayer game setup"));
 	} else {

=== modified file 'src/ui_fsmenu/multiplayer.cc'
--- src/ui_fsmenu/multiplayer.cc	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/multiplayer.cc	2019-05-03 19:28:13 +0000
@@ -20,7 +20,6 @@
 #include "ui_fsmenu/multiplayer.h"
 
 #include "base/i18n.h"
-#include "graphic/text_constants.h"
 #include "network/crypto.h"
 #include "network/internet_gaming.h"
 #include "profile/profile.h"
@@ -32,7 +31,8 @@
    : FullscreenMenuMainMenu(),
 
      // Title
-     title(this, 0, 0, _("Choose game type"), UI::Align::kCenter),
+     title(this, 0, 0, 0, 0, _("Choose game type"), UI::Align::kCenter,
+		   g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
 
      // Buttons
      metaserver(
@@ -51,7 +51,7 @@
 	   boost::bind(&FullscreenMenuMultiPlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 	               boost::ref(*this), FullscreenMenuBase::MenuTarget::kBack));
 
-	title.set_fontsize(fs_big());
+	title.set_font_scale(scale_factor());
 
 	vbox_.add(&metaserver, UI::Box::Resizing::kFullSize);
 	vbox_.add(&lan, UI::Box::Resizing::kFullSize);

=== modified file 'src/ui_fsmenu/netsetup_lan.cc'
--- src/ui_fsmenu/netsetup_lan.cc	2019-04-09 16:43:49 +0000
+++ src/ui_fsmenu/netsetup_lan.cc	2019-05-03 19:28:13 +0000
@@ -22,7 +22,6 @@
 #include "base/i18n.h"
 #include "base/macros.h"
 #include "graphic/graphic.h"
-#include "graphic/text_constants.h"
 #include "network/constants.h"
 #include "network/network.h"
 #include "profile/profile.h"
@@ -37,11 +36,12 @@
      listw_(get_w() * 9 / 16),
 
      // Text labels
-     title(this, get_w() / 2, get_h() / 10, _("Begin Network Game"), UI::Align::kCenter),
+     title(this, get_w() / 2, get_h() / 10, 0, 0, _("Begin Network Game"), UI::Align::kCenter,
+		   g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
      opengames_(
-        this, get_w() * 3 / 50, get_h() * 27 / 100, _("List of games in your local network:")),
-     playername_(this, get_w() * 16 / 25, get_h() * 27 / 100, _("Your nickname:")),
-     hostname_(this, get_w() * 16 / 25, get_h() * 17 / 40, _("Host to connect:")),
+        this, get_w() * 3 / 50, get_h() * 27 / 100, 0, 0, _("List of games in your local network:")),
+     playername_(this, get_w() * 16 / 25, get_h() * 27 / 100, 0, 0, _("Your nickname:")),
+     hostname_(this, get_w() * 16 / 25, get_h() * 17 / 40, 0, 0, _("Host to connect:")),
 
      // Buttons
      joingame(this,
@@ -83,18 +83,12 @@
                 get_w() * 16 / 25,
                 get_h() * 3333 / 10000,
                 butw_,
-                buth_,
-                2,
-                UI::PanelStyle::kFsMenu,
-                fs_small()),
+                UI::PanelStyle::kFsMenu),
      hostname(this,
               get_w() * 16 / 25,
               get_h() * 19 / 40,
               get_w() * 17 / 80,
-              buth_,
-              2,
-              UI::PanelStyle::kFsMenu,
-              fs_small()),
+              UI::PanelStyle::kFsMenu),
 
      // List
      opengames(this,
@@ -114,7 +108,9 @@
 
 	Section& s = g_options.pull_section("global");  //  for playername
 
-	title.set_fontsize(UI_FONT_SIZE_BIG);
+	playername.set_font_scale(scale_factor());
+	hostname.set_font_scale(scale_factor());
+
 	hostname.changed.connect(boost::bind(&FullscreenMenuNetSetupLAN::change_hostname, this));
 	playername.set_text(s.get_string("nickname", (_("nobody"))));
 	playername.changed.connect(boost::bind(&FullscreenMenuNetSetupLAN::change_playername, this));

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2019-03-18 18:03:08 +0000
+++ src/ui_fsmenu/options.cc	2019-05-03 19:28:13 +0000
@@ -35,7 +35,6 @@
 #include "graphic/graphic.h"
 #include "graphic/text/bidi.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "helper.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -79,7 +78,8 @@
      padding_(10),
 
      // Title
-     title_(this, 0, 0, _("Options"), UI::Align::kCenter),
+     title_(this, 0, 0, 0, 0, _("Options"), UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
 
      // Buttons
      button_box_(this, 0, 0, UI::Box::Horizontal),
@@ -213,8 +213,6 @@
      /** TRANSLATORS: and it also lets you jump to it on the map. */
      single_watchwin_(&box_game_, Vector2i::zero(), _("Use single watchwindow mode")),
      os_(opt) {
-	// Set up UI Elements
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 
 	// Buttons
 	button_box_.add(UI::g_fh->fontset()->is_rtl() ? &ok_ : &cancel_);
@@ -523,7 +521,7 @@
 		             .str();
 	}
 	// Make font a bit smaller so the link will fit at 800x600 resolution.
-	translation_info_.set_text(as_uifont(message, 12));
+	translation_info_.set_text(as_richtext_paragraph(message, UI::FontStyle::kFsMenuTranslationInfo));
 }
 
 void FullscreenMenuOptions::clicked_apply() {

=== modified file 'src/ui_fsmenu/scenario_select.cc'
--- src/ui_fsmenu/scenario_select.cc	2019-04-24 01:33:04 +0000
+++ src/ui_fsmenu/scenario_select.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/i18n.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
-#include "graphic/text_constants.h"
 #include "logic/filesystem_constants.h"
 #include "map_io/widelands_map_loader.h"
 #include "profile/profile.h"
@@ -51,8 +50,11 @@
      title_(&header_box_,
             0,
             0,
+			0,
+			0,
             is_tutorial_ ? _("Choose a tutorial") : _("Choose a scenario"),
-            UI::Align::kCenter),
+            UI::Align::kCenter,
+			g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
      subtitle_(&header_box_,
                0,
                0,
@@ -64,7 +66,6 @@
                UI::MultilineTextarea::ScrollMode::kNoScrolling),
      scenario_details_(this),
      campaign_(camp) {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 
 	// Set subtitle of the page
 	if (campaign_ == nullptr) {
@@ -218,9 +219,7 @@
 		te.set_string(0, (boost::format("%d") % (i + 1)).str());
 		te.set_picture(
 		   1, g_gr->images().get("images/ui_basic/ls_wlmap.png"), scenario_data->descname);
-		if (!scenario_data->playable) {
-			te.set_color(UI_FONT_CLR_DISABLED);
-		}
+		te.set_disabled(!scenario_data->playable);
 	}
 
 	if (!table_.empty()) {

=== modified file 'src/ui_fsmenu/scenariodetails.cc'
--- src/ui_fsmenu/scenariodetails.cc	2019-04-24 01:33:04 +0000
+++ src/ui_fsmenu/scenariodetails.cc	2019-05-03 19:28:13 +0000
@@ -21,7 +21,6 @@
 #include <boost/format.hpp>
 
 #include "base/i18n.h"
-#include "graphic/text_constants.h"
 #include "ui_basic/scrollbar.h"
 
 ScenarioDetails::ScenarioDetails(Panel* parent)

=== modified file 'src/ui_fsmenu/singleplayer.cc'
--- src/ui_fsmenu/singleplayer.cc	2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/singleplayer.cc	2019-05-03 19:28:13 +0000
@@ -20,13 +20,12 @@
 #include "ui_fsmenu/singleplayer.h"
 
 #include "base/i18n.h"
-#include "graphic/text_constants.h"
 
 FullscreenMenuSinglePlayer::FullscreenMenuSinglePlayer()
    : FullscreenMenuMainMenu(),
 
      // Title
-     title(this, 0, 0, _("Single Player"), UI::Align::kCenter),
+     title(this, 0, 0, 0, 0, _("Single Player"), UI::Align::kCenter, g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle)),
 
      // Buttons
      new_game(&vbox_, "new_game", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuMenu, _("New Game")),
@@ -48,7 +47,7 @@
 	   boost::bind(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 	               boost::ref(*this), FullscreenMenuBase::MenuTarget::kBack));
 
-	title.set_fontsize(fs_big());
+	title.set_font_scale(scale_factor());
 
 	vbox_.add(&new_game, UI::Box::Resizing::kFullSize);
 	vbox_.add(&campaign, UI::Box::Resizing::kFullSize);

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2019-04-24 06:01:37 +0000
+++ src/wlapplication.cc	2019-05-03 19:28:13 +0000
@@ -55,7 +55,6 @@
 #include "graphic/default_resolution.h"
 #include "graphic/font_handler.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "helper.h"
 #include "io/filesystem/disk_filesystem.h"
 #include "io/filesystem/filesystem_exceptions.h"

=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt	2019-04-24 06:01:37 +0000
+++ src/wui/CMakeLists.txt	2019-05-03 19:28:13 +0000
@@ -26,6 +26,7 @@
     graphic
     graphic_color
     graphic_fonthandler
+    graphic_playercolor
     graphic_text
     graphic_text_layout
     logic
@@ -84,10 +85,11 @@
     base_time_string
     helper
     game_io
+    graphic
     graphic_fonthandler
     graphic_image_io
     graphic_surface
-    graphic_text_constants
+    graphic_text_layout
     io_filesystem
     logic
     logic_filesystem_constants
@@ -113,7 +115,6 @@
     base_log
     graphic
     graphic_fonthandler
-    graphic_text_constants
     graphic_text_layout
     io_filesystem
     logic
@@ -288,7 +289,6 @@
     graphic_playercolor
     graphic_surface
     graphic_text
-    graphic_text_constants
     graphic_text_layout
     io_fileread
     io_filesystem

=== modified file 'src/wui/attack_box.cc'
--- src/wui/attack_box.cc	2019-02-23 11:00:49 +0000
+++ src/wui/attack_box.cc	2019-05-03 19:28:13 +0000
@@ -27,7 +27,6 @@
 #include "base/macros.h"
 #include "graphic/font_handler.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "logic/map_objects/tribes/soldier.h"
 
 constexpr int32_t kUpdateTimeInGametimeMs = 1000;  //  1 second, gametime
@@ -74,9 +73,8 @@
 }
 
 UI::Textarea&
-AttackBox::add_text(UI::Box& parent, std::string str, UI::Align alignment, int fontsize) {
-	UI::Textarea& result = *new UI::Textarea(&parent, str.c_str());
-	result.set_fontsize(fontsize);
+AttackBox::add_text(UI::Box& parent, std::string str, UI::Align alignment, const UI::FontStyleInfo& style) {
+	UI::Textarea& result = *new UI::Textarea(&parent, str.c_str(), UI::Align::kLeft, style);
 	parent.add(&result, UI::Box::Resizing::kAlign, alignment);
 	return result;
 }
@@ -132,7 +130,7 @@
 
 	UI::Box& linebox = *new UI::Box(this, 0, 0, UI::Box::Horizontal);
 	add(&linebox);
-	add_text(linebox, _("Soldiers:"));
+	add_text(linebox, _("Soldiers:"), UI::Align::kLeft, g_gr->styles().font_style(UI::FontStyle::kLabel));
 	linebox.add_space(8);
 
 	less_soldiers_ =
@@ -144,9 +142,8 @@
 
 	const std::string attack_string =
 	   (boost::format(_("%1% / %2%")) % (max_attackers > 0 ? 1 : 0) % max_attackers).str();
-
 	soldiers_text_.reset(
-	   &add_text(columnbox, attack_string, UI::Align::kCenter, UI_FONT_SIZE_ULTRASMALL));
+	   &add_text(columnbox, attack_string, UI::Align::kCenter, g_gr->styles().slider_style(UI::SliderStyle::kWuiDark).font()));
 
 	soldiers_slider_ = add_slider(
 	   columnbox, 100, 10, 0, max_attackers, max_attackers > 0 ? 1 : 0, _("Number of soldiers"));

=== modified file 'src/wui/attack_box.h'
--- src/wui/attack_box.h	2019-02-23 11:00:49 +0000
+++ src/wui/attack_box.h	2019-05-03 19:28:13 +0000
@@ -25,7 +25,6 @@
 
 #include "graphic/font_handler.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "logic/map_objects/bob.h"
 #include "logic/map_objects/tribes/soldier.h"
 #include "logic/player.h"
@@ -65,8 +64,8 @@
 	// TODO(GunChleoc): This should also return a unique_ptr
 	UI::Textarea& add_text(UI::Box& parent,
 	                       std::string str,
-	                       UI::Align alignment = UI::Align::kLeft,
-	                       int fontsize = UI_FONT_SIZE_SMALL);
+	                       UI::Align alignment,
+	                       const UI::FontStyleInfo& style);
 	std::unique_ptr<UI::Button> add_button(UI::Box& parent,
 	                                       const std::string& text,
 	                                       void (AttackBox::*fn)(),

=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc	2019-03-10 16:19:24 +0000
+++ src/wui/building_statistics_menu.cc	2019-05-03 19:28:13 +0000
@@ -38,79 +38,77 @@
 constexpr int kButtonHeight = 20;
 constexpr int kButtonRowHeight = kButtonHeight + kMargin;
 constexpr int kLabelHeight = 18;
-constexpr int kLabelFontSize = 12;
+constexpr int kTabHeight = 35 + 5 * (kBuildGridCellHeight + kLabelHeight + kLabelHeight);
 constexpr int32_t kWindowWidth = kColumns * kBuildGridCellWidth;
 
 constexpr int32_t kUpdateTimeInGametimeMs = 1000;  //  1 second, gametime
 
 using namespace Widelands;
 
-namespace {
-void set_label_font(UI::Textarea* label) {
-	label->set_fontsize(kLabelFontSize);
-}
-}  // namespace
-
 inline InteractivePlayer& BuildingStatisticsMenu::iplayer() const {
 	return dynamic_cast<InteractivePlayer&>(*get_parent());
 }
 
 BuildingStatisticsMenu::BuildingStatisticsMenu(InteractivePlayer& parent,
                                                UI::UniqueWindow::Registry& registry)
-   : UI::UniqueWindow(
-        &parent, "building_statistics", &registry, kWindowWidth, 100, _("Building Statistics")),
+   : UI::UniqueWindow(&parent,
+                      "building_statistics",
+                      &registry,
+                      kWindowWidth,
+                      100,
+                      _("Building Statistics")),
+	  style_(g_gr->styles().building_statistics_style()),
      tab_panel_(this, UI::TabPanelStyle::kWuiDark),
-     navigation_panel_(this, 0, 0, kWindowWidth, 4 * kButtonRowHeight),
+	  navigation_panel_(this, 0, 0, kWindowWidth, 4 * kButtonRowHeight),
      building_name_(
         &navigation_panel_, get_inner_w() / 2, 0, 0, kButtonHeight, "", UI::Align::kCenter),
-     owned_label_(&navigation_panel_, kMargin, kButtonRowHeight, 0, kButtonHeight, _("Owned:")),
+     owned_label_(&navigation_panel_, kMargin, kButtonRowHeight, 0, kButtonHeight, _("Owned:"),
+				  UI::Align::kLeft, style_.building_statistics_details_font()),
      construction_label_(&navigation_panel_,
                          kMargin,
                          2 * kButtonRowHeight,
                          0,
                          kButtonHeight,
-                         _("Under Construction:")),
+                         _("Under Construction:"), UI::Align::kLeft, style_.building_statistics_details_font()),
      unproductive_box_(&navigation_panel_, kMargin, 3 * kButtonRowHeight + 3, UI::Box::Horizontal),
      unproductive_label_(
         &unproductive_box_,
         /** TRANSLATORS: This is the first part of productivity with input field */
         /** TRANSLATORS: Building statistics window - 'Low Productivity <input>%:' */
         _("Low Productivity")),
+	 // We need consistent height here - test
      unproductive_percent_(
         &unproductive_box_,
         0,
         0,
         35,
-        0,
-        1,
-        UI::PanelStyle::kWui,
-        kLabelFontSize - UI::g_fh->fontset()->size_offset()),  // We need consistent height here
+        UI::PanelStyle::kWui),
      unproductive_label2_(
         &unproductive_box_,
         /** TRANSLATORS: This is the second part of productivity with input field */
         /** TRANSLATORS: Building statistics window -  'Low Productivity <input>%:' */
-        _("%:")),
+        _("%:"), UI::Align::kLeft, style_.building_statistics_details_font()),
      no_owned_label_(&navigation_panel_,
                      get_inner_w() - 2 * kButtonRowHeight - kMargin,
                      kButtonRowHeight,
                      0,
                      kButtonHeight,
                      "",
-                     UI::Align::kRight),
+                     UI::Align::kRight, style_.building_statistics_details_font()),
      no_construction_label_(&navigation_panel_,
                             get_inner_w() - 2 * kButtonRowHeight - kMargin,
                             2 * kButtonRowHeight,
                             0,
                             kButtonHeight,
                             "",
-                            UI::Align::kRight),
+                            UI::Align::kRight, style_.building_statistics_details_font()),
      no_unproductive_label_(&navigation_panel_,
                             get_inner_w() - 2 * kButtonRowHeight - kMargin,
                             3 * kButtonRowHeight,
                             0,
                             kButtonHeight,
                             "",
-                            UI::Align::kRight),
+                            UI::Align::kRight, style_.building_statistics_details_font()),
      current_building_type_(INVALID_INDEX),
      last_building_index_(0),
      last_building_type_(INVALID_INDEX),
@@ -124,13 +122,7 @@
 	owned_labels_ = std::vector<UI::Textarea*>(nr_building_types_);
 	productivity_labels_ = std::vector<UI::Textarea*>(nr_building_types_);
 
-	set_label_font(&owned_label_);
-	set_label_font(&construction_label_);
-	set_label_font(&unproductive_label_);
-	set_label_font(&unproductive_label2_);
-	set_label_font(&no_owned_label_);
-	set_label_font(&no_construction_label_);
-	set_label_font(&no_unproductive_label_);
+	unproductive_percent_.set_font_style_and_margin(style_.building_statistics_details_font(), style_.editbox_margin());
 
 	unproductive_label_.set_size(unproductive_label_.get_w(), kButtonRowHeight);
 	unproductive_percent_.set_text(std::to_string(low_production_));
@@ -411,14 +403,14 @@
 	button_box->add(building_buttons_[id]);
 
 	owned_labels_[id] =
-	   new UI::Textarea(button_box, 0, 0, kBuildGridCellWidth, kLabelHeight, UI::Align::kCenter);
-	owned_labels_[id]->set_fontsize(kLabelFontSize);
+	   new UI::Textarea(button_box, 0, 0, kBuildGridCellWidth, kLabelHeight, "", UI::Align::kCenter,
+						style_.building_statistics_button_font());
 	owned_labels_[id]->set_fixed_width(kBuildGridCellWidth);
 	button_box->add(owned_labels_[id]);
 
 	productivity_labels_[id] =
-	   new UI::Textarea(button_box, 0, 0, kBuildGridCellWidth, kLabelHeight, UI::Align::kCenter);
-	productivity_labels_[id]->set_fontsize(kLabelFontSize);
+	   new UI::Textarea(button_box, 0, 0, kBuildGridCellWidth, kLabelHeight, "", UI::Align::kCenter,
+						style_.building_statistics_button_font());
 	productivity_labels_[id]->set_fixed_width(kBuildGridCellWidth);
 	button_box->add(productivity_labels_[id]);
 
@@ -673,16 +665,14 @@
 				int const percent =
 				   static_cast<int>(static_cast<float>(total_prod) / static_cast<float>(nr_owned));
 
-				RGBColor color;
-				if (percent < low_production_) {
-					color = UI_FONT_CLR_BAD;
-				} else if (percent < ((low_production_ < 50) ?
-				                         2 * low_production_ :
-				                         low_production_ + ((100 - low_production_) / 2))) {
-					color = UI_FONT_CLR_OK;
-				} else {
-					color = UI_FONT_CLR_GOOD;
-				}
+				const RGBColor& color = (percent < low_production_) ?
+							style_.low_color() :
+							(percent < ((low_production_ < 50) ?
+												2 * low_production_ :
+												low_production_ + ((100 - low_production_) / 2))) ?
+								style_.medium_color() :
+								style_.high_color();
+
 				/** TRANSLATORS: Percent in building statistics window, e.g. 85% */
 				/** TRANSLATORS: If you wish to add a space, translate as '%i %%' */
 				const std::string perc_str = (boost::format(_("%i%%")) % percent).str();
@@ -706,14 +696,11 @@
 			}
 		} else if (building.type() == MapObjectType::MILITARYSITE) {
 			if (nr_owned) {
-				RGBColor color;
-				if (total_stationed_soldiers < total_soldier_capacity / 2) {
-					color = UI_FONT_CLR_BAD;
-				} else if (total_stationed_soldiers < total_soldier_capacity) {
-					color = UI_FONT_CLR_OK;
-				} else {
-					color = UI_FONT_CLR_GOOD;
-				}
+				const RGBColor& color =  (total_stationed_soldiers < total_soldier_capacity / 2) ?
+							style_.low_color() :
+							(total_stationed_soldiers < total_soldier_capacity) ?
+								style_.medium_color() :
+								style_.high_color();
 				const std::string perc_str =
 				   (boost::format(_("%1%/%2%")) % total_stationed_soldiers % total_soldier_capacity)
 				      .str();
@@ -745,7 +732,7 @@
 		} else {
 			owned_text = (boost::format(_("%1%/%2%")) % nr_owned % "–").str();
 		}
-		set_labeltext(owned_labels_[id], owned_text, UI_FONT_CLR_FG);
+		set_labeltext(owned_labels_[id], owned_text, style_.building_statistics_details_font().color());
 		owned_labels_[id]->set_visible((nr_owned + nr_build) > 0);
 
 		building_buttons_[id]->set_enabled((nr_owned + nr_build) > 0);
@@ -771,10 +758,10 @@
 	}
 }
 
-void BuildingStatisticsMenu::set_labeltext(UI::Textarea* textarea,
-                                           const std::string& text,
-                                           const RGBColor& color) {
-	textarea->set_color(color);
+void BuildingStatisticsMenu::set_labeltext(UI::Textarea* textarea, const std::string& text, const RGBColor& color) {
+	UI::FontStyleInfo style(style_.building_statistics_button_font());
+	style.set_color(color);
+	textarea->set_style(style);
 	textarea->set_text(text);
 	textarea->set_visible(true);
 }

=== modified file 'src/wui/building_statistics_menu.h'
--- src/wui/building_statistics_menu.h	2019-02-23 11:00:49 +0000
+++ src/wui/building_statistics_menu.h	2019-05-03 19:28:13 +0000
@@ -92,7 +92,7 @@
 	/// Jumps to the next / previous appropriate building
 	void jump_building(JumpTarget target, bool reverse);
 
-	/// Sets the label for id type to text in the chosen color with dynamic font size
+	/// Sets the label for the given textarea to text in the chosen color
 	void set_labeltext(UI::Textarea* textarea, const std::string& text, const RGBColor& color);
 
 	/// Sets the current building type for the bottom navigation
@@ -108,6 +108,9 @@
 
 	InteractivePlayer& iplayer() const;
 
+	/// Style
+	const UI::BuildingStatisticsStyleInfo& style_;
+
 	/// UI tabs
 	UI::TabPanel tab_panel_;
 	UI::Box* tabs_[kNoOfBuildingTabs];

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2019-03-25 15:39:52 +0000
+++ src/wui/buildingwindow.cc	2019-05-03 19:28:13 +0000
@@ -253,10 +253,9 @@
 			const Widelands::TribeDescr& tribe = owner.tribe();
 			if (owner.is_building_type_allowed(enhancement)) {
 				const Widelands::BuildingDescr& building_descr = *tribe.get_building_descr(enhancement);
-
 				std::string enhance_tooltip =
 				   (boost::format(_("Enhance to %s")) % building_descr.descname().c_str()).str() +
-				   "<br><font size=11>" + _("Construction costs:") + "</font><br>" +
+				   "<br>" + g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal).header_font().as_font_tag(_("Construction costs:")) + "<br>" +
 				   waremap_to_richtext(tribe, building_descr.enhancement_cost());
 
 				UI::Button* enhancebtn =
@@ -293,7 +292,9 @@
 
 				UI::Button* dismantlebtn =
 				   new UI::Button(capsbuttons, "dismantle", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
-				                  g_gr->images().get(pic_dismantle), dismantle_text);
+				                  g_gr->images().get(pic_dismantle),
+				                  std::string(_("Dismantle")) + "<br>" + g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal).header_font().as_font_tag(_("Returns:")) +
+				                     "<br>" + waremap_to_richtext(owner.tribe(), wares));
 				dismantlebtn->sigclicked.connect(
 				   boost::bind(&BuildingWindow::act_dismantle, boost::ref(*this)));
 				capsbuttons->add(dismantlebtn);

=== modified file 'src/wui/chat_msg_layout.cc'
--- src/wui/chat_msg_layout.cc	2019-02-23 11:00:49 +0000
+++ src/wui/chat_msg_layout.cc	2019-05-03 19:28:13 +0000
@@ -22,22 +22,19 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
 
-#include "chat/chat.h"
 #include "graphic/color.h"
+#include "graphic/playercolor.h"
 #include "graphic/text_layout.h"
 #include "logic/player.h"
 
 namespace {
 
-// Returns the hexcolor for the 'player'.
-std::string color(const int16_t playern) {
-	if ((playern >= 0) && playern < kMaxPlayers) {
-		const RGBColor& clr = kPlayerColors[playern];
-		char buf[sizeof("ffffff")];
-		snprintf(buf, sizeof(buf), "%.2x%.2x%.2x", clr.r, clr.g, clr.b);
-		return buf;
-	}
-	return "999999";
+// Returns a player name font tag with player color.
+std::string as_playercolor(const int16_t playern, const std::string& text) {
+	const RGBColor& playercolor = ((playern >= 0) && playern < kMaxPlayers) ?
+				kPlayerColors[playern] :
+				g_gr->styles().font_style(UI::FontStyle::kChatServer).color();
+	return g_gr->styles().font_style(UI::FontStyle::kChatPlayername).as_font_tag(g_gr->styles().color_tag(text, playercolor));
 }
 
 std::string sanitize_message(const std::string& given_text) {
@@ -51,59 +48,46 @@
 
 // Returns a richtext string that can be displayed to the user.
 std::string format_as_richtext(const ChatMessage& chat_message) {
-	const std::string& font_face = "serif";
-	std::string message = "<p><font color=33ff33 size=9>";
-
-	const std::string sanitized = sanitize_message(chat_message.msg);
-
-	// time calculation
+	// Time calculation
 	char ts[13];
 	strftime(ts, sizeof(ts), "[%H:%M] ", localtime(&chat_message.time));
-	message += ts;
-
-	message = (boost::format("%s</font><font size=14 face=%s color=%s") % message % font_face %
-	           color(chat_message.playern))
-	             .str();
-
+
+	std::string message = g_gr->styles().font_style(UI::FontStyle::kChatTimestamp).as_font_tag(ts);
+
+	const std::string sanitized = sanitize_message(chat_message.msg);
 	const std::string sender_escaped = richtext_escape(chat_message.sender);
 	const std::string recipient_escaped = richtext_escape(chat_message.recipient);
 
 	if (chat_message.recipient.size() && chat_message.sender.size()) {
 		// Personal message handling
 		if (sanitized.compare(0, 3, "/me")) {
-			message = (boost::format(
-			              "%s bold=1>%s @ %s:</font><font size=14 face=%s shadow=1 color=eeeeee> %s") %
-			           message % sender_escaped % recipient_escaped % font_face % sanitized)
-			             .str();
-
+			message += as_playercolor(chat_message.playern,
+						(boost::format("%s @%s:") % sender_escaped % recipient_escaped).str());
+			message += g_gr->styles().font_style(UI::FontStyle::kChatWhisper).as_font_tag(
+						(boost::format("%s %s") % message % sanitized).str());
 		} else {
-			message =
-			   (boost::format(
-			       "%s>@%s &gt; </font><font size=14 face=%s color=%s italic=1 shadow=1> %s%s") %
-			    message % recipient_escaped % font_face % color(chat_message.playern) %
-			    sender_escaped % sanitized.substr(3))
-			      .str();
+			message += message = as_playercolor(chat_message.playern, (
+						(boost::format("@%s: -&gt; %s") % recipient_escaped % sender_escaped).str()));
+			message += g_gr->styles().font_style(UI::FontStyle::kChatWhisper).as_font_tag(
+						(boost::format("%s %s") % message % sanitized.substr(3)).str());
 		}
 	} else {
 		// Normal messages handling
 		if (!sanitized.compare(0, 3, "/me")) {
-			message += " italic=1>-&gt; ";
-			if (chat_message.sender.size())
-				message += sender_escaped;
-			else
-				message += "***";
-			message += sanitized.substr(3);
+			message += message = as_playercolor(chat_message.playern, (
+						(boost::format("-&gt; %s") % (chat_message.sender.empty() ? "***" : sender_escaped)).str()));
+			message += g_gr->styles().font_style(UI::FontStyle::kChatMessage).as_font_tag(
+						(boost::format("%s %s") % message % sanitized.substr(3)).str());
 		} else if (chat_message.sender.size()) {
-			message =
-			   (boost::format("%s bold=1>%s:</font><font size=14 face=%s shadow=1 color=eeeeee> %s") %
-			    message % sender_escaped % font_face % sanitized)
+			const std::string sender_formatted = as_playercolor(chat_message.playern, (boost::format("%s:") % sender_escaped).str());
+			message +=
+			   (boost::format("%s %s") %
+			    sender_formatted % g_gr->styles().font_style(UI::FontStyle::kChatMessage).as_font_tag(sanitized))
 			      .str();
 		} else {
-			message += " bold=1>*** ";
-			message += sanitized;
+			message += g_gr->styles().font_style(UI::FontStyle::kChatServer).as_font_tag("*** " + sanitized);
 		}
 	}
 
-	// return the formated message
-	return message + "</font><br></p>";
+	return (boost::format("<p>%s</p>") % message).str();
 }

=== modified file 'src/wui/chat_overlay.cc'
--- src/wui/chat_overlay.cc	2019-02-23 11:00:49 +0000
+++ src/wui/chat_overlay.cc	2019-05-03 19:28:13 +0000
@@ -21,11 +21,15 @@
 
 #include <memory>
 
+#include <boost/format.hpp>
+
 #include "base/macros.h"
 #include "base/wexception.h"
 #include "chat/chat.h"
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/style_manager.h"
 #include "graphic/text/rt_errors.h"
 #include "profile/profile.h"
 #include "wui/chat_msg_layout.h"
@@ -130,8 +134,8 @@
 			oldest_ = log_messages_[log_idx].time;
 			// Do some richtext formatting here
 			if (now - oldest_ < CHAT_DISPLAY_TIME) {
-				richtext = "<p><font face=serif size=14 color=dddddd bold=1>" +
-				           log_messages_[log_idx].msg + "<br></font></p>" + richtext;
+				richtext = (boost::format("<p>%s</p>")
+						% g_gr->styles().font_style(UI::FontStyle::kChatServer).as_font_tag(log_messages_[log_idx].msg)).str();
 			}
 			log_idx--;
 		} else if (log_idx < 0 || (chat_idx >= 0 && chat_->get_messages()[chat_idx].time >=

=== modified file 'src/wui/encyclopedia_window.cc'
--- src/wui/encyclopedia_window.cc	2019-02-23 11:00:49 +0000
+++ src/wui/encyclopedia_window.cc	2019-05-03 19:28:13 +0000
@@ -26,6 +26,7 @@
 #include <boost/format.hpp>
 
 #include "base/i18n.h"
+#include "graphic/text_layout.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
 #include "scripting/lua_coroutine.h"

=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc	2019-02-23 11:00:49 +0000
+++ src/wui/fieldaction.cc	2019-05-03 19:28:13 +0000
@@ -90,13 +90,10 @@
 	const Widelands::BuildingDescr& descr =
 	   *plr_->tribe().get_building_descr(Widelands::DescriptionIndex(id));
 
-	// TODO(sirver): change this to take a Button subclass instead of
-	// parameters. This will allow overriding the way it is rendered
-	// to bring back player colors.
 	UI::IconGrid::add(descr.name(), descr.representative_image(&plr_->get_playercolor()),
 	                  reinterpret_cast<void*>(id),
-	                  descr.descname() + "<br><font size=11>" + _("Construction costs:") +
-	                     "</font><br>" + waremap_to_richtext(plr_->tribe(), descr.buildcost()));
+	                  descr.descname() + "<br>" + g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal).header_font().as_font_tag(_("Construction costs:")) +
+	                     "<br>" + waremap_to_richtext(plr_->tribe(), descr.buildcost()));
 }
 
 /*

=== modified file 'src/wui/game_chat_panel.cc'
--- src/wui/game_chat_panel.cc	2019-04-24 06:01:37 +0000
+++ src/wui/game_chat_panel.cc	2019-05-03 19:28:13 +0000
@@ -46,7 +46,7 @@
              "",
              UI::Align::kLeft,
              UI::MultilineTextarea::ScrollMode::kScrollLogForced),
-     editbox(this, 0, h - 20, w, 20, 2, style),
+     editbox(this, 0, h - 20, w, style),
      chat_message_counter(0),
      chat_sound(SoundHandler::register_fx(SoundType::kChat, "sound/lobby_chat")) {
 
@@ -68,7 +68,7 @@
 void GameChatPanel::recalculate(bool has_new_message) {
 	const std::vector<ChatMessage> msgs = chat_.get_messages();
 
-	size_t msgs_size = msgs.size();
+	const size_t msgs_size = msgs.size();
 	std::string str = "<rt>";
 	for (uint32_t i = 0; i < msgs_size; ++i) {
 		str += format_as_richtext(msgs[i]);

=== modified file 'src/wui/game_main_menu_save_game.cc'
--- src/wui/game_main_menu_save_game.cc	2019-02-23 11:00:49 +0000
+++ src/wui/game_main_menu_save_game.cc	2019-05-03 19:28:13 +0000
@@ -64,7 +64,7 @@
 
      filename_box_(load_or_save_.table_box(), 0, 0, UI::Box::Horizontal),
      filename_label_(&filename_box_, 0, 0, 0, 0, _("Filename:"), UI::Align::kLeft),
-     filename_editbox_(&filename_box_, 0, 0, 0, 0, 2, UI::PanelStyle::kWui),
+     filename_editbox_(&filename_box_, 0, 0, 0, UI::PanelStyle::kWui),
 
      buttons_box_(load_or_save_.game_details()->button_box(), 0, 0, UI::Box::Horizontal),
      cancel_(&buttons_box_, "cancel", 0, 0, 0, 0, UI::ButtonStyle::kWuiSecondary, _("Cancel")),

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2019-04-18 16:50:35 +0000
+++ src/wui/game_message_menu.cc	2019-05-03 19:28:13 +0000
@@ -25,6 +25,7 @@
 #include "base/time_string.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
+#include "graphic/text_layout.h"
 #include "logic/map_objects/map_object.h"
 #include "logic/message_queue.h"
 #include "logic/player.h"

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2019-02-23 11:00:49 +0000
+++ src/wui/game_summary.cc	2019-05-03 19:28:13 +0000
@@ -47,7 +47,7 @@
 	game_.game_controller()->set_desired_speed(0);
 	// Init boxes
 	UI::Box* vbox = new UI::Box(this, 0, 0, UI::Box::Vertical, 0, 0, PADDING);
-	title_area_ = new UI::Textarea(vbox, "", UI::Align::kCenter);
+	title_area_ = new UI::Textarea(vbox, "", UI::Align::kCenter, g_gr->styles().font_style(UI::FontStyle::kFsMenuTitle));
 	vbox->add(title_area_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
 	vbox->add_space(PADDING);
 
@@ -104,9 +104,6 @@
 	players_table_->add_column(100, _("Status"), "", UI::Align::kCenter);
 	players_table_->add_column(100, _("Time"), "", UI::Align::kCenter);
 
-	// Prepare Elements
-	title_area_->set_fontsize(UI_FONT_SIZE_BIG);
-
 	// Connections
 	continue_button_->sigclicked.connect(boost::bind(&GameSummaryScreen::continue_clicked, this));
 	stop_button_->sigclicked.connect(boost::bind(&GameSummaryScreen::stop_clicked, this));

=== modified file 'src/wui/gamedetails.cc'
--- src/wui/gamedetails.cc	2019-02-23 11:00:49 +0000
+++ src/wui/gamedetails.cc	2019-05-03 19:28:13 +0000
@@ -28,12 +28,12 @@
 #include "base/i18n.h"
 #include "base/log.h"
 #include "base/time_string.h"
+#include "graphic/graphic.h"
 #include "graphic/image_io.h"
-#include "graphic/text_constants.h"
+#include "graphic/text_layout.h"
 #include "graphic/texture.h"
 #include "io/filesystem/layered_filesystem.h"
 
-// TODO(GunChleoc): Arabic: line height broken for descriptions for Arabic.
 SavegameData::SavegameData()
    : gametime(""),
      nrplayers("0"),
@@ -87,7 +87,7 @@
 	add(button_box_, UI::Box::Resizing::kFullSize);
 
 	minimap_icon_.set_visible(false);
-	minimap_icon_.set_frame(UI_FONT_CLR_FG);
+	minimap_icon_.set_frame(g_gr->styles().minimap_icon_frame());
 }
 
 void GameDetails::clear() {

=== modified file 'src/wui/helpwindow.cc'
--- src/wui/helpwindow.cc	2019-02-23 11:00:49 +0000
+++ src/wui/helpwindow.cc	2019-05-03 19:28:13 +0000
@@ -25,6 +25,7 @@
 #include <boost/format.hpp>
 
 #include "base/i18n.h"
+#include "graphic/text_layout.h"
 #include "logic/map_objects/tribes/building.h"
 #include "scripting/lua_interface.h"
 #include "scripting/lua_table.h"

=== modified file 'src/wui/inputqueuedisplay.cc'
--- src/wui/inputqueuedisplay.cc	2019-04-25 06:40:24 +0000
+++ src/wui/inputqueuedisplay.cc	2019-05-03 19:28:13 +0000
@@ -27,6 +27,7 @@
 #include "economy/request.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/text_layout.h"
 #include "logic/player.h"
 #include "wui/interactive_gamebase.h"
 
@@ -242,19 +243,23 @@
 	uint32_t x = Border;
 	uint32_t y = Border + (total_height_ - 2 * Border - WARE_MENU_PIC_WIDTH) / 2;
 
-	boost::format tooltip_format("%s<br><p><font size=%d bold=0>%s<br>%s</font></p>");
+	boost::format tooltip_format("<p>%s%s%s</p>");
 
 	decrease_max_fill_ = new UI::Button(
 	   this, "decrease_max_fill", x, y, WARE_MENU_PIC_WIDTH, WARE_MENU_PIC_HEIGHT,
 	   UI::ButtonStyle::kWuiMenu, g_gr->images().get("images/ui_basic/scrollbar_left.png"),
 	   (tooltip_format
-	    /** TRANSLATORS: Button tooltip in in a building's wares input queue */
-	    % _("Decrease the number of wares you want to be stored here") %
-	    UI_FONT_SIZE_MESSAGE
-	    /** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
-	    % _("Hold down Shift to decrease all ware types at the same time")
-	    /** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
-	    % _("Hold down Ctrl to allow none of this ware"))
+	    % g_gr->styles().font_style(UI::FontStyle::kTooltipHeader).as_font_tag(
+			/** TRANSLATORS: Button tooltip in in a building's wares input queue */
+			_("Decrease the number of wares you want to be stored here"))
+
+	    % as_listitem(
+			/** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
+			_("Hold down Shift to decrease all ware types at the same time"), UI::FontStyle::kTooltip)
+
+	    % as_listitem(
+			/** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
+			_("Hold down Ctrl to allow none of this ware"), UI::FontStyle::kTooltip))
 	      .str());
 	decrease_max_fill_->sigclicked.connect(
 	   boost::bind(&InputQueueDisplay::decrease_max_fill_clicked, boost::ref(*this)));
@@ -265,13 +270,18 @@
 	   this, "increase_max_fill", x, y, WARE_MENU_PIC_WIDTH, WARE_MENU_PIC_HEIGHT,
 	   UI::ButtonStyle::kWuiMenu, g_gr->images().get("images/ui_basic/scrollbar_right.png"),
 	   (tooltip_format
-	    /** TRANSLATORS: Button tooltip in a building's wares input queue */
-	    % _("Increase the number of wares you want to be stored here") %
-	    UI_FONT_SIZE_MESSAGE
-	    /** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
-	    % _("Hold down Shift to increase all ware types at the same time")
-	    /** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
-	    % _("Hold down Ctrl to allow all of this ware"))
+
+	    % g_gr->styles().font_style(UI::FontStyle::kTooltipHeader).as_font_tag(
+			/** TRANSLATORS: Button tooltip in a building's wares input queue */
+			_("Increase the number of wares you want to be stored here"))
+
+	    % as_listitem(
+			/** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
+			_("Hold down Shift to increase all ware types at the same time"), UI::FontStyle::kTooltip)
+
+	    % as_listitem(
+			/** TRANSLATORS: Button tooltip in in a building's wares input queue - option explanation */
+			_("Hold down Ctrl to allow all of this ware"), UI::FontStyle::kTooltip))
 	      .str());
 	increase_max_fill_->sigclicked.connect(
 	   boost::bind(&InputQueueDisplay::increase_max_fill_clicked, boost::ref(*this)));

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2019-04-25 06:31:33 +0000
+++ src/wui/interactive_base.cc	2019-05-03 19:28:13 +0000
@@ -34,7 +34,6 @@
 #include "graphic/default_resolution.h"
 #include "graphic/font_handler.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "logic/cmd_queue.h"
 #include "logic/game.h"
@@ -513,7 +512,7 @@
 	}
 	if (!node_text.empty()) {
 		std::shared_ptr<const UI::RenderedText> rendered_text =
-		   UI::g_fh->render(as_condensed(node_text));
+		   UI::g_fh->render(as_richtext_paragraph(node_text, UI::FontStyle::kWuiGameSpeedAndCoordinates));
 		rendered_text->draw(
 		   dst, Vector2i(get_w() - 5, get_h() - rendered_text->height() - 5), UI::Align::kRight);
 	}
@@ -523,14 +522,14 @@
 		// Blit in-game clock
 		const std::string gametime(gametimestring(egbase().get_gametime(), true));
 		std::shared_ptr<const UI::RenderedText> rendered_text =
-		   UI::g_fh->render(as_condensed(gametime));
+		   UI::g_fh->render(as_richtext_paragraph(gametime, UI::FontStyle::kWuiGameSpeedAndCoordinates));
 		rendered_text->draw(dst, Vector2i(5, 5));
 
 		// Blit FPS when playing a game in debug mode
 		if (get_display_flag(dfDebug)) {
 			static boost::format fps_format("%5.1f fps (avg: %5.1f fps)");
-			rendered_text = UI::g_fh->render(as_condensed(
-			   (fps_format % (1000.0 / frametime_) % (1000.0 / (avg_usframetime_ / 1000))).str()));
+			rendered_text = UI::g_fh->render(as_richtext_paragraph(
+			   (fps_format % (1000.0 / frametime_) % (1000.0 / (avg_usframetime_ / 1000))).str(), UI::FontStyle::kWuiGameSpeedAndCoordinates));
 			rendered_text->draw(dst, Vector2i((get_w() - rendered_text->width()) / 2, 5));
 		}
 	}

=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc	2019-03-01 16:24:48 +0000
+++ src/wui/interactive_gamebase.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "base/macros.h"
 #include "graphic/font_handler.h"
 #include "graphic/rendertarget.h"
-#include "graphic/text_constants.h"
 #include "graphic/text_layout.h"
 #include "logic/findbob.h"
 #include "logic/game.h"
@@ -122,18 +121,18 @@
 		uint32_t const desired = game_controller->desired_speed();
 		if (real == desired) {
 			if (real != 1000) {
-				game_speed = as_condensed(speed_string(real));
+				game_speed = speed_string(real);
 			}
 		} else {
-			game_speed = as_condensed((boost::format
+			game_speed = (boost::format
 			                           /** TRANSLATORS: actual_speed (desired_speed) */
 			                           (_("%1$s (%2$s)")) %
 			                           speed_string(real) % speed_string(desired))
-			                             .str());
+			                             .str();
 		}
 
 		if (!game_speed.empty()) {
-			std::shared_ptr<const UI::RenderedText> rendered_text = UI::g_fh->render(game_speed);
+			std::shared_ptr<const UI::RenderedText> rendered_text = UI::g_fh->render(as_richtext_paragraph(game_speed, UI::FontStyle::kWuiGameSpeedAndCoordinates));
 			rendered_text->draw(dst, Vector2i(get_w() - 5, 5), UI::Align::kRight);
 		}
 	}

=== modified file 'src/wui/load_or_save_game.cc'
--- src/wui/load_or_save_game.cc	2019-04-18 16:50:35 +0000
+++ src/wui/load_or_save_game.cc	2019-05-03 19:28:13 +0000
@@ -31,6 +31,7 @@
 #include "game_io/game_loader.h"
 #include "game_io/game_preload_packet.h"
 #include "graphic/font_handler.h"
+#include "graphic/text_layout.h"
 #include "helper.h"
 #include "io/filesystem/filesystem_exceptions.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -93,33 +94,33 @@
                             _("Delete"))),
      game_(g) {
 	table_.add_column(130, _("Save Date"), _("The date this game was saved"), UI::Align::kLeft);
+
 	if (filetype_ != FileType::kGameSinglePlayer) {
-		std::vector<std::string> modes;
+		std::string game_mode_tooltip =
+				/** TRANSLATORS: Tooltip header for the "Mode" column when choosing a game/replay to load. */
+				/** TRANSLATORS: %s is a list of game modes. */
+				g_gr->styles().font_style(UI::FontStyle::kTooltipHeader).as_font_tag(_("Game Mode"));
+
 		if (filetype_ == FileType::kReplay) {
 			/** TRANSLATORS: Tooltip for the "Mode" column when choosing a game/replay to load. */
 			/** TRANSLATORS: Make sure that you keep consistency in your translation. */
-			modes.push_back(_("SP = Single Player"));
+			game_mode_tooltip += as_listitem(_("SP = Single Player"), UI::FontStyle::kTooltip);
 		}
 		/** TRANSLATORS: Tooltip for the "Mode" column when choosing a game/replay to load. */
 		/** TRANSLATORS: Make sure that you keep consistency in your translation. */
-		modes.push_back(_("MP = Multiplayer"));
+		game_mode_tooltip += as_listitem(_("MP = Multiplayer"), UI::FontStyle::kTooltip);
 		/** TRANSLATORS: Tooltip for the "Mode" column when choosing a game/replay to load. */
 		/** TRANSLATORS: Make sure that you keep consistency in your translation. */
-		modes.push_back(_("H = Multiplayer (Host)"));
-		const std::string mode_tooltip_1 =
-		   /** TRANSLATORS: Tooltip for the "Mode" column when choosing a game/replay to load. */
-		   /** TRANSLATORS: %s is a list of game modes. */
-		   ((boost::format(_("Game Mode: %s.")) %
-		     i18n::localize_list(modes, i18n::ConcatenateWith::COMMA)))
-		      .str();
-		const std::string mode_tooltip_2 = _("Numbers are the number of players.");
+		game_mode_tooltip += as_listitem(_("H = Multiplayer (Host)"), UI::FontStyle::kTooltip);
+
+		game_mode_tooltip += g_gr->styles().font_style(UI::FontStyle::kTooltip).as_font_tag(_("Numbers are the number of players."));
 
 		table_.add_column(
 		   65,
 		   /** TRANSLATORS: Game Mode table column when choosing a game/replay to load. */
 		   /** TRANSLATORS: Keep this to 5 letters maximum. */
 		   /** TRANSLATORS: A tooltip will explain if you need to use an abbreviation. */
-		   _("Mode"), (boost::format("%s %s") % mode_tooltip_1 % mode_tooltip_2).str());
+		   _("Mode"), game_mode_tooltip);
 	}
 	table_.add_column(0, _("Description"),
 	                  _("The filename that the game was saved under followed by the map’s name, "

=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc	2019-02-23 11:00:49 +0000
+++ src/wui/login_box.cc	2019-05-03 19:28:13 +0000
@@ -21,6 +21,8 @@
 
 #include "base/i18n.h"
 #include "graphic/font_handler.h"
+#include "graphic/graphic.h"
+#include "graphic/style_manager.h"
 #include "profile/profile.h"
 #include "ui_basic/button.h"
 #include "ui_basic/messagebox.h"
@@ -31,14 +33,15 @@
 
 	int32_t margin = 10;
 
-	ta_nickname = new UI::Textarea(this, margin, margin, _("Nickname:"));
-	ta_password = new UI::Textarea(this, margin, 40, _("Password:"));
-	eb_nickname = new UI::EditBox(this, 150, margin, 330, 20, 2, UI::PanelStyle::kWui);
-	eb_password = new UI::EditBox(this, 150, 40, 330, 20, 2, UI::PanelStyle::kWui);
+	ta_nickname = new UI::Textarea(this, margin, margin, 0, 0, _("Nickname:"));
+	ta_password = new UI::Textarea(this, margin, 40, 0, 0, _("Password:"));
+	eb_nickname = new UI::EditBox(this, 150, margin, 330, UI::PanelStyle::kWui);
+	eb_password = new UI::EditBox(this, 150, 40, 330, UI::PanelStyle::kWui);
 
 	pwd_warning =
 	   new UI::MultilineTextarea(this, margin, 65, 505, 50, UI::PanelStyle::kWui,
 	                             _("WARNING: Password will be shown and saved readable!"));
+	pwd_warning->set_style(g_gr->styles().font_style(UI::FontStyle::kWarning));
 
 	cb_register = new UI::Checkbox(this, Vector2i(margin, 110), _("Log in to a registered account"),
 	                               "", get_inner_w() - 2 * margin);

=== modified file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	2019-04-18 16:50:35 +0000
+++ src/wui/mapdetails.cc	2019-05-03 19:28:13 +0000
@@ -27,8 +27,6 @@
 #include "base/i18n.h"
 #include "base/log.h"
 #include "base/wexception.h"
-#include "graphic/font_handler.h"
-#include "graphic/text_constants.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game_controller.h"
 #include "logic/game_settings.h"
@@ -70,7 +68,10 @@
 }
 
 void MapDetails::layout() {
-	name_label_.set_size(get_w() - padding_, text_height() + 2);
+	name_label_.set_size(get_w() - padding_, text_height(style_ == UI::PanelStyle::kFsMenu ?
+	                                                        UI::FontStyle::kFsMenuInfoPanelHeading :
+	                                                        UI::FontStyle::kWuiInfoPanelHeading) +
+	                                            2);
 
 	// Adjust sizes for show / hide suggested teams
 	if (suggested_teams_box_->is_visible()) {

=== modified file 'src/wui/multiplayersetupgroup.cc'
--- src/wui/multiplayersetupgroup.cc	2019-02-23 11:00:49 +0000
+++ src/wui/multiplayersetupgroup.cc	2019-05-03 19:28:13 +0000
@@ -32,7 +32,6 @@
 #include "base/wexception.h"
 #include "graphic/graphic.h"
 #include "graphic/playercolor.h"
-#include "graphic/text_constants.h"
 #include "logic/game.h"
 #include "logic/game_settings.h"
 #include "logic/map_objects/tribes/tribe_basic_info.h"

=== modified file 'src/wui/multiplayersetupgroup.h'
--- src/wui/multiplayersetupgroup.h	2019-02-23 11:00:49 +0000
+++ src/wui/multiplayersetupgroup.h	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 
 #include "graphic/font_handler.h"
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "network/network_player_settings_backend.h"
 #include "ui_basic/box.h"
 #include "ui_basic/panel.h"

=== modified file 'src/wui/playerdescrgroup.cc'
--- src/wui/playerdescrgroup.cc	2019-02-23 11:00:49 +0000
+++ src/wui/playerdescrgroup.cc	2019-05-03 19:28:13 +0000
@@ -26,7 +26,6 @@
 #include "ai/computer_player.h"
 #include "base/i18n.h"
 #include "base/wexception.h"
-#include "graphic/text_constants.h"
 #include "logic/game_settings.h"
 #include "logic/map_objects/tribes/tribe_basic_info.h"
 #include "logic/player.h"

=== modified file 'src/wui/plot_area.cc'
--- src/wui/plot_area.cc	2019-04-24 19:40:14 +0000
+++ src/wui/plot_area.cc	2019-05-03 19:28:13 +0000
@@ -50,10 +50,8 @@
    15 * kMinutes, 30 * kMinutes, 1 * kHours, 2 * kHours, 5 * kHours, 10 * kHours, 30 * kHours};
 
 const char BG_PIC[] = "images/wui/plot_area_bg.png";
-const RGBColor kAxisLineColor(0, 0, 0);
 constexpr int kAxisLinesWidth = 2;
 constexpr int kPlotLinesWidth = 3;
-const RGBColor kZeroLineColor(255, 255, 255);
 
 enum class Units {
 	kMinutesNarrow,
@@ -64,16 +62,14 @@
 	kDayGeneric
 };
 
-std::string ytick_text_style(const std::string& text, const RGBColor& clr) {
-	static boost::format f(
-	   "<rt keep_spaces=1><p><font face=condensed size=13 color=%02x%02x%02x>%s</font></p></rt>");
-	f % int(clr.r) % int(clr.g) % int(clr.b);
-	f % text;
+std::string ytick_text_style(const std::string& text, const UI::FontStyleInfo& style) {
+	static boost::format f("<rt keep_spaces=1><p>%s</p></rt>");
+	f % style.as_font_tag(text);
 	return f.str();
 }
 
 std::string xtick_text_style(const std::string& text) {
-	return ytick_text_style(text, RGBColor(255, 0, 0));
+	return ytick_text_style(text, g_gr->styles().statistics_plot_style().x_tick_font());
 }
 
 /**
@@ -173,10 +169,10 @@
  * print the string into the RenderTarget.
  */
 void draw_value(const std::string& value,
-                const RGBColor& color,
+                const UI::FontStyleInfo& style,
                 const Vector2i& pos,
                 RenderTarget& dst) {
-	std::shared_ptr<const UI::RenderedText> tick = UI::g_fh->render(ytick_text_style(value, color));
+	std::shared_ptr<const UI::RenderedText> tick = UI::g_fh->render(ytick_text_style(value, style));
 	Vector2i point(pos);  // Un-const this
 	UI::center_vertically(tick->height(), &point);
 	tick->draw(dst, point, UI::Align::kRight);
@@ -184,12 +180,15 @@
 
 uint32_t calc_plot_x_max_ticks(int32_t plot_width) {
 	// Render a number with 3 digits (maximal length which should appear)
-	return plot_width / UI::g_fh->render(ytick_text_style(" -888 ", kAxisLineColor))->width();
+	return plot_width / UI::g_fh->render(xtick_text_style(" -888 "))->width();
 }
 
 int calc_slider_label_width(const std::string& label) {
 	// Font size and style as used by DiscreteSlider
-	return UI::g_fh->render(as_condensed(label, UI::Align::kLeft, UI_FONT_SIZE_SMALL - 2))->width();
+	return UI::g_fh
+	   ->render(as_richtext_paragraph(
+	      label, g_gr->styles().slider_style(UI::SliderStyle::kWuiLight).font()))
+	   ->width();
 }
 
 /**
@@ -200,6 +199,9 @@
                   const uint32_t inner_h,
                   const float xline_length,
                   RenderTarget& dst) {
+	const RGBColor& axis_line_color =
+	   g_gr->styles().statistics_plot_style().axis_line_color();
+
 	uint32_t how_many_ticks, max_x;
 
 	Units unit = get_suggested_unit(time_ms, true);
@@ -234,7 +236,7 @@
 	// X Axis
 	dst.draw_line_strip({Vector2f(kSpacing, inner_h - kSpaceBottom),
 	                     Vector2f(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
-	                    kAxisLineColor, kAxisLinesWidth);
+	                    axis_line_color, kAxisLinesWidth);
 	// Arrow
 	dst.draw_line_strip(
 	   {
@@ -242,12 +244,12 @@
 	      Vector2f(kSpacing, inner_h - kSpaceBottom),
 	      Vector2f(kSpacing + 5, inner_h - kSpaceBottom + 3),
 	   },
-	   kAxisLineColor, kAxisLinesWidth);
+	   axis_line_color, kAxisLinesWidth);
 
 	//  Y Axis
 	dst.draw_line_strip({Vector2f(inner_w - kSpaceRight, kSpacing * 3),
 	                     Vector2f(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
-	                    kAxisLineColor, kAxisLinesWidth);
+	                    axis_line_color, kAxisLinesWidth);
 	//  No Arrow here, since this doesn't continue.
 
 	float sub = (xline_length - kSpaceLeftOfLabel) / how_many_ticks;
@@ -256,7 +258,7 @@
 	for (uint32_t i = 0; i <= how_many_ticks; ++i) {
 		dst.draw_line_strip({Vector2f(static_cast<int32_t>(posx), inner_h - kSpaceBottom),
 		                     Vector2f(static_cast<int32_t>(posx), inner_h - kSpaceBottom + 3)},
-		                    kAxisLineColor, kAxisLinesWidth);
+		                    axis_line_color, kAxisLinesWidth);
 
 		// The space at the end is intentional to have the tick centered
 		// over the number, not to the left
@@ -274,7 +276,7 @@
 	//  draw yticks, one at full, one at three-quarter, one at half, one at quarter & 0
 	dst.draw_line_strip({Vector2f(inner_w - kSpaceRight + 3, kSpacing * 3),
 	                     Vector2f(inner_w - kSpaceRight - 3, kSpacing * 3)},
-	                    kAxisLineColor, kAxisLinesWidth);
+	                    axis_line_color, kAxisLinesWidth);
 
 	dst.draw_line_strip(
 	   {Vector2f(
@@ -283,12 +285,12 @@
 	    Vector2f(
 	       inner_w - kSpaceRight,
 	       kSpacing * 3 + ((((inner_h - kSpaceBottom) + kSpacing * 3) / 2) - kSpacing * 3) / 2)},
-	   kAxisLineColor, kAxisLinesWidth);
+	   axis_line_color, kAxisLinesWidth);
 
 	dst.draw_line_strip(
 	   {Vector2f(inner_w - kSpaceRight + 3, ((inner_h - kSpaceBottom) + kSpacing * 3) / 2),
 	    Vector2f(inner_w - kSpaceRight, ((inner_h - kSpaceBottom) + kSpacing * 3) / 2)},
-	   kAxisLineColor, kAxisLinesWidth);
+	   axis_line_color, kAxisLinesWidth);
 
 	dst.draw_line_strip(
 	   {Vector2f(inner_w - kSpaceRight + 2,
@@ -297,11 +299,11 @@
 	    Vector2f(inner_w - kSpaceRight,
 	             inner_h - kSpaceBottom -
 	                (inner_h - kSpaceBottom - ((inner_h - kSpaceBottom) + kSpacing * 3) / 2) / 2)},
-	   kAxisLineColor, kAxisLinesWidth);
+	   axis_line_color, kAxisLinesWidth);
 
 	dst.draw_line_strip({Vector2f(inner_w - kSpaceRight + 3, inner_h - kSpaceBottom),
 	                     Vector2f(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
-	                    kAxisLineColor, kAxisLinesWidth);
+	                    axis_line_color, kAxisLinesWidth);
 
 	//  print the used unit
 	std::shared_ptr<const UI::RenderedText> xtick =
@@ -487,7 +489,7 @@
 	         Vector2i::zero());
 	draw_plot(dst, get_inner_h() - kSpaceBottom, std::to_string(highest_scale_), highest_scale_);
 	// Print the 0
-	draw_value((boost::format("%u") % (0)).str(), RGBColor(255, 0, 0),
+	draw_value((boost::format("%u") % (0)).str(), g_gr->styles().statistics_plot_style().x_tick_font(),
 	           Vector2i(get_inner_w() - kSpaceRight + 3, get_inner_h() - kSpaceBottom + 10), dst);
 }
 
@@ -509,7 +511,7 @@
 	draw_diagram(time_ms_, get_inner_w(), get_inner_h(), xline_length_, dst);
 
 	//  print the maximal value into the top right corner
-	draw_value(yscale_label, RGBColor(60, 125, 0),
+	draw_value(yscale_label, g_gr->styles().statistics_plot_style().y_max_value_font(),
 	           Vector2i(get_inner_w() - kSpaceRight + 3, kSpacing + 2), dst);
 }
 
@@ -708,13 +710,14 @@
 	// draw zero line
 	dst.draw_line_strip({Vector2f(get_inner_w() - kSpaceRight, yoffset),
 	                     Vector2f(get_inner_w() - kSpaceRight - xline_length_, yoffset)},
-	                    kZeroLineColor, kPlotLinesWidth);
+	                    g_gr->styles().statistics_plot_style().zero_line_color(),
+	                    kPlotLinesWidth);
 
 	// Draw data and diagram
 	draw_plot(dst, yoffset, std::to_string(highest_scale_), 2 * highest_scale_);
-
 	// Print the min value
-	draw_value((boost::format("-%u") % (highest_scale_)).str(), RGBColor(60, 125, 0),
+	draw_value((boost::format("-%u") % (highest_scale_)).str(),
+	           g_gr->styles().statistics_plot_style().y_min_value_font(),
 	           Vector2i(get_inner_w() - kSpaceRight + 3, get_inner_h() - kSpaceBottom + 10), dst);
 }
 

=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc	2019-02-23 11:00:49 +0000
+++ src/wui/soldierlist.cc	2019-05-03 19:28:13 +0000
@@ -26,6 +26,7 @@
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
+#include "graphic/text_layout.h"
 #include "logic/map_objects/tribes/building.h"
 #include "logic/map_objects/tribes/militarysite.h"
 #include "logic/map_objects/tribes/soldier.h"
@@ -357,6 +358,7 @@
 
 	InteractiveGameBase& igbase_;
 	Widelands::Building& building_;
+	const UI::FontStyle font_style_;
 	SoldierPanel soldierpanel_;
 	UI::Radiogroup soldier_preference_;
 	UI::Textarea infotext_;
@@ -367,6 +369,7 @@
 
      igbase_(igb),
      building_(building),
+	  font_style_(UI::FontStyle::kLabel),
      soldierpanel_(*this, igb.egbase(), building),
      infotext_(this, _("Click soldier to send away")) {
 	add(&soldierpanel_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
@@ -379,17 +382,17 @@
 	soldierpanel_.set_click(boost::bind(&SoldierList::eject, this, _1));
 
 	// We don't want translators to translate this twice, so it's a bit involved.
-	int w = UI::g_fh
-	           ->render(
-	              as_uifont((boost::format("%s ")  // We need some extra space to fix bug 724169
+	int w =
+	   UI::g_fh->render(as_richtext_paragraph(
+	                        (boost::format("%s ")  // We need some extra space to fix bug 724169
 	                         % (boost::format(
 	                               /** TRANSLATORS: Health, Attack, Defense, Evade */
 	                               _("HP: %1$u/%2$u  AT: %3$u/%4$u  DE: %5$u/%6$u  EV: %7$u/%8$u")) %
 	                            8 % 8 % 8 % 8 % 8 % 8 % 8 % 8))
-	                           .str()))
-	           ->width();
+	                           .str(), font_style_))
+	      ->width();
 	uint32_t maxtextwidth =
-	   std::max(w, UI::g_fh->render(as_uifont(_("Click soldier to send away")))->width());
+	   std::max(w, UI::g_fh->render(as_richtext_paragraph(_("Click soldier to send away"), font_style_))->width());
 	set_min_desired_breadth(maxtextwidth + 4);
 
 	UI::Box* buttons = new UI::Box(this, 0, 0, UI::Box::Horizontal);

=== modified file 'src/wui/sound_options.h'
--- src/wui/sound_options.h	2019-03-18 06:08:21 +0000
+++ src/wui/sound_options.h	2019-05-03 19:28:13 +0000
@@ -19,6 +19,7 @@
 #ifndef WL_WUI_SOUND_OPTIONS_H
 #define WL_WUI_SOUND_OPTIONS_H
 
+#include "graphic/styles/text_panel_style.h"
 #include "ui_basic/box.h"
 
 /**

=== modified file 'src/wui/waresdisplay.cc'
--- src/wui/waresdisplay.cc	2019-02-23 11:00:49 +0000
+++ src/wui/waresdisplay.cc	2019-05-03 19:28:13 +0000
@@ -316,12 +316,14 @@
 	}
 
 	//  draw a background
-	const Image* bgpic = g_gr->images().get(draw_selected ? "images/wui/ware_list_bg_selected.png" :
-	                                                        "images/wui/ware_list_bg.png");
-	uint16_t w = bgpic->width();
+	const UI::WareInfoStyleInfo& style = draw_selected ?
+				g_gr->styles().ware_info_style(UI::WareInfoStyle::kHighlight) :
+				g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal);
+
+	uint16_t w = style.icon_background_image()->width();
 
 	const Vector2i p = ware_position(id);
-	dst.blit(p, bgpic);
+	dst.blit(p, style.icon_background_image());
 
 	const Image* icon = type_ == Widelands::wwWORKER ? tribe_.get_worker_descr(id)->icon() :
 	                                                   tribe_.get_ware_descr(id)->icon();
@@ -332,7 +334,7 @@
 	              info_color_for_ware(id));
 
 	std::shared_ptr<const UI::RenderedText> rendered_text =
-	   UI::g_fh->render(as_waresinfo(info_for_ware(id)));
+	   UI::g_fh->render(as_richtext_paragraph(info_for_ware(id), style.info_font()));
 	rendered_text->draw(dst, Vector2i(p.x + w - rendered_text->width() - 1,
 	                                  p.y + WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 1 -
 	                                     rendered_text->height()));
@@ -378,7 +380,7 @@
 }
 
 RGBColor AbstractWaresDisplay::info_color_for_ware(Widelands::DescriptionIndex /* ware */) {
-	return RGBColor(0, 0, 0);
+	return g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal).info_background();
 }
 
 WaresDisplay::~WaresDisplay() {
@@ -433,14 +435,17 @@
 	std::vector<Widelands::DescriptionIndex>::iterator j;
 	Widelands::TribeDescr::WaresOrder order = tribe.wares_order();
 
+	const UI::WareInfoStyleInfo& style = g_gr->styles().ware_info_style(UI::WareInfoStyle::kNormal);
+
 	for (i = order.begin(); i != order.end(); ++i)
 		for (j = i->begin(); j != i->end(); ++j)
 			if ((c = map.find(*j)) != map.end()) {
 				ret += "<div width=30 padding=2><p align=center>"
-				       "<div width=26 background=454545><p align=center><img src=\"" +
+				       "<div width=26 background=" + style.icon_background().hex_value() + "><p align=center><img src=\"" +
 				       tribe.get_ware_descr(c->first)->icon_filename() +
-				       "\"></p></div><div width=26 background=000000><p><font size=9>" +
-				       get_amount_string(c->second) + "</font></p></div></p></div>";
+				       "\"></p></div><div width=26 background=" + style.info_background().hex_value() + "><p>" +
+				       style.info_font().as_font_tag(get_amount_string(c->second)) +
+				       "</p></div></p></div>";
 			}
 	return ret;
 }


Follow ups