← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/scrollbar_beautification into lp:widelands

 

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

Commit message:
Improved scrollbar and table header layout and fixed croopping issues with scrolling dropdowns.

- Scrollbars now use brighten_rect for their layout and have a beveled edge. Removed background picture.
- Button background for scrollbars and table headers is now configurable.
- Tables can now assign a column that will adjust its width according to overall table size. Stop painting into the scrollbar.
- Fixed text cropping for scrolling dropdowns.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/scrollbar_beautification/+merge/309635
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/scrollbar_beautification into lp:widelands.
=== removed file 'data/images/ui_basic/scrollbar_background.png'
Binary files data/images/ui_basic/scrollbar_background.png	2014-12-03 10:10:14 +0000 and data/images/ui_basic/scrollbar_background.png	1970-01-01 00:00:00 +0000 differ
=== modified file 'src/editor/ui_menus/categorized_item_selection_menu.h'
--- src/editor/ui_menus/categorized_item_selection_menu.h	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/categorized_item_selection_menu.h	2016-10-30 09:05:12 +0000
@@ -90,6 +90,7 @@
                               20,
                               "",
                               UI::Align::kCenter,
+                              g_gr->images().get("images/ui_basic/but1.png"),
                               UI::MultilineTextarea::ScrollMode::kNoScrolling),
      tool_(tool) {
 	add(&tab_panel_, UI::Align::kCenter);

=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc	2016-10-25 08:11:31 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc	2016-10-30 09:05:12 +0000
@@ -79,7 +79,13 @@
      author_(&main_box_, 0, 0, max_w_, 0, 2, g_gr->images().get("images/ui_basic/but1.png")),
      size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),
 
-     teams_list_(&teams_box_, 0, 0, max_w_, 60, UI::ListselectLayout::kShowCheck),
+     teams_list_(&teams_box_,
+                 0,
+                 0,
+                 max_w_,
+                 60,
+                 g_gr->images().get("images/ui_basic/but1.png"),
+                 UI::ListselectLayout::kShowCheck),
 
      modal_(modal) {
 
@@ -96,8 +102,10 @@
 	// height.
 	hint_ =
 	   new UI::MultilineEditbox(&main_box_, 0, 0, max_w_, std::max(labelh_, remaining_space * 1 / 3),
-	                            "", g_gr->images().get("images/ui_basic/but1.png"));
+	                            "", g_gr->images().get("images/ui_basic/but1.png"),
+	                            g_gr->images().get("images/ui_basic/but1.png"));
 	descr_ = new UI::MultilineEditbox(&main_box_, 0, 0, max_w_, remaining_space - hint_->get_h(), "",
+	                                  g_gr->images().get("images/ui_basic/but1.png"),
 	                                  g_gr->images().get("images/ui_basic/but1.png"));
 
 	main_box_.add(

=== modified file 'src/ui_basic/box.cc'
--- src/ui_basic/box.cc	2016-10-16 09:31:42 +0000
+++ src/ui_basic/box.cc	2016-10-30 09:05:12 +0000
@@ -166,7 +166,9 @@
 			pagesize = get_inner_h() - Scrollbar::kSize;
 		}
 		if (scrollbar_ == nullptr) {
-			scrollbar_.reset(new Scrollbar(this, sb_x, sb_y, sb_w, sb_h, orientation_ == Horizontal));
+			scrollbar_.reset(new Scrollbar(this, sb_x, sb_y, sb_w, sb_h,
+			                               g_gr->images().get("images/ui_basic/but3.png"),
+			                               orientation_ == Horizontal));
 			scrollbar_->moved.connect(boost::bind(&Box::scrollbar_moved, this, _1));
 		} else {
 			scrollbar_->set_pos(Vector2i(sb_x, sb_y));

=== modified file 'src/ui_basic/dropdown.cc'
--- src/ui_basic/dropdown.cc	2016-10-28 10:05:18 +0000
+++ src/ui_basic/dropdown.cc	2016-10-30 09:05:12 +0000
@@ -26,15 +26,19 @@
 #include "base/i18n.h"
 #include "graphic/align.h"
 #include "graphic/font_handler1.h"
-#include "graphic/graphic.h"
-#include "graphic/image.h"
 #include "graphic/rendertarget.h"
 #include "ui_basic/mouse_constants.h"
 
 namespace UI {
 
-BaseDropdown::BaseDropdown(
-   UI::Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label)
+BaseDropdown::BaseDropdown(UI::Panel* parent,
+                           int32_t x,
+                           int32_t y,
+                           uint32_t w,
+                           uint32_t h,
+                           const std::string& label,
+                           const Image* background,
+                           const Image* button_background)
    : UI::Panel(
         parent,
         x,
@@ -53,22 +57,15 @@
                   0,
                   24,
                   get_h(),
-                  g_gr->images().get("images/ui_basic/but3.png"),
+                  button_background,
                   g_gr->images().get("images/ui_basic/scrollbar_down.png"),
                   pgettext("dropdown", "Select Item")),
-     display_button_(&button_box_,
-                     "dropdown_label",
-                     0,
-                     0,
-                     w - 24,
-                     get_h(),
-                     g_gr->images().get("images/ui_basic/but1.png"),
-                     label),
+     display_button_(&button_box_, "dropdown_label", 0, 0, w - 24, get_h(), background, label),
      // Hook into parent so we can drop down outside the panel
-     list_(parent, x, y + get_h(), w, 0, ListselectLayout::kDropdown),
+     list_(parent, x, y + get_h(), w, 0, button_background, ListselectLayout::kDropdown),
      label_(label) {
 	list_.set_visible(false);
-	list_.set_background(g_gr->images().get("images/ui_basic/but1.png"));
+	list_.set_background(background);
 	display_button_.set_perm_pressed(true);
 	button_box_.add(&display_button_, UI::Align::kLeft);
 	button_box_.add(&push_button_, UI::Align::kLeft);

=== modified file 'src/ui_basic/dropdown.h'
--- src/ui_basic/dropdown.h	2016-10-28 17:52:59 +0000
+++ src/ui_basic/dropdown.h	2016-10-30 09:05:12 +0000
@@ -25,6 +25,8 @@
 
 #include <boost/signals2.hpp>
 
+#include "graphic/graphic.h"
+#include "graphic/image.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/listselect.h"
@@ -35,14 +37,22 @@
 /// Implementation for a dropdown menu that lets the user select a value.
 class BaseDropdown : public Panel {
 protected:
-	/// \param parent     the parent panel
-	/// \param x          the x-position within 'parent'
-	/// \param y          the y-position within 'parent'
-	/// \param w          the dropdown's width
-	/// \param h          the maximum height for the dropdown list
-	/// \param label      a label to prefix to the selected entry on the display button.
-	BaseDropdown(
-	   Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label);
+	/// \param parent             the parent panel
+	/// \param x                  the x-position within 'parent'
+	/// \param y                  the y-position within 'parent'
+	/// \param w                  the dropdown's width
+	/// \param h                  the maximum height for the dropdown list
+	/// \param label              a label to prefix to the selected entry on the display button.
+	/// \param background         the background image for this dropdown
+	/// \param button_background  the background image all buttons in this dropdown
+	BaseDropdown(Panel* parent,
+	             int32_t x,
+	             int32_t y,
+	             uint32_t w,
+	             uint32_t h,
+	             const std::string& label,
+	             const Image* background,
+	             const Image* button_background);
 	~BaseDropdown();
 
 public:
@@ -103,7 +113,7 @@
 	/// Returns true if the mouse pointer left the vicinity of the dropdown.
 	bool is_mouse_away() const;
 
-	uint32_t max_list_height_;
+	int max_list_height_;
 	const int mouse_tolerance_;  // Allow mouse outside the panel a bit before autocollapse
 	UI::Box button_box_;
 	UI::Button push_button_;
@@ -117,15 +127,23 @@
 /// A dropdown menu that lets the user select a value of the datatype 'Entry'.
 template <typename Entry> class Dropdown : public BaseDropdown {
 public:
-	/// \param parent     the parent panel
-	/// \param x          the x-position within 'parent'
-	/// \param y          the y-position within 'parent'
-	/// \param w          the dropdown's width
-	/// \param h          the maximum height for the dropdown list
-	/// \param label      a label to prefix to the selected entry on the display button.
-	///                   entry.
-	Dropdown(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label)
-	   : BaseDropdown(parent, x, y, w, h, label) {
+	/// \param parent             the parent panel
+	/// \param x                  the x-position within 'parent'
+	/// \param y                  the y-position within 'parent'
+	/// \param w                  the dropdown's width
+	/// \param h                  the maximum height for the dropdown list
+	/// \param label              a label to prefix to the selected entry on the display button.
+	/// \param background         the background image for this dropdown
+	/// \param button_background  the background image all buttons in this dropdown
+	Dropdown(Panel* parent,
+	         int32_t x,
+	         int32_t y,
+	         uint32_t w,
+	         uint32_t h,
+	         const std::string& label,
+	         const Image* background = g_gr->images().get("images/ui_basic/but1.png"),
+	         const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"))
+	   : BaseDropdown(parent, x, y, w, h, label, background, button_background) {
 	}
 	~Dropdown() {
 		clear();

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2016-10-28 17:52:59 +0000
+++ src/ui_basic/listselect.cc	2016-10-30 09:05:12 +0000
@@ -51,12 +51,13 @@
                                const int32_t y,
                                const uint32_t w,
                                const uint32_t h,
+                               const Image* button_background,
                                const ListselectLayout selection_mode)
    : Panel(parent, x, y, w, h),
      lineheight_(
         UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() +
         kMargin),
-     scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, false),
+     scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, button_background),
      scrollpos_(0),
      selection_(no_selection_index()),
      last_click_time_(-10000),
@@ -66,12 +67,9 @@
 	set_thinks(false);
 
 	scrollbar_.moved.connect(boost::bind(&BaseListselect::set_scrollpos, this, _1));
-	scrollbar_.set_singlestepsize(lineheight_);
-	scrollbar_.set_pagesize(h - 2 * lineheight_);
-	scrollbar_.set_steps(1);
 
 	if (selection_mode_ == ListselectLayout::kShowCheck) {
-		uint32_t pic_h;
+		int pic_h;
 		check_pic_ = g_gr->images().get("images/ui_basic/list_selected.png");
 		max_pic_width_ = check_pic_->width();
 		pic_h = check_pic_->height();
@@ -81,6 +79,7 @@
 		max_pic_width_ = 0;
 	}
 	set_can_focus(true);
+	layout();
 }
 
 /**
@@ -125,10 +124,10 @@
 	er->use_clr = false;
 	er->name = name;
 	er->tooltip = tooltip_text;
-	uint32_t entry_height = lineheight_;
+	int entry_height = lineheight_;
 	if (pic) {
-		uint16_t w = pic->width();
-		uint16_t h = pic->height();
+		int w = pic->width();
+		int h = pic->height();
 		entry_height = (h >= entry_height) ? h : entry_height;
 		if (max_pic_width_ < w)
 			max_pic_width_ = w;
@@ -139,7 +138,7 @@
 
 	entry_records_.push_back(er);
 
-	scrollbar_.set_steps(entry_records_.size() * get_lineheight() - get_h());
+	layout();
 
 	if (sel)
 		select(entry_records_.size() - 1);
@@ -161,10 +160,10 @@
 	er->name = name;
 	er->tooltip = tooltip_text;
 
-	uint32_t entry_height = lineheight_;
+	int entry_height = lineheight_;
 	if (pic) {
-		uint16_t w = pic->width();
-		uint16_t h = pic->height();
+		int w = pic->width();
+		int h = pic->height();
 		entry_height = (h >= entry_height) ? h : entry_height;
 		if (max_pic_width_ < w)
 			max_pic_width_ = w;
@@ -175,7 +174,7 @@
 
 	entry_records_.push_front(er);
 
-	scrollbar_.set_steps(entry_records_.size() * get_lineheight() - get_h());
+	layout();
 
 	if (sel)
 		select(0);
@@ -307,7 +306,7 @@
 	return entry_records_[selection_]->tooltip;
 }
 
-uint32_t BaseListselect::get_lineheight() const {
+int BaseListselect::get_lineheight() const {
 	return lineheight_ + kMargin;
 }
 
@@ -318,7 +317,11 @@
 void BaseListselect::layout() {
 	scrollbar_.set_size(scrollbar_.get_w(), get_h());
 	scrollbar_.set_pagesize(get_h() - 2 * get_lineheight());
-	scrollbar_.set_steps(entry_records_.size() * get_lineheight() - get_h());
+	const int steps = entry_records_.size() * get_lineheight() - get_h();
+	scrollbar_.set_steps(steps);
+	if (scrollbar_.is_enabled() && selection_mode_ == ListselectLayout::kDropdown) {
+		scrollbar_.set_steps(steps + kMargin);
+	}
 }
 
 /**
@@ -327,7 +330,7 @@
 void BaseListselect::draw(RenderTarget& dst) {
 	// draw text lines
 	const int eff_h =
-	   selection_mode_ == ListselectLayout::kDropdown ? get_inner_h() - 4 : get_inner_h();
+	   selection_mode_ == ListselectLayout::kDropdown ? get_inner_h() - kMargin : get_inner_h();
 	uint32_t idx = scrollpos_ / get_lineheight();
 	int y = 1 + idx * get_lineheight() - scrollpos_;
 
@@ -346,21 +349,24 @@
 		dst.fill_rect(Rectf(get_w() - 2.f, 1.f, 1.f, get_h() - 1.f), black);
 		dst.fill_rect(Rectf(get_w() - 1.f, 0.f, 1.f, get_h()), black);
 	} else {
-		dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
+		dst.brighten_rect(Rectf(0.f, 0.f, get_eff_w(), get_h()), ms_darken_value);
 	}
 
-	int lineheight = lineheight_;
 	while (idx < entry_records_.size()) {
 		assert(eff_h < std::numeric_limits<int32_t>::max());
 
+		const EntryRecord& er = *entry_records_[idx];
+		const Image* entry_text_im = UI::g_fh1->render(as_uifont(
+		   richtext_escape(er.name), UI_FONT_SIZE_SMALL, er.use_clr ? er.clr : UI_FONT_CLR_FG));
+
+		int lineheight = std::max(get_lineheight(), entry_text_im->height());
+
 		// Don't draw over the bottom edge
 		lineheight = std::min(eff_h - y, lineheight);
 		if (lineheight < 0) {
 			break;
 		}
 
-		const EntryRecord& er = *entry_records_[idx];
-
 		Vector2f point(selection_mode_ == ListselectLayout::kDropdown ? 3.f : 1.f, y);
 		uint32_t maxw =
 		   get_eff_w() -
@@ -384,18 +390,15 @@
 			}
 		}
 
-		uint32_t picw = max_pic_width_ ? max_pic_width_ + 10 : 0;
+		int picw = max_pic_width_ ? max_pic_width_ + 10 : 0;
 
 		// Now draw pictures
 		if (er.pic) {
 			dst.blit(Vector2f(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
-			                  y + (lineheight_ - er.pic->height()) / 2),
+			                  y + (get_lineheight() - er.pic->height()) / 2),
 			         er.pic);
 		}
 
-		const Image* entry_text_im = UI::g_fh1->render(as_uifont(
-		   richtext_escape(er.name), UI_FONT_SIZE_SMALL, er.use_clr ? er.clr : UI_FONT_CLR_FG));
-
 		Align alignment =
 		   i18n::has_rtl_character(er.name.c_str(), 20) ? UI::Align::kRight : UI::Align::kLeft;
 		if (static_cast<int>(alignment & UI::Align::kRight)) {
@@ -410,7 +413,7 @@
 		}
 
 		// Fix vertical position for mixed font heights
-		if (lineheight_ > static_cast<uint32_t>(entry_text_im->height())) {
+		if (get_lineheight() > entry_text_im->height()) {
 			point.y += (lineheight_ - entry_text_im->height()) / 2;
 		} else {
 			point.y -= (entry_text_im->height() - lineheight_) / 2;

=== modified file 'src/ui_basic/listselect.h'
--- src/ui_basic/listselect.h	2016-10-28 17:52:59 +0000
+++ src/ui_basic/listselect.h	2016-10-30 09:05:12 +0000
@@ -26,6 +26,7 @@
 #include <boost/signals2.hpp>
 
 #include "graphic/color.h"
+#include "graphic/graphic.h"
 #include "ui_basic/panel.h"
 #include "ui_basic/scrollbar.h"
 
@@ -50,6 +51,7 @@
 	               int32_t y,
 	               uint32_t w,
 	               uint32_t h,
+	               const Image* button_background,
 	               ListselectLayout selection_mode = ListselectLayout::kPlain);
 	~BaseListselect();
 
@@ -109,7 +111,7 @@
 	}
 
 	///  Return the total height (text + spacing) occupied by a single line.
-	uint32_t get_lineheight() const;
+	int get_lineheight() const;
 
 	uint32_t get_eff_w() const;
 
@@ -142,8 +144,8 @@
 	};
 	using EntryRecordDeque = std::deque<EntryRecord*>;
 
-	uint32_t max_pic_width_;
-	uint32_t lineheight_;
+	int max_pic_width_;
+	int lineheight_;
 	EntryRecordDeque entry_records_;
 	Scrollbar scrollbar_;
 	uint32_t scrollpos_;  //  in pixels
@@ -162,8 +164,9 @@
 	           int32_t y,
 	           uint32_t w,
 	           uint32_t h,
+	           const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
 	           ListselectLayout selection_mode = ListselectLayout::kPlain)
-	   : BaseListselect(parent, x, y, w, h, selection_mode) {
+	   : BaseListselect(parent, x, y, w, h, button_background, selection_mode) {
 	}
 
 	void add(const std::string& name,
@@ -214,8 +217,9 @@
 	           int32_t y,
 	           uint32_t w,
 	           uint32_t h,
+	           const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
 	           ListselectLayout selection_mode = ListselectLayout::kPlain)
-	   : Base(parent, x, y, w, h, selection_mode) {
+	   : Base(parent, x, y, w, h, button_background, selection_mode) {
 	}
 
 	void add(const std::string& name,

=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/messagebox.cc	2016-10-30 09:05:12 +0000
@@ -71,8 +71,9 @@
 		scrollmode = MultilineTextarea::ScrollMode::kScrollNormal;
 	}
 
-	textarea_.reset(new MultilineTextarea(
-	   this, margin, margin, width - 2 * margin, height, text, align, scrollmode));
+	textarea_.reset(new MultilineTextarea(this, margin, margin, width - 2 * margin, height, text,
+	                                      align, g_gr->images().get("images/ui_basic/but1.png"),
+	                                      scrollmode));
 
 	// Now add the buttons
 	const int button_y = textarea_->get_y() + textarea_->get_h() + 2 * margin;

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2016-10-16 20:35:47 +0000
+++ src/ui_basic/multilineeditbox.cc	2016-10-30 09:05:12 +0000
@@ -59,7 +59,7 @@
 	WordWrap ww;
 	/*@}*/
 
-	Data(MultilineEditbox&);
+	Data(MultilineEditbox&, const Image* button_background);
 	void refresh_ww();
 
 	void update();
@@ -87,8 +87,9 @@
                                    uint32_t w,
                                    uint32_t h,
                                    const std::string& text,
-                                   const Image* background)
-   : Panel(parent, x, y, w, h), d_(new Data(*this)) {
+                                   const Image* background,
+                                   const Image* button_background)
+   : Panel(parent, x, y, w, h), d_(new Data(*this, button_background)) {
 	d_->background = background;
 	set_handle_mouse(true);
 	set_can_focus(true);
@@ -98,8 +99,8 @@
 	set_text(text);
 }
 
-MultilineEditbox::Data::Data(MultilineEditbox& o)
-   : scrollbar(&o, o.get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, o.get_h(), false),
+MultilineEditbox::Data::Data(MultilineEditbox& o, const Image* button_background)
+   : scrollbar(&o, o.get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, o.get_h(), button_background),
      cursor_pos(0),
      maxbytes(std::min(g_gr->max_texture_size() / UI_FONT_SIZE_SMALL, 0xffff)),
      ww_valid(false),

=== modified file 'src/ui_basic/multilineeditbox.h'
--- src/ui_basic/multilineeditbox.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/multilineeditbox.h	2016-10-30 09:05:12 +0000
@@ -36,13 +36,15 @@
  * @ref Editbox and @ref MultilineTextarea
  */
 struct MultilineEditbox : public Panel {
-	MultilineEditbox(Panel*,
-	                 int32_t x,
-	                 int32_t y,
-	                 uint32_t w,
-	                 uint32_t h,
-	                 const std::string& text,
-	                 const Image* background = g_gr->images().get("images/ui_basic/but2.png"));
+	MultilineEditbox(
+	   Panel*,
+	   int32_t x,
+	   int32_t y,
+	   uint32_t w,
+	   uint32_t h,
+	   const std::string& text,
+	   const Image* background = g_gr->images().get("images/ui_basic/but2.png"),
+	   const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"));
 
 	boost::signals2::signal<void()> changed;
 

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2016-10-16 20:53:06 +0000
+++ src/ui_basic/multilinetextarea.cc	2016-10-30 09:05:12 +0000
@@ -38,13 +38,14 @@
                                      const uint32_t h,
                                      const std::string& text,
                                      const Align align,
+                                     const Image* button_background,
                                      MultilineTextarea::ScrollMode scroll_mode)
    : Panel(parent, x, y, w, h),
      text_(text),
      color_(UI_FONT_CLR_FG),
      force_new_renderer_(false),
      use_old_renderer_(false),
-     scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, false),
+     scrollbar_(this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, button_background, false),
      scrollmode_(scroll_mode) {
 	assert(scrollmode_ == MultilineTextarea::ScrollMode::kNoScrolling || Scrollbar::kSize <= w);
 	set_thinks(false);

=== modified file 'src/ui_basic/multilinetextarea.h'
--- src/ui_basic/multilinetextarea.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/multilinetextarea.h	2016-10-30 09:05:12 +0000
@@ -53,6 +53,7 @@
 	   const uint32_t h,
 	   const std::string& text = std::string(),
 	   const Align = UI::Align::kLeft,
+	   const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
 	   MultilineTextarea::ScrollMode scroll_mode = MultilineTextarea::ScrollMode::kScrollNormal);
 
 	const std::string& get_text() const {

=== modified file 'src/ui_basic/scrollbar.cc'
--- src/ui_basic/scrollbar.cc	2016-10-25 08:11:31 +0000
+++ src/ui_basic/scrollbar.cc	2016-10-30 09:05:12 +0000
@@ -44,6 +44,7 @@
                      int32_t const y,
                      uint32_t const w,
                      uint32_t const h,
+                     const Image* button_background,
                      bool const horiz)
    : Panel(parent, x, y, w, h),
      horizontal_(horiz),
@@ -60,8 +61,7 @@
                                            "images/ui_basic/scrollbar_up.png")),
      pic_plus_(g_gr->images().get(horiz ? "images/ui_basic/scrollbar_right.png" :
                                           "images/ui_basic/scrollbar_down.png")),
-     pic_background_(g_gr->images().get("images/ui_basic/scrollbar_background.png")),
-     pic_buttons_(g_gr->images().get("images/ui_basic/but3.png")) {
+     pic_buttons_(button_background) {
 	set_thinks(true);
 	layout();
 }
@@ -233,7 +233,7 @@
 	set_scrollpos(pos);
 }
 
-void Scrollbar::draw_button(RenderTarget& dst, const Area area, const Rectf& r) {
+void Scrollbar::draw_button(RenderTarget& dst, Area area, const Rectf& r) {
 	dst.tile(r.cast<int>(), pic_buttons_, Vector2i(get_x(), get_y()));
 
 	// Draw the picture
@@ -285,23 +285,33 @@
 	}
 }
 
-void Scrollbar::draw_area(RenderTarget& dst, const Area area, const Rectf& r) {
-	dst.tile(r.cast<int>(), pic_background_, Vector2i(get_x(), get_y()) + r.origin().cast<int>());
-
-	if (area == pressed_)
-		dst.brighten_rect(r, BUTTON_EDGE_BRIGHT_FACTOR);
+void Scrollbar::draw_area(RenderTarget& dst, Area area, const Rectf& r) {
+	//  background
+	dst.brighten_rect(r, area == pressed_ ? 2 * MOUSE_OVER_BRIGHT_FACTOR : MOUSE_OVER_BRIGHT_FACTOR);
+	if (horizontal_) {
+		//  top edge
+		dst.brighten_rect(Rectf(r.x, r.y, r.w - 1.f, 1.f), -BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.x, r.y + 1.f, r.w - 2.f, 1.f), -BUTTON_EDGE_BRIGHT_FACTOR);
+		//  bottom edge
+		dst.brighten_rect(Rectf(r.x, r.h - 2.f, r.w, 2.f), BUTTON_EDGE_BRIGHT_FACTOR);
+	} else {
+		//  right edge
+		dst.brighten_rect(Rectf(r.w - 2.f, r.y, 2.f, r.h), BUTTON_EDGE_BRIGHT_FACTOR);
+		//  left edge
+		dst.brighten_rect(Rectf(r.x, r.y, 1.f, r.h - 1.f), -BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.x + 1.f, r.y, 1.f, r.h - 2.f), -BUTTON_EDGE_BRIGHT_FACTOR);
+	}
 }
 
 /**
  * Draw the scrollbar.
 */
 void Scrollbar::draw(RenderTarget& dst) {
-	uint32_t knobpos = get_knob_pos();
-	uint32_t knobsize = get_knob_size();
-
 	if (!is_enabled()) {
 		return;  // Don't draw a scrollbar that doesn't do anything
 	}
+	uint32_t knobpos = get_knob_pos();
+	uint32_t knobsize = get_knob_size();
 
 	if (horizontal_) {
 		if ((2 * buttonsize_ + knobsize) > static_cast<uint32_t>(get_w())) {

=== modified file 'src/ui_basic/scrollbar.h'
--- src/ui_basic/scrollbar.h	2016-10-16 20:35:47 +0000
+++ src/ui_basic/scrollbar.h	2016-10-30 09:05:12 +0000
@@ -23,6 +23,7 @@
 #include <boost/signals2.hpp>
 
 #include "base/rect.h"
+#include "graphic/graphic.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -37,7 +38,13 @@
 	static constexpr int kSize = 24;
 
 public:
-	Scrollbar(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool horiz);
+	Scrollbar(Panel* parent,
+	          int32_t x,
+	          int32_t y,
+	          uint32_t w,
+	          uint32_t h,
+	          const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	          bool horiz = false);
 
 	boost::signals2::signal<void(int32_t)> moved;
 
@@ -76,7 +83,7 @@
 	void action(Area area);
 
 	void draw_button(RenderTarget&, Area, const Rectf&);
-	void draw_area(RenderTarget&, Area, const Rectf&);
+	void draw_area(RenderTarget& dst, Area area, const Rectf& r);
 	void draw(RenderTarget&) override;
 	void think() override;
 
@@ -100,7 +107,6 @@
 
 	const Image* pic_minus_;  ///< left/up
 	const Image* pic_plus_;   ///< right/down
-	const Image* pic_background_;
 	const Image* pic_buttons_;
 };
 }

=== modified file 'src/ui_basic/spinbox.cc'
--- src/ui_basic/spinbox.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/spinbox.cc	2016-10-30 09:05:12 +0000
@@ -84,7 +84,7 @@
                  int32_t const maxval,
                  const std::string& label_text,
                  const SpinBox::Units& unit,
-                 const Image* background,
+                 const Image* button_background,
                  SpinBox::Type type,
                  int32_t step_size,
                  int32_t big_step_size)
@@ -98,7 +98,7 @@
 	}
 	sbi_->value = startval;
 	sbi_->unit = unit;
-	sbi_->background = background;
+	sbi_->background = button_background;
 
 	bool is_big = type_ == SpinBox::Type::kBig;
 
@@ -126,9 +126,9 @@
 
 	box_ = new UI::Box(this, 0, 0, UI::Box::Horizontal, actual_w, texth, padding);
 
-	UI::MultilineTextarea* label =
-	   new UI::MultilineTextarea(box_, 0, 0, w - unit_w - no_padding * padding, texth, label_text,
-	                             UI::Align::kLeft, UI::MultilineTextarea::ScrollMode::kNoScrolling);
+	UI::MultilineTextarea* label = new UI::MultilineTextarea(
+	   box_, 0, 0, w - unit_w - no_padding * padding, texth, label_text, UI::Align::kLeft,
+	   button_background, UI::MultilineTextarea::ScrollMode::kNoScrolling);
 	box_->add(label, UI::Align::kHCenter);
 
 	sbi_->text = new UI::Textarea(box_, "", UI::Align::kCenter);

=== modified file 'src/ui_basic/spinbox.h'
--- src/ui_basic/spinbox.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/spinbox.h	2016-10-30 09:05:12 +0000
@@ -58,7 +58,7 @@
 	        int32_t maxval,
 	        const std::string& label_text = std::string(),
 	        const Units& unit = Units::kNone,
-	        const Image* buttonbackground = g_gr->images().get("images/ui_basic/but3.png"),
+	        const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
 	        SpinBox::Type = SpinBox::Type::kSmall,
 	        // The amount by which units are increased/decreased for small and big steps when a
 	        // button is pressed.

=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc	2016-10-24 14:04:00 +0000
+++ src/ui_basic/table.cc	2016-10-30 09:05:12 +0000
@@ -44,8 +44,13 @@
  *       w       dimensions, in pixels, of the Table
  *       h
 */
-Table<void*>::Table(
-   Panel* const parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const bool descending)
+Table<void*>::Table(Panel* const parent,
+                    int32_t x,
+                    int32_t y,
+                    uint32_t w,
+                    uint32_t h,
+                    const Image* button_background,
+                    const bool descending)
    : Panel(parent, x, y, w, h),
      total_width_(0),
      headerheight_(
@@ -53,15 +58,28 @@
         4),
      lineheight_(
         UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height()),
+     button_background_(button_background),
      scrollbar_(nullptr),
+     scrollbar_filler_button_(
+        new Button(this, "", 0, 0, Scrollbar::kSize, headerheight_, button_background, "")),
      scrollpos_(0),
      selection_(no_selection_index()),
      last_click_time_(-10000),
      last_selection_(no_selection_index()),
      sort_column_(0),
-     sort_descending_(descending) {
+     sort_descending_(descending),
+     flexible_column_(std::numeric_limits<size_t>::max()) {
 	set_thinks(false);
 	set_can_focus(true);
+	scrollbar_filler_button_->set_visible(false);
+	scrollbar_ =
+	   new Scrollbar(get_parent(), get_x() + get_w() - Scrollbar::kSize, get_y() + headerheight_,
+	                 Scrollbar::kSize, get_h() - headerheight_, button_background);
+	scrollbar_->moved.connect(boost::bind(&Table::set_scrollpos, this, _1));
+	scrollbar_->set_steps(1);
+	scrollbar_->set_singlestepsize(lineheight_);
+	scrollbar_->set_pagesize(get_h() - lineheight_);
+	scrollbar_filler_button_->set_enabled(false);
 }
 
 /**
@@ -81,6 +99,7 @@
                               const std::string& title,
                               const std::string& tooltip_string,
                               Align const alignment,
+                              TableColumnType column_type,
                               bool const is_checkbox_column) {
 	//  If there would be existing entries, they would not get the new column.
 	assert(size() == 0);
@@ -97,8 +116,8 @@
 		Column c;
 		// All columns have a title button that is clickable for sorting.
 		// The title text can be empty.
-		c.btn = new Button(this, title, complete_width, 0, width, headerheight_,
-		                   g_gr->images().get("images/ui_basic/but3.png"), title, tooltip_string);
+		c.btn = new Button(this, title, complete_width, 0, width, headerheight_, button_background_,
+		                   title, tooltip_string);
 		c.btn->sigclicked.connect(
 		   boost::bind(&Table::header_button_clicked, boost::ref(*this), columns_.size()));
 		c.width = width;
@@ -114,16 +133,12 @@
 		}
 
 		columns_.push_back(c);
-	}
-	if (!scrollbar_) {
-		scrollbar_ =
-		   new Scrollbar(get_parent(), get_x() + get_w() - Scrollbar::kSize, get_y() + headerheight_,
-		                 Scrollbar::kSize, get_h() - headerheight_, false);
-		scrollbar_->moved.connect(boost::bind(&Table::set_scrollpos, this, _1));
-		scrollbar_->set_steps(1);
-		scrollbar_->set_singlestepsize(lineheight_);
-		scrollbar_->set_pagesize(get_h() - lineheight_);
-	}
+		if (column_type == TableColumnType::kFlexible) {
+			assert(flexible_column_ == std::numeric_limits<size_t>::max());
+			flexible_column_ = columns_.size() - 1;
+		}
+	}
+	layout();
 }
 
 void Table<void*>::set_column_title(uint8_t const col, const std::string& title) {
@@ -204,6 +219,10 @@
 	last_selection_ = no_selection_index();
 }
 
+uint32_t Table<void*>::get_eff_w() const {
+	return scrollbar_->is_enabled() ? get_w() - scrollbar_->get_w() : get_w();
+}
+
 void Table<void*>::fit_height(uint32_t entries) {
 	if (entries == 0) {
 		entries = size();
@@ -224,7 +243,7 @@
 	uint32_t idx = scrollpos_ / lineheight;
 	int32_t y = 1 + idx * lineheight - scrollpos_ + headerheight_;
 
-	dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
+	dst.brighten_rect(Rectf(0.f, 0.f, get_eff_w(), get_h()), ms_darken_value);
 
 	while (idx < entry_records_.size()) {
 		if (y >= static_cast<int32_t>(get_h()))
@@ -489,6 +508,7 @@
 		select(entry_records_.size() - 1);
 		scrollbar_->set_scrollpos(std::numeric_limits<int32_t>::max());
 	}
+	layout();
 	return result;
 }
 
@@ -523,6 +543,34 @@
 		return columns_[sort_column_].compare(a, b);
 }
 
+void Table<void*>::layout() {
+	// If we have a flexible column, adjust the column sizes.
+	if (flexible_column_ != std::numeric_limits<size_t>::max()) {
+		int all_columns_width = scrollbar_->is_enabled() ? scrollbar_->get_w() : 0;
+		for (const auto& column : columns_) {
+			all_columns_width += column.width;
+		}
+		if (all_columns_width != get_w()) {
+			Column& column = columns_.at(flexible_column_);
+			column.width = column.width + get_w() - all_columns_width;
+			column.btn->set_size(column.width, column.btn->get_h());
+			int offset = 0;
+			for (const auto& col : columns_) {
+				col.btn->set_pos(Vector2i(offset, col.btn->get_y()));
+				offset = col.btn->get_x() + col.btn->get_w();
+			}
+			if (scrollbar_->is_enabled()) {
+				const UI::Button* last_column_btn = columns_.back().btn;
+				scrollbar_filler_button_->set_pos(
+				   Vector2i(last_column_btn->get_x() + last_column_btn->get_w(), 0));
+				scrollbar_filler_button_->set_visible(true);
+			} else {
+				scrollbar_filler_button_->set_visible(false);
+			}
+		}
+	}
+}
+
 /**
  * Sort the table alphabetically. Make sure that the current selection stays
  * valid (though it might scroll out of visibility).

=== modified file 'src/ui_basic/table.h'
--- src/ui_basic/table.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/table.h	2016-10-30 09:05:12 +0000
@@ -28,12 +28,15 @@
 
 #include "graphic/align.h"
 #include "graphic/color.h"
+#include "graphic/graphic.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
 struct Scrollbar;
 struct Button;
 
+enum class TableColumnType { kFixed, kFlexible };
+
 /** A table with columns and lines.
  *
  * The entries can be sorted by columns by
@@ -48,7 +51,13 @@
 public:
 	struct EntryRecord {};
 
-	Table(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool descending = false);
+	Table(Panel* parent,
+	      int32_t x,
+	      int32_t y,
+	      uint32_t w,
+	      uint32_t h,
+	      const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	      bool descending = false);
 	~Table();
 
 	boost::signals2::signal<void(uint32_t)> selected;
@@ -59,6 +68,7 @@
 	                const std::string& title = std::string(),
 	                const std::string& tooltip = std::string(),
 	                Align = UI::Align::kLeft,
+	                TableColumnType column_type = TableColumnType::kFixed,
 	                bool is_checkbox_column = false);
 
 	void set_column_title(uint8_t col, const std::string& title);
@@ -157,7 +167,13 @@
 	 */
 	using CompareFn = boost::function<bool(uint32_t, uint32_t)>;
 
-	Table(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool descending = false);
+	Table(Panel* parent,
+	      int32_t x,
+	      int32_t y,
+	      uint32_t w,
+	      uint32_t h,
+	      const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	      bool descending = false);
 	~Table();
 
 	boost::signals2::signal<void(uint32_t)> selected;
@@ -167,6 +183,7 @@
 	                const std::string& title = std::string(),
 	                const std::string& tooltip = std::string(),
 	                Align = UI::Align::kLeft,
+	                TableColumnType column_type = TableColumnType::kFixed,
 	                bool is_checkbox_column = false);
 
 	void set_column_title(uint8_t col, const std::string& title);
@@ -245,9 +262,7 @@
 	uint32_t get_lineheight() const {
 		return lineheight_ + 2;
 	}
-	uint32_t get_eff_w() const {
-		return get_w();
-	}
+	uint32_t get_eff_w() const;
 
 	/// Adjust the desired size to fit the height needed for the number of entries.
 	/// If entries == 0, the current entries are used.
@@ -264,9 +279,8 @@
 	bool default_compare_checkbox(uint32_t column, uint32_t a, uint32_t b);
 	bool default_compare_string(uint32_t column, uint32_t a, uint32_t b);
 	bool sort_helper(uint32_t a, uint32_t b);
+	void layout() override;
 
-	struct Column;
-	using Columns = std::vector<Column>;
 	struct Column {
 		Button* btn;
 		uint32_t width;
@@ -274,6 +288,7 @@
 		bool is_checkbox_column;
 		CompareFn compare;
 	};
+	using Columns = std::vector<Column>;
 
 	static const int32_t ms_darken_value = -20;
 
@@ -281,13 +296,18 @@
 	uint32_t total_width_;
 	uint32_t headerheight_;
 	int32_t lineheight_;
+	const Image* button_background_;
 	Scrollbar* scrollbar_;
+	// A disabled button that will fill the space above the scroll bar
+	UI::Button* scrollbar_filler_button_;
 	int32_t scrollpos_;  //  in pixels
 	uint32_t selection_;
 	uint32_t last_click_time_;
 	uint32_t last_selection_;  // for double clicks
 	Columns::size_type sort_column_;
 	bool sort_descending_;
+	// This column will grow/shrink depending on the scrollbar being present
+	size_t flexible_column_;
 
 	void header_button_clicked(Columns::size_type);
 	using EntryRecordVector = std::vector<EntryRecord*>;
@@ -298,8 +318,14 @@
 template <typename Entry> class Table<const Entry* const> : public Table<void*> {
 public:
 	using Base = Table<void*>;
-	Table(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const bool descending = false)
-	   : Base(parent, x, y, w, h, descending) {
+	Table(Panel* parent,
+	      int32_t x,
+	      int32_t y,
+	      uint32_t w,
+	      uint32_t h,
+	      const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	      const bool descending = false)
+	   : Base(parent, x, y, w, h, button_background, descending) {
 	}
 
 	EntryRecord& add(Entry const* const entry = 0, bool const select_this = false) {
@@ -404,8 +430,14 @@
 template <> class Table<uintptr_t> : public Table<void*> {
 public:
 	using Base = Table<void*>;
-	Table(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const bool descending = false)
-	   : Base(parent, x, y, w, h, descending) {
+	Table(Panel* parent,
+	      int32_t x,
+	      int32_t y,
+	      uint32_t w,
+	      uint32_t h,
+	      const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	      const bool descending = false)
+	   : Base(parent, x, y, w, h, button_background, descending) {
 	}
 
 	EntryRecord& add(uintptr_t const entry, bool const select_this = false) {
@@ -430,8 +462,14 @@
 template <> class Table<uintptr_t const> : public Table<uintptr_t> {
 public:
 	using Base = Table<uintptr_t>;
-	Table(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const bool descending = false)
-	   : Base(parent, x, y, w, h, descending) {
+	Table(Panel* parent,
+	      int32_t x,
+	      int32_t y,
+	      uint32_t w,
+	      uint32_t h,
+	      const Image* button_background = g_gr->images().get("images/ui_basic/but3.png"),
+	      const bool descending = false)
+	   : Base(parent, x, y, w, h, button_background, descending) {
 	}
 };
 }

=== modified file 'src/ui_fsmenu/campaign_select.cc'
--- src/ui_fsmenu/campaign_select.cc	2016-09-26 07:32:54 +0000
+++ src/ui_fsmenu/campaign_select.cc	2016-10-30 09:05:12 +0000
@@ -42,7 +42,7 @@
  */
 FullscreenMenuCampaignSelect::FullscreenMenuCampaignSelect()
    : FullscreenMenuLoadMapOrGame(),
-     table_(this, tablex_, tabley_, tablew_, tableh_, false),
+     table_(this, tablex_, tabley_, tablew_, tableh_),
 
      // Main Title
      title_(this, get_w() / 2, tabley_ / 3, _("Choose a campaign"), UI::Align::kHCenter),
@@ -106,7 +106,7 @@
 	table_.add_column(45, _("Diff."), _("Difficulty"), UI::Align::kLeft);
 	table_.add_column(100, _("Tribe"), _("Tribe Name"), UI::Align::kLeft);
 	table_.add_column(
-	   table_.get_w() - 100 - 45, _("Campaign Name"), _("Campaign Name"), UI::Align::kLeft);
+	   0, _("Campaign Name"), _("Campaign Name"), UI::Align::kLeft, UI::TableColumnType::kFlexible);
 	table_.set_column_compare(
 	   0, boost::bind(&FullscreenMenuCampaignSelect::compare_difficulty, this, _1, _2));
 	table_.set_sort_column(0);
@@ -269,7 +269,7 @@
  */
 FullscreenMenuCampaignMapSelect::FullscreenMenuCampaignMapSelect(bool is_tutorial)
    : FullscreenMenuLoadMapOrGame(),
-     table_(this, tablex_, tabley_, tablew_, tableh_, false),
+     table_(this, tablex_, tabley_, tablew_, tableh_),
 
      // Main title
      title_(this,
@@ -344,7 +344,8 @@
 
 	/** TRANSLATORS: Campaign scenario number table header */
 	table_.add_column(35, _("#"), number_tooltip, UI::Align::kLeft);
-	table_.add_column(table_.get_w() - 35, name_tooltip, name_tooltip, UI::Align::kLeft);
+	table_.add_column(
+	   0, name_tooltip, name_tooltip, UI::Align::kLeft, UI::TableColumnType::kFlexible);
 	table_.set_sort_column(0);
 
 	table_.focus();

=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc	2016-09-25 12:24:46 +0000
+++ src/ui_fsmenu/internet_lobby.cc	2016-10-30 09:05:12 +0000
@@ -135,7 +135,8 @@
 	/** TRANSLATORS: Player Name */
 	clientsonline_list_.add_column((lisw_ - 22) * 3 / 8, pgettext("player", "Name"));
 	clientsonline_list_.add_column((lisw_ - 22) * 2 / 8, _("Version"));
-	clientsonline_list_.add_column((lisw_ - 22) * 3 / 8, _("Game"));
+	clientsonline_list_.add_column(
+	   0, _("Game"), "", UI::Align::kLeft, UI::TableColumnType::kFlexible);
 	clientsonline_list_.set_column_compare(
 	   0, boost::bind(&FullscreenMenuInternetLobby::compare_clienttype, this, _1, _2));
 	clientsonline_list_.double_clicked.connect(

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2016-10-24 14:04:00 +0000
+++ src/ui_fsmenu/loadgame.cc	2016-10-30 09:05:12 +0000
@@ -85,7 +85,13 @@
                                                GameController* gc,
                                                bool is_replay)
    : FullscreenMenuLoadMapOrGame(),
-     table_(this, tablex_, tabley_, tablew_, tableh_, true),
+     table_(this,
+            tablex_,
+            tabley_,
+            tablew_,
+            tableh_,
+            g_gr->images().get("images/ui_basic/but3.png"),
+            true),
 
      is_replay_(is_replay),
      // Main title
@@ -189,7 +195,6 @@
 	delete_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLoadGame::clicked_delete, boost::ref(*this)));
 	table_.add_column(130, _("Save Date"), _("The date this game was saved"), UI::Align::kLeft);
-	int used_width = 130;
 	if (is_replay_ || settings_->settings().multiplayer) {
 		std::vector<std::string> modes;
 		if (is_replay_) {
@@ -218,12 +223,11 @@
 		   /** TRANSLATORS: A tooltip will explain if you need to use an abbreviation. */
 		   _("Mode"), (boost::format("%s %s") % mode_tooltip_1 % mode_tooltip_2).str(),
 		   UI::Align::kLeft);
-		used_width += 65;
 	}
-	table_.add_column(table_.get_w() - used_width, _("Description"),
+	table_.add_column(0, _("Description"),
 	                  _("The filename that the game was saved under followed by the map’s name, "
 	                    "or the map’s name followed by the last objective achieved."),
-	                  UI::Align::kLeft);
+	                  UI::Align::kLeft, UI::TableColumnType::kFlexible);
 	table_.set_column_compare(
 	   0, boost::bind(&FullscreenMenuLoadGame::compare_date_descending, this, _1, _2));
 	table_.selected.connect(boost::bind(&FullscreenMenuLoadGame::entry_selected, this));

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2016-10-28 18:04:11 +0000
+++ src/ui_fsmenu/options.cc	2016-10-30 09:05:12 +0000
@@ -257,7 +257,6 @@
      /** TRANSLATORS: A watchwindow is a window where you keep watching an object or a map region,*/
      /** TRANSLATORS: and it also lets you jump to it on the map. */
      single_watchwin_(&box_game_, Vector2i(0, 0), _("Use single watchwindow mode")),
-
      os_(opt) {
 	// Set up UI Elements
 	title_.set_fontsize(UI_FONT_SIZE_BIG);

=== modified file 'src/wui/game_debug_ui.cc'
--- src/wui/game_debug_ui.cc	2016-09-07 09:30:49 +0000
+++ src/wui/game_debug_ui.cc	2016-10-30 09:05:12 +0000
@@ -62,8 +62,15 @@
    : UI::Panel(&parent, 0, 0, 350, 200),
      egbase_(egbase),
      object_(&obj),
-     log_(
-        this, 0, 0, 350, 200, "", UI::Align::kLeft, UI::MultilineTextarea::ScrollMode::kScrollLog) {
+     log_(this,
+          0,
+          0,
+          350,
+          200,
+          "",
+          UI::Align::kLeft,
+          g_gr->images().get("images/ui_basic/but1.png"),
+          UI::MultilineTextarea::ScrollMode::kScrollLog) {
 	obj.set_logsink(this);
 }
 

=== modified file 'src/wui/game_main_menu_save_game.cc'
--- src/wui/game_main_menu_save_game.cc	2016-09-25 12:24:46 +0000
+++ src/wui/game_main_menu_save_game.cc	2016-10-30 09:05:12 +0000
@@ -66,7 +66,12 @@
               0,
               2,
               g_gr->images().get("images/ui_basic/but1.png")),
-     ls_(this, HSPACING, VSPACING, LIST_WIDTH, LIST_HEIGHT - editbox_.get_h()),
+     ls_(this,
+         HSPACING,
+         VSPACING,
+         LIST_WIDTH,
+         LIST_HEIGHT - editbox_.get_h(),
+         g_gr->images().get("images/ui_basic/but1.png")),
      name_label_(this, DESCRIPTION_X, 5, 0, 20, _("Map Name:"), UI::Align::kCenterLeft),
      mapname_(this, DESCRIPTION_X, 20, 0, 20, " ", UI::Align::kCenterLeft),
      gametime_label_(this, DESCRIPTION_X, 45, 0, 20, _("Game Time:"), UI::Align::kCenterLeft),

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2016-10-24 14:04:00 +0000
+++ src/wui/game_message_menu.cc	2016-10-30 09:05:12 +0000
@@ -56,15 +56,17 @@
                   get_inner_h() - kMessageBodyY - 2 * kPadding - kButtonSize,
                   "",
                   UI::Align::kLeft,
+                  g_gr->images().get("images/ui_basic/but1.png"),
                   UI::MultilineTextarea::ScrollMode::kScrollNormalForced),
      mode(Inbox) {
 
-	list = new UI::Table<uintptr_t>(
-	   this, kPadding, kButtonSize + 2 * kPadding, kWindowWidth - 2 * kPadding, kTableHeight);
+	list = new UI::Table<uintptr_t>(this, kPadding, kButtonSize + 2 * kPadding,
+	                                kWindowWidth - 2 * kPadding, kTableHeight,
+	                                g_gr->images().get("images/ui_basic/but1.png"));
 	list->selected.connect(boost::bind(&GameMessageMenu::selected, this, _1));
 	list->double_clicked.connect(boost::bind(&GameMessageMenu::double_clicked, this, _1));
 	list->add_column(kWindowWidth - 2 * kPadding - 60 - 60 - 75, _("Title"));
-	list->add_column(60, pgettext("message", "Type"), "", UI::Align::kHCenter, true);
+	list->add_column(60, pgettext("message", "Type"), "", UI::Align::kHCenter);
 	list->add_column(60, _("Status"), "", UI::Align::kHCenter);
 	/** TRANSLATORS: We have very little space here. You can also translate this as "Time" or "Time
 	 * Sent" */

=== modified file 'src/wui/game_objectives_menu.cc'
--- src/wui/game_objectives_menu.cc	2016-09-29 08:46:35 +0000
+++ src/wui/game_objectives_menu.cc	2016-10-30 09:05:12 +0000
@@ -48,6 +48,7 @@
                    FULL_OBJECTIVE_TEXT,
                    "",
                    UI::Align::kLeft,
+                   g_gr->images().get("images/ui_basic/but1.png"),
                    UI::MultilineTextarea::ScrollMode::kScrollNormalForced) {
 	list.selected.connect(boost::bind(&GameObjectivesMenu::selected, this, _1));
 	if (get_usedefaultpos())

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2016-10-20 19:29:28 +0000
+++ src/wui/game_summary.cc	2016-10-30 09:05:12 +0000
@@ -97,7 +97,7 @@
 	players_table_->add_column(150, _("Player"));
 	players_table_->add_column(80, _("Team"), "", UI::Align::kHCenter);
 	players_table_->add_column(100, _("Status"), "", UI::Align::kHCenter);
-	players_table_->add_column(100, _("Time"));
+	players_table_->add_column(0, _("Time"), "", UI::Align::kRight, UI::TableColumnType::kFlexible);
 
 	// Prepare Elements
 	title_area_->set_fontsize(UI_FONT_SIZE_BIG);

=== modified file 'src/wui/gamechatpanel.cc'
--- src/wui/gamechatpanel.cc	2016-08-04 15:49:05 +0000
+++ src/wui/gamechatpanel.cc	2016-10-30 09:05:12 +0000
@@ -42,6 +42,7 @@
              h - 25,
              "",
              UI::Align::kLeft,
+             g_gr->images().get("images/ui_basic/but1.png"),
              UI::MultilineTextarea::ScrollMode::kScrollLogForced),
      editbox(this, 0, h - 20, w, 20, 2),
      chat_message_counter(std::numeric_limits<uint32_t>::max()) {

=== modified file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	2016-10-16 09:31:42 +0000
+++ src/wui/mapdetails.cc	2016-10-30 09:05:12 +0000
@@ -82,6 +82,7 @@
                  20,
                  "",
                  UI::Align::kLeft,
+                 g_gr->images().get("images/ui_basic/but3.png"),
                  UI::MultilineTextarea::ScrollMode::kNoScrolling),
      descr_(&main_box_, 0, 0, max_w, 20, ""),
      suggested_teams_box_(

=== modified file 'src/wui/maptable.cc'
--- src/wui/maptable.cc	2016-08-04 15:49:05 +0000
+++ src/wui/maptable.cc	2016-10-30 09:05:12 +0000
@@ -28,12 +28,13 @@
 
 MapTable::MapTable(
    UI::Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const bool descending)
-   : UI::Table<uintptr_t>(parent, x, y, w, h, descending) {
+   : UI::Table<uintptr_t>(
+        parent, x, y, w, h, g_gr->images().get("images/ui_basic/but3.png"), descending) {
 
 	/** TRANSLATORS: Column title for number of players in map list */
 	add_column(35, _("Pl."), _("Number of players"), UI::Align::kHCenter);
-	add_column(
-	   get_w() - 35 - 115, _("Filename"), _("The name of the map or scenario"), UI::Align::kLeft);
+	add_column(0, _("Filename"), _("The name of the map or scenario"), UI::Align::kLeft,
+	           UI::TableColumnType::kFlexible);
 	add_column(115, _("Size"), _("The size of the map (Width x Height)"), UI::Align::kLeft);
 	set_sort_column(0);
 }


Follow ups