SugarPaletteWindowWidget: add border rules - SL #4295

This were in the GTK2 theme the palette xthickness and ythickness.

Signed-off-by: Manuel Quiñones <6f5069c5b6be23302a13accec56587944be09079@laptop.org>
Acked-by: Simon Schampijer <088e16a1019277b15d58faf0541e11910eb756f6@laptop.org>

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68

# Radio size used to be:
#
# radio_size = my_floor(subcell_size + bullet_size + line_width)
#
# But a screenshot shows that the graphic was actually rendered at 26px
# so the SVG displays at the correct size.
# FIXME this only works for 100, has not been tested in 75 resolution
radio_size = 26

# FIXME this should be calculated with the radio size and the bullet
# size:
scale_trough_margin = 8

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

}

* {
    -sugar-focus-line: @white;

    /* A lot of these will probably need to be changed, but this has to
       be done when the exact sizes are known */
    -GtkWidget-interior-focus: 0;

    /* we have to disable focus border for GtkTreeView, see #1261 */
    -GtkTreeView-interior-focus: 1;
    -GtkTreeView-focus-line-width: 0;

    -GtkTextView-interior-focus: 1;

    -GtkWidget-focus-line-width: 0;  /* Prevents some drawing glitches */
    -GtkEntry-focus-line-width: 0;
    -GtkScale-focus-line-width: 0;
    -GtkWidget-focus-padding: 0;
    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    /* We fake the default border in the theme */
    -GtkButton-default-border: 0 0 0 0;
    -GtkButton-default-outside-border: 0 0 0 0;
    -GtkButton-image-spacing: $subcell_size;

    -GtkEntry-progress-border: $thickness $thickness $thickness $thickness;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);
    -GtkToolbar-shadow-type: none;

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkButtonBox-child-min-height: $(3*subcell_size);
    -GtkButtonBox-child-min-width: $(3*subcell_size);
    -GtkButtonBox-child-internal-pad-x: 0;
    -GtkButtonBox-child-internal-pad-y: 0;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:insensitive {
    color: @button_grey;
}

/* Backgrounds and windows */

GtkWindow {
    background-color: @panel_grey;
    color: @black;
}

GtkDialog {
    background-color: @black;
    color: @white;
}

SugarIntroWindow {
    background-color: @white;
}

SugarIntroWindow {
    color: @black;
}

GtkLabel, GtkLabel:insensitive {
    background-color: transparent;
}

/* Buttons */

.button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    /* It would be nicer to just set the inner-border, but that does not work
       for combo boxes ... The combobox ignores it, so set it to 0px
       See http://bugzilla.gnome.org/show_bug.cgi?id=485762 */

    -GtkButton-inner-border: 0 0 0 0;
    padding: $(border)px $(border)px $(border)px $(border)px;

    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background-color: @button_grey;
    color: @white;
}

.button:focused {
    border-color: @white;
}

.button:active {
    background-color: @white;
}

.button:insensitive {
    background-color: transparent;
}

.button:active:focused {
    color: @black;
    border-color: @button_grey;
}

/* Spin buttons */

.spinbutton.button {
    border-radius: 0px;
    border-width: 0px;
    border-style: solid;
    background-color: @button_grey;
}

.spinbutton.button:last-child {
    border-radius: 0px $(2*subcell_size)px $(2*subcell_size)px 0px;
    border-width: 0px 0px 0px $(thickness)px;
    border-style: solid;
    border-color: @selection_grey;
}

.spinbutton.button:active {
    background-color: @black;
}

.spinbutton.button:insensitive {
    background-color: @selection_grey;
}

/* Toggle buttons */

GtkToggleButton.button:active {
    background-color: @white;
    color: @black;
}

/* Entries and views */

.view {
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background-color: @white;
}

GtkTreeView {
    background-color: @button_grey;
}

GtkTreeView row:nth-child(even) {
    background-color: @row_even;
}
GtkTreeView row:nth-child(odd) {
    background-color: @row_odd;
}

.entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background-color: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

.entry.progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background-color: @selection_grey;
}

.entry:focused {
    background-color: @white;
}

.toolbar .entry:focused {
    border-color: @white;
}

.entry:insensitive, .view:insensitive {
    background-color: @button_grey;
}

.entry:insensitive {
    border-color: @button_grey;
}

.view:selected {
    background-color: @panel_grey;
    color: @black;
}

.entry:selected,
.entry:selected:focused,
.view:selected:focused {
    background-color: @selection_grey;
    color: @black;
}

.entry:selected,
.entry:selected:focused {
    border-color: @selection_grey;
}

/* Frames */

GtkScrolledWindow.frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

GtkFrame.frame.journal-preview-box {
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

/* Combo boxes */

GtkComboBox {
    color: @white;
}

GtkComboBox .separator {
    /* Remove the separator turning it transparent */
    color: alpha(@theme_base_color, 0.0);
}

/* Notebooks */

.notebook {
    background-color: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
}

.notebook tab {
    background-color: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
.notebook tab GtkLabel {
    color: @white;
    padding: $(subcell_size)px 0;
}

.notebook tab .button GtkLabel {
    color: @black;
}

.notebook tab:active {
    background-color: @toolbar_grey;
}

.notebook tab .button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseTabPage {
    background-color: @black;
}

BrowseSearchWindow .view {
    background-color: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

SugarSectionView {
    background-color: @white;
    color: @black;
}

SugarSectionView *:insensitive {
    background-color: @white;
}

/* Alert */

SugarAlert {
    background-color: @black;
    color: @white;
}

SugarAlert *:insensitive {
    background-color: @black;
}

.button SugarTimeoutIcon GtkLabel,
.button SugarTimeoutIcon GtkLabel:prelight {
    background-color: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

.button SugarTimeoutIcon GtkLabel:active {
    background-color: @toolbar_grey;
    color: @white;
}

/* Tray */

SugarHTray, SugarVTray {
    background-color: @toolbar_grey;
}

SugarHTray * , SugarVTray * { background-color: @toolbar_grey;}

/* Menus and palettes */

SugarPaletteWindowWidget {
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    background-color: @black;
    color: @white;
}

SugarPaletteWindowWidget .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background-color: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background-color: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:insensitive {
    background-color: @toolbar_grey;
}

.menu {
    background-color: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    -GtkMenu-horizontal-padding: $thickness;
    -GtkMenu-vertical-padding  : $thickness;
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset : 0;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px 0px $(subcell_size)px 0px;
    border-width: 2px;
    border-color: @button_grey;
    border-style: solid;
}

.menu :active {
    background-color: @button_grey;
}

.menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

.menuitem:prelight {
    background-color: @button_grey;
}

.menuitem.separator {
    padding: $(subcell_size)px 0px;
}

SugarPaletteHeader.menuitem {
    padding: 0px $((subcell_size * 3 - font_height) / 2)px;
}

SugarPaletteHeader.menuitem:prelight {
    background-color: @black;
}

SugarPaletteHeaderSeparator.menuitem.separator {
    padding: 0px 0px $(subcell_size)px 0px;
}

.tooltip {
    background-color: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

.tooltip * {
    color: @white;
}

/* Scrollbars */

.scrollbar {
    -GtkRange-slider-width: $subcell_size;
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

.scrollbar.trough {
    background-color: @button_grey;
    border-width: 0px;
}

.scrollbar.slider {
    background-color: @white;
    border-radius: $(2*subcell_size)px;
    border-width: 0px;
}

.scrollbar.slider:active {
    background-color: @text_field_grey;
}

/* Progress bars */

/* Scrollbar padding hack? What was that about? */

GtkProgressBar.progressbar {
    background-color: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

GtkProgressBar.trough {
    background-color: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

.toolbar GtkProgressBar.trough,
SugarPaletteWindowWidget GtkProgressBar.trough {
    background-color: @black;
}

/* Separators */

.separator {
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

/* Tool buttons */

.toolbar {
padding: 0px;
background-color: @toolbar_grey;
color: @white;
}

.toolbar .button,
SugarPaletteWindowWidget SugarRadioToolButton .button {
    border-color: transparent;
    border-radius: 0px;
    border-style: none;
}

.toolbar .button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

.toolbar GtkToolButton .button,
.toolbar SugarRadioToolButton *,
SugarPaletteWindowWidget SugarRadioToolButton *,
SugarPaletteWindowWidget GtkToolButton .button {
    background-color: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding)px;
}

.toolbar GtkToolButton .button,
SugarPaletteWindowWidget GtkToolButton .button:prelight {
    padding: $(toolbutton_padding - default_padding)px;
    border-width: $(default_padding)px;
    border-style: solid;
    background-clip: padding-box;
}

.toolbar GtkToolButton .button:prelight,
SugarPaletteWindowWidget GtkToolButton .button:prelight {
    background-color: @black;
}

.toolbar SugarRadioToolButton *:active,
SugarPaletteWindowWidget SugarRadioToolButton *:active {
    background-color: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

SugarPaletteWindowWidget GtkToolButton .button:active {
    background-color: @transparent;
}

.toolbar GtkToolButton .button:active {
    background-color: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

SugarPaletteWindowWidget GtkScrolledWindow * {
    background-color: @black;
}

.toolbar GtkComboBox .button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

.scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

/* We have to override the color of the scale, otherwise the slider
   background image is invisible or not set for this palettes.
   Upstream bug: https://bugzilla.gnome.org/show_bug.cgi?id=686703 */
SugarPaletteWindowWidget .scale {
    color: transparent;
}

.scale.trough {
    background-color: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

.scale.trough.vertical {
    margin: 0 $(scale_trough_margin)px;
}

.scale.trough:focused {
    border-color: @white;
}

.scale.trough.top,
.scale.trough.left {
    background-color: @white;
}

.scale.trough.top:focused,
.scale.trough.left:focused {
    border-color: @selection_grey;
}

.scale.trough {
    border-radius: 0px $(2*subcell_size)px $(2*subcell_size)px 0px;
}

.scale.trough.vertical {
    border-radius: 0px 0px $(2*subcell_size)px $(2*subcell_size)px;
}

.scale.trough.top {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0px 0px;
}

.scale.trough.left {
    border-radius: $(2*subcell_size)px 0px 0px $(2*subcell_size)px;
}

.scale.slider,
.scale.slider:active {
    background-color: transparent;
}

.scale.slider {
    background-image: url("assets/scale-slider.svg");
}

.scale.slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

GtkCheckButton:prelight {
    background-color: alpha(@theme_base_color, 0.0);
}

.toolbar GtkCheckButton,
SugarPaletteWindowWidget GtkCheckButton {
    color: @theme_base_color;
}

.radio,
.radio row:selected,
.radio row:selected:focused {
    background-image: url("assets/radio.svg");
    background-color: alpha(@theme_base_color, 0.0);
}

.radio:selected,
.radio:selected row:selected,
.radio:selected row:selected:focused {
    background-image: url("assets/radio-selected.svg");
}

.radio:active,
.radio row:selected:active,
.radio row:selected:focused:active {
    background-image: url("assets/radio-active.svg");
}

.radio:active:selected,
.radio:selected row:selected:active,
.radio:selected row:selected:focused:active {
    background-image: url("assets/radio-active-selected.svg");
}

.check,
.check row:selected,
.check row:selected:focused {
    background-image: url("assets/checkbox-unchecked.svg");
    background-color: alpha(@theme_base_color, 0.0);
}

.check:selected,
.check:selected row:selected,
.check:selected row:selected:focused {
    background-image: url("assets/checkbox-unchecked-selected.svg");
}

.check:active,
.check row:selected:active,
.check row:selected:focused:active {
    background-image: url("assets/checkbox-checked.svg");
}

.check:active:selected,
.check:selected row:selected:active,
.check:selected row:selected:focused:active {
    background-image: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

.toolitem {
    /* arrow in the toolbarbox */
    color: @white;
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

GtkImage {
    background-color: transparent;
}

/* Sugar Frame Window */

SugarFrameWindow {
    background-color: @toolbar_grey;
}

/* Sugar Canvas icon */

SugarCanvasIcon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
}

SugarCanvasIcon:prelight {
    border-color: @zoom_views_prelight;
    background-color: @zoom_views_prelight;
}

SugarCanvasIcon:active {
    border-color: @zoom_views_active;
    background-color: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background-color: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:prelight {
    background-color: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background-color: @zoom_views_active;
}

/* Text cursor handles */

.cursor-handle.top,
.cursor-handle.bottom {
    background-color: transparent;
    box-shadow: none;
    border-style: none;
    border-image: none;
    border-radius: 0px;
    border-width: 0px;
}

.cursor-handle.bottom {
    background-image: url("assets/cursor-handle-bottom.svg");
}

.cursor-handle.top {
    background-image: url("assets/cursor-handle-top.svg");
}

.cursor-handle.insertion-cursor {
    background-image: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background-color: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background-color: @selection_grey;
}

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68

# Radio size used to be:
#
# radio_size = my_floor(subcell_size + bullet_size + line_width)
#
# But a screenshot shows that the graphic was actually rendered at 26px
# so the SVG displays at the correct size.
# FIXME this only works for 100, has not been tested in 75 resolution
radio_size = 26

# FIXME this should be calculated with the radio size and the bullet
# size:
scale_trough_margin = 8

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

}

* {
    -sugar-focus-line: @white;

    /* A lot of these will probably need to be changed, but this has to
       be done when the exact sizes are known */
    -GtkWidget-interior-focus: 0;

    /* we have to disable focus border for GtkTreeView, see #1261 */
    -GtkTreeView-interior-focus: 1;
    -GtkTreeView-focus-line-width: 0;

    -GtkTextView-interior-focus: 1;

    -GtkWidget-focus-line-width: 0;  /* Prevents some drawing glitches */
    -GtkEntry-focus-line-width: 0;
    -GtkScale-focus-line-width: 0;
    -GtkWidget-focus-padding: 0;
    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    /* We fake the default border in the theme */
    -GtkButton-default-border: 0 0 0 0;
    -GtkButton-default-outside-border: 0 0 0 0;
    -GtkButton-image-spacing: $subcell_size;

    -GtkEntry-progress-border: $thickness $thickness $thickness $thickness;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);
    -GtkToolbar-shadow-type: none;

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkButtonBox-child-min-height: $(3*subcell_size);
    -GtkButtonBox-child-min-width: $(3*subcell_size);
    -GtkButtonBox-child-internal-pad-x: 0;
    -GtkButtonBox-child-internal-pad-y: 0;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:insensitive {
    color: @button_grey;
}

/* Backgrounds and windows */

GtkWindow {
    background-color: @panel_grey;
    color: @black;
}

GtkDialog {
    background-color: @black;
    color: @white;
}

SugarIntroWindow {
    background-color: @white;
}

SugarIntroWindow {
    color: @black;
}

GtkLabel, GtkLabel:insensitive {
    background-color: transparent;
}

/* Buttons */

.button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    /* It would be nicer to just set the inner-border, but that does not work
       for combo boxes ... The combobox ignores it, so set it to 0px
       See http://bugzilla.gnome.org/show_bug.cgi?id=485762 */

    -GtkButton-inner-border: 0 0 0 0;
    padding: $(border)px $(border)px $(border)px $(border)px;

    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background-color: @button_grey;
    color: @white;
}

.button:focused {
    border-color: @white;
}

.button:active {
    background-color: @white;
}

.button:insensitive {
    background-color: transparent;
}

.button:active:focused {
    color: @black;
    border-color: @button_grey;
}

/* Spin buttons */

.spinbutton.button {
    border-radius: 0px;
    border-width: 0px;
    border-style: solid;
    background-color: @button_grey;
}

.spinbutton.button:last-child {
    border-radius: 0px $(2*subcell_size)px $(2*subcell_size)px 0px;
    border-width: 0px 0px 0px $(thickness)px;
    border-style: solid;
    border-color: @selection_grey;
}

.spinbutton.button:active {
    background-color: @black;
}

.spinbutton.button:insensitive {
    background-color: @selection_grey;
}

/* Toggle buttons */

GtkToggleButton.button:active {
    background-color: @white;
    color: @black;
}

/* Entries and views */

.view {
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background-color: @white;
}

GtkTreeView {
    background-color: @button_grey;
}

GtkTreeView row:nth-child(even) {
    background-color: @row_even;
}
GtkTreeView row:nth-child(odd) {
    background-color: @row_odd;
}

.entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background-color: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

.entry.progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background-color: @selection_grey;
}

.entry:focused {
    background-color: @white;
}

.toolbar .entry:focused {
    border-color: @white;
}

.entry:insensitive, .view:insensitive {
    background-color: @button_grey;
}

.entry:insensitive {
    border-color: @button_grey;
}

.view:selected {
    background-color: @panel_grey;
    color: @black;
}

.entry:selected,
.entry:selected:focused,
.view:selected:focused {
    background-color: @selection_grey;
    color: @black;
}

.entry:selected,
.entry:selected:focused {
    border-color: @selection_grey;
}

/* Frames */

GtkScrolledWindow.frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

GtkFrame.frame.journal-preview-box {
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

/* Combo boxes */

GtkComboBox {
    color: @white;
}

GtkComboBox .separator {
    /* Remove the separator turning it transparent */
    color: alpha(@theme_base_color, 0.0);
}

/* Notebooks */

.notebook {
    background-color: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
}

.notebook tab {
    background-color: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
.notebook tab GtkLabel {
    color: @white;
    padding: $(subcell_size)px 0;
}

.notebook tab .button GtkLabel {
    color: @black;
}

.notebook tab:active {
    background-color: @toolbar_grey;
}

.notebook tab .button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseTabPage {
    background-color: @black;
}

BrowseSearchWindow .view {
    background-color: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

SugarSectionView {
    background-color: @white;
    color: @black;
}

SugarSectionView *:insensitive {
    background-color: @white;
}

/* Alert */

SugarAlert {
    background-color: @black;
    color: @white;
}

SugarAlert *:insensitive {
    background-color: @black;
}

.button SugarTimeoutIcon GtkLabel,
.button SugarTimeoutIcon GtkLabel:prelight {
    background-color: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

.button SugarTimeoutIcon GtkLabel:active {
    background-color: @toolbar_grey;
    color: @white;
}

/* Tray */

SugarHTray, SugarVTray {
    background-color: @toolbar_grey;
}

SugarHTray * , SugarVTray * { background-color: @toolbar_grey;}

/* Menus and palettes */

SugarPaletteWindowWidget {
    background-color: @black;
    color: @white;
}

SugarPaletteWindowWidget .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background-color: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background-color: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:insensitive {
    background-color: @toolbar_grey;
}

.menu {
    background-color: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    -GtkMenu-horizontal-padding: $thickness;
    -GtkMenu-vertical-padding  : $thickness;
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset : 0;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px 0px $(subcell_size)px 0px;
    border-width: 2px;
    border-color: @button_grey;
    border-style: solid;
}

.menu :active {
    background-color: @button_grey;
}

.menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

.menuitem:prelight {
    background-color: @button_grey;
}

.menuitem.separator {
    padding: $(subcell_size)px 0px;
}

SugarPaletteHeader.menuitem {
    padding: 0px $((subcell_size * 3 - font_height) / 2)px;
}

SugarPaletteHeader.menuitem:prelight {
    background-color: @black;
}

SugarPaletteHeaderSeparator.menuitem.separator {
    padding: 0px 0px $(subcell_size)px 0px;
}

.tooltip {
    background-color: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

.tooltip * {
    color: @white;
}

/* Scrollbars */

.scrollbar {
    -GtkRange-slider-width: $subcell_size;
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

.scrollbar.trough {
    background-color: @button_grey;
    border-width: 0px;
}

.scrollbar.slider {
    background-color: @white;
    border-radius: $(2*subcell_size)px;
    border-width: 0px;
}

.scrollbar.slider:active {
    background-color: @text_field_grey;
}

/* Progress bars */

/* Scrollbar padding hack? What was that about? */

GtkProgressBar.progressbar {
    background-color: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

GtkProgressBar.trough {
    background-color: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

.toolbar GtkProgressBar.trough,
SugarPaletteWindowWidget GtkProgressBar.trough {
    background-color: @black;
}

/* Separators */

.separator {
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

/* Tool buttons */

.toolbar {
padding: 0px;
background-color: @toolbar_grey;
color: @white;
}

.toolbar .button,
SugarPaletteWindowWidget SugarRadioToolButton .button {
    border-color: transparent;
    border-radius: 0px;
    border-style: none;
}

.toolbar .button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

.toolbar GtkToolButton .button,
.toolbar SugarRadioToolButton *,
SugarPaletteWindowWidget SugarRadioToolButton *,
SugarPaletteWindowWidget GtkToolButton .button {
    background-color: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding)px;
}

.toolbar GtkToolButton .button,
SugarPaletteWindowWidget GtkToolButton .button:prelight {
    padding: $(toolbutton_padding - default_padding)px;
    border-width: $(default_padding)px;
    border-style: solid;
    background-clip: padding-box;
}

.toolbar GtkToolButton .button:prelight,
SugarPaletteWindowWidget GtkToolButton .button:prelight {
    background-color: @black;
}

.toolbar SugarRadioToolButton *:active,
SugarPaletteWindowWidget SugarRadioToolButton *:active {
    background-color: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

SugarPaletteWindowWidget GtkToolButton .button:active {
    background-color: @transparent;
}

.toolbar GtkToolButton .button:active {
    background-color: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

SugarPaletteWindowWidget GtkScrolledWindow * {
    background-color: @black;
}

.toolbar GtkComboBox .button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

.scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

/* We have to override the color of the scale, otherwise the slider
   background image is invisible or not set for this palettes.
   Upstream bug: https://bugzilla.gnome.org/show_bug.cgi?id=686703 */
SugarPaletteWindowWidget .scale {
    color: transparent;
}

.scale.trough {
    background-color: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

.scale.trough.vertical {
    margin: 0 $(scale_trough_margin)px;
}

.scale.trough:focused {
    border-color: @white;
}

.scale.trough.top,
.scale.trough.left {
    background-color: @white;
}

.scale.trough.top:focused,
.scale.trough.left:focused {
    border-color: @selection_grey;
}

.scale.trough {
    border-radius: 0px $(2*subcell_size)px $(2*subcell_size)px 0px;
}

.scale.trough.vertical {
    border-radius: 0px 0px $(2*subcell_size)px $(2*subcell_size)px;
}

.scale.trough.top {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0px 0px;
}

.scale.trough.left {
    border-radius: $(2*subcell_size)px 0px 0px $(2*subcell_size)px;
}

.scale.slider,
.scale.slider:active {
    background-color: transparent;
}

.scale.slider {
    background-image: url("assets/scale-slider.svg");
}

.scale.slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

GtkCheckButton:prelight {
    background-color: alpha(@theme_base_color, 0.0);
}

.toolbar GtkCheckButton,
SugarPaletteWindowWidget GtkCheckButton {
    color: @theme_base_color;
}

.radio,
.radio row:selected,
.radio row:selected:focused {
    background-image: url("assets/radio.svg");
    background-color: alpha(@theme_base_color, 0.0);
}

.radio:selected,
.radio:selected row:selected,
.radio:selected row:selected:focused {
    background-image: url("assets/radio-selected.svg");
}

.radio:active,
.radio row:selected:active,
.radio row:selected:focused:active {
    background-image: url("assets/radio-active.svg");
}

.radio:active:selected,
.radio:selected row:selected:active,
.radio:selected row:selected:focused:active {
    background-image: url("assets/radio-active-selected.svg");
}

.check,
.check row:selected,
.check row:selected:focused {
    background-image: url("assets/checkbox-unchecked.svg");
    background-color: alpha(@theme_base_color, 0.0);
}

.check:selected,
.check:selected row:selected,
.check:selected row:selected:focused {
    background-image: url("assets/checkbox-unchecked-selected.svg");
}

.check:active,
.check row:selected:active,
.check row:selected:focused:active {
    background-image: url("assets/checkbox-checked.svg");
}

.check:active:selected,
.check:selected row:selected:active,
.check:selected row:selected:focused:active {
    background-image: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

.toolitem {
    /* arrow in the toolbarbox */
    color: @white;
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

GtkImage {
    background-color: transparent;
}

/* Sugar Frame Window */

SugarFrameWindow {
    background-color: @toolbar_grey;
}

/* Sugar Canvas icon */

SugarCanvasIcon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
}

SugarCanvasIcon:prelight {
    border-color: @zoom_views_prelight;
    background-color: @zoom_views_prelight;
}

SugarCanvasIcon:active {
    border-color: @zoom_views_active;
    background-color: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background-color: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:prelight {
    background-color: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background-color: @zoom_views_active;
}

/* Text cursor handles */

.cursor-handle.top,
.cursor-handle.bottom {
    background-color: transparent;
    box-shadow: none;
    border-style: none;
    border-image: none;
    border-radius: 0px;
    border-width: 0px;
}

.cursor-handle.bottom {
    background-image: url("assets/cursor-handle-bottom.svg");
}

.cursor-handle.top {
    background-image: url("assets/cursor-handle-top.svg");
}

.cursor-handle.insertion-cursor {
    background-image: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background-color: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background-color: @selection_grey;
}


Fix the color of the not selected tab

Fix the color of the not selected tab

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if theme == "sugar-xo":
    xo = True
    line_width = 2.25       # 2.25
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    bullet_size = 9.5
    font_height = 24
else: # About 50% smaller
    xo = False
    line_width = 1.125
    thick_line_width = 1.75
    subcell_size = 7
    bullet_size = 5
    font_height = 12

radio_size = my_floor(subcell_size + bullet_size + line_width)
scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

}
style "default"
{
    # Will be overriden in some widgets
    color["focus_line"] = "#FFFFFF"

    bg[NORMAL] = "#808080"
    bg[PRELIGHT] = "#808080"
    bg[ACTIVE] = "#ffffff"
    bg[SELECTED] = "#e7e7e7"

    fg[NORMAL]        = "#000000"
    fg[ACTIVE]        = "#000000"
    fg[SELECTED]      = "#ffffff"
    fg[PRELIGHT]      = "#ffffff"

    text[NORMAL] = "#000000" # "#7f7f7f" 1. need to patch GTK+ to use ACTIVE when focused, 2. what color should this really be?
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    base[NORMAL] = "#E6E6E6"
    base[ACTIVE] = "#ffffff"
    base[SELECTED] = "#a6a6a6"
    base[PRELIGHT] = "#ffffff"

    fg[INSENSITIVE] = "#808080"
    text[INSENSITIVE] = "#808080"

    xthickness = $thickness
    ythickness = $thickness

    # A lot of these will probably need to be changed, but this has to
    # be done when the exact sizes are known
    GtkWidget::interior-focus = 0
    GtkWidget::focus-line-width = 1   # This does not do anything really
    GtkWidget::focus-padding = 0
    # 0.05 works good for both the sugar and sugar-xo themes
    GtkWidget::cursor-aspect-ratio = 0.05

    GtkWidget::wide-separators = 0
    GtkWidget::separator-height = $thickness
    GtkWidget::separator-width = $thickness

    GtkRange::activate-slider = 1
    GtkButton::inner-border = { 6, 6, 6, 6 }           # ??

    GtkButton::default-border = { 1, 1, 1, 1 }         # line_width - focus-line-width
    GtkButton::default-outside-border = { 2, 2, 2, 2 } # focus-line-width

    GtkScrolledWindow::scrollbar-spacing = 0

    GtkExpander::expander-size = 24
    GtkExpander::expander-spacing = 2     # XXX

    GtkTreeView::expander-size = 24

    GtkArrow::arrow-size = 1.0

    engine "sugar" {
        # Is this correct? Should we make sure it is pixel aligned?
        # 6 pixel for the XO version, and 3 for the "normal" one
        line_width = $line_width
        # 9-10 pixel for the XO version, and 4 for the "normal" one
        thick_line_width = $thick_line_width

        max_radius = $( xo ? 25 : 15)
    }
}

style "window-content"
{
    color["bg_color"] = "#C0C0C0"

    bg[INSENSITIVE] = @bg_color
    base[INSENSITIVE] = @bg_color
}

style "window"
{
    color["bg_color"] = "#C0C0C0"

    bg[NORMAL] = @bg_color
}

style "scrollbar"
{
    GtkRange::slider-width = 16    # ?
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkScrollbar::min-slider-length = 30    # ?
    GtkScrollbar::has-forward-stepper = 0
    GtkScrollbar::has-backward-stepper = 0
    GtkScrollbar::has-secondary-forward-stepper = 0
    GtkScrollbar::has-secondary-backward-stepper = 0

    # Hack for mozilla as it does not obey the above style properties ...
    # Really, mozilla should be fixed ...
    GtkRange::stepper-size = 1

    engine "sugar" {
        hint = "scrollbar"
        scrollbar_border = 3
    }
}

style "scale"
{
    GtkWidget::focus-line-width = 0

    # "square" slider (really round of course)
    # Same as indicator-size?
    GtkRange::slider-width = $scale_slider_width
    GtkScale::slider-length = $scale_slider_width
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkRange::trough-side-details = 1
}

# hints for the trough sizing hacks
style "hscale" = "scale"
{
    engine "sugar" {
        hint = "hscale"
    }
}

style "vscale" = "scale"
{
    engine "sugar" {
        hint = "vscale"
    }
}

style "spinbutton"
{
    fg[NORMAL]        = "#ffffff"
    engine "sugar" {
        hint = "spinbutton"
    }
}

style "comboboxentry"
{
    # Copied from the "default" style. Part of the workaround for bug #382646.
    text[NORMAL] = "#000000"
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    engine "sugar" {
        hint = "comboboxentry"
    }
}

style "frame"
{
    bg[NORMAL] = "#404040"
}

style "notebook"
{
    GtkNotebook::tab-overlap = -2

    xthickness = 0
    ythickness = 0

    bg[ACTIVE] = "#808080"
}

style "toolbutton"
{
    color["focus_line"] = "#000000"

    #bg[NORMAL] = "#404040"
    bg[PRELIGHT] = "#000000"
    bg[ACTIVE] = "#808080"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"
    fg[PRELIGHT] = "#ffffff"

    engine "sugar" {
        max_radius = 5.0
    }
}

style "toolbox"
{
    color["bg_color"] = "#404040"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"

    bg[NORMAL] = @bg_color
}

style "toolbox-content"
{
    GtkToolbar::shadow-type = GTK_SHADOW_NONE

    color["bg_color"] = "#404040"

    bg[INSENSITIVE] = @bg_color
}

style "panel"
{
    bg[NORMAL] = "#C0C0C0"
    fg[NORMAL] = "#000000"
}

style "entry"
{
    # small inner border and a large x/ythickness for entries
    # to reduce the number of hacks needed :-)
    xthickness = $(thickness*3)
    ythickness = $(thickness*3)

    # This tries to get a height of exactly 45 pixel for the entry.
    GtkEntry::inner-border = { $(subcell_size - thickness*3), $(subcell_size - thickness*3),
                               $(my_floor((3*subcell_size - font_height - thickness*3*2)/2)), $(my_ceil((3*subcell_size - font_height - thickness*3*2)/2)) }

    GtkWidget::focus-line-width = 0
}

style "button"
{
    fg[NORMAL]        = "#ffffff"
}

style "combobox"
{
    # Work around GTK+ bug #382646
    text[NORMAL]      = "#FFFFFF"
    text[ACTIVE]      = "#FFFFFF"
    text[PRELIGHT]    = "#ffffff"
}

style "checkbutton"
{
    fg[NORMAL]        = "#000000"
    fg[PRELIGHT]      = "#000000"
    fg[ACTIVE]        = "#000000"

    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    # I won't get the exact sizing, but this should be pretty close
    GtkCheckButton::indicator-size = $radio_size
    GtkCheckButton::indicator-spacing = 3
    GtkWidget::focus-padding = 3
}

style "progressbar"
{
    xthickness = 0
    ythickness = 0

    # Make the bar visible (only until the engine implements it!)
    bg[PRELIGHT] = "#ffffff"
}

style "menu"
{
    color["bg_color"] = "#000000"

    fg[NORMAL]   = "#ffffff"
    fg[PRELIGHT] = "#ffffff"
    bg[NORMAL] = "#808080"

    # The following colors are for the check and radio menu items
    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    GtkMenu::horizontal-padding = 0
    GtkMenu::vertical-padding   = 0

    xthickness = 0
    ythickness = 0
}

style "menuitem"
{
    GtkCheckMenuItem::indicator-size = $radio_size

    bg[PRELIGHT] = "#808080"

    # For check/radio menu items
    text[NORMAL] = "#FFFFFF"
    text[PRELIGHT] = "#FFFFFF"

    GtkMenuItem::horizontal-padding = $line_width
    xthickness = $(my_ceil(line_width * 2))
    ythickness = $thickness
}

style "separatormenuitem"
{
    GtkMenuItem::horizontal-padding = 0
    xthickness = 0
}

class "GtkWidget"      style "default"
class "GtkWindow"      style "window"
class "GtkEventBox"    style "window"
class "GtkNotebook"    style "notebook"
class "GtkEntry"       style "entry"
class "GtkSpinButton"  style "spinbutton"
class "GtkScrollbar"   style "scrollbar"
class "GtkHScale"      style "hscale"
class "GtkVScale"      style "vscale"
class "GtkProgressBar" style "progressbar"

widget_class "<GtkWindow>.*"                style "window-content"

widget_class "*<SugarToolbox>*"             style "toolbox"
widget_class "*<SugarToolbox>.GtkNotebook"  style "toolbox"
widget_class "*<SugarToolbox>*"             style "toolbox-content"
widget_class "*<GtkToolButton>*"            style "toolbutton"

widget_class "*<GtkMenu>*"                style "menu"
widget_class "*<GtkMenuItem>*"            style "menuitem"
widget_class "*<GtkSeparatorMenuItem>*"   style "menuitem"

widget_class "*<GtkComboBox>*"         style "combobox"
widget_class "*<GtkComboBoxEntry>*"    style "comboboxentry"
widget_class "*<GtkCombo>*"            style "comboboxentry"
widget_class "*<GtkButton>*"           style "button"
widget_class "*<GtkCheckButton>*"      style "checkbutton"

widget_class "*<SugarPanel>"           style "panel"

widget_class "*<SugarFrameWindow>*"    style "frame"

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if theme == "sugar-xo":
    xo = True
    line_width = 2.25       # 2.25
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    bullet_size = 9.5
    font_height = 24
else: # About 50% smaller
    xo = False
    line_width = 1.125
    thick_line_width = 1.75
    subcell_size = 7
    bullet_size = 5
    font_height = 12

radio_size = my_floor(subcell_size + bullet_size + line_width)
scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

}
style "default"
{
    # Will be overriden in some widgets
    color["focus_line"] = "#FFFFFF"

    bg[NORMAL] = "#808080"
    bg[PRELIGHT] = "#808080"
    bg[ACTIVE] = "#ffffff"
    bg[SELECTED] = "#e7e7e7"

    fg[NORMAL]        = "#000000"
    fg[ACTIVE]        = "#000000"
    fg[SELECTED]      = "#ffffff"
    fg[PRELIGHT]      = "#ffffff"

    text[NORMAL] = "#000000" # "#7f7f7f" 1. need to patch GTK+ to use ACTIVE when focused, 2. what color should this really be?
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    base[NORMAL] = "#E6E6E6"
    base[ACTIVE] = "#ffffff"
    base[SELECTED] = "#a6a6a6"
    base[PRELIGHT] = "#ffffff"

    fg[INSENSITIVE] = "#808080"
    text[INSENSITIVE] = "#808080"

    xthickness = $thickness
    ythickness = $thickness

    # A lot of these will probably need to be changed, but this has to
    # be done when the exact sizes are known
    GtkWidget::interior-focus = 0
    GtkWidget::focus-line-width = 1   # This does not do anything really
    GtkWidget::focus-padding = 0
    # 0.05 works good for both the sugar and sugar-xo themes
    GtkWidget::cursor-aspect-ratio = 0.05

    GtkWidget::wide-separators = 0
    GtkWidget::separator-height = $thickness
    GtkWidget::separator-width = $thickness

    GtkRange::activate-slider = 1
    GtkButton::inner-border = { 6, 6, 6, 6 }           # ??

    GtkButton::default-border = { 1, 1, 1, 1 }         # line_width - focus-line-width
    GtkButton::default-outside-border = { 2, 2, 2, 2 } # focus-line-width

    GtkScrolledWindow::scrollbar-spacing = 0

    GtkExpander::expander-size = 24
    GtkExpander::expander-spacing = 2     # XXX

    GtkTreeView::expander-size = 24

    GtkArrow::arrow-size = 1.0

    engine "sugar" {
        # Is this correct? Should we make sure it is pixel aligned?
        # 6 pixel for the XO version, and 3 for the "normal" one
        line_width = $line_width
        # 9-10 pixel for the XO version, and 4 for the "normal" one
        thick_line_width = $thick_line_width

        max_radius = $( xo ? 25 : 15)
    }
}

style "window-content"
{
    color["bg_color"] = "#C0C0C0"

    bg[INSENSITIVE] = @bg_color
    base[INSENSITIVE] = @bg_color
}

style "window"
{
    color["bg_color"] = "#C0C0C0"

    bg[NORMAL] = @bg_color
}

style "scrollbar"
{
    GtkRange::slider-width = 16    # ?
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkScrollbar::min-slider-length = 30    # ?
    GtkScrollbar::has-forward-stepper = 0
    GtkScrollbar::has-backward-stepper = 0
    GtkScrollbar::has-secondary-forward-stepper = 0
    GtkScrollbar::has-secondary-backward-stepper = 0

    # Hack for mozilla as it does not obey the above style properties ...
    # Really, mozilla should be fixed ...
    GtkRange::stepper-size = 1

    engine "sugar" {
        hint = "scrollbar"
        scrollbar_border = 3
    }
}

style "scale"
{
    GtkWidget::focus-line-width = 0

    # "square" slider (really round of course)
    # Same as indicator-size?
    GtkRange::slider-width = $scale_slider_width
    GtkScale::slider-length = $scale_slider_width
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkRange::trough-side-details = 1
}

# hints for the trough sizing hacks
style "hscale" = "scale"
{
    engine "sugar" {
        hint = "hscale"
    }
}

style "vscale" = "scale"
{
    engine "sugar" {
        hint = "vscale"
    }
}

style "spinbutton"
{
    fg[NORMAL]        = "#ffffff"
    engine "sugar" {
        hint = "spinbutton"
    }
}

style "comboboxentry"
{
    # Copied from the "default" style. Part of the workaround for bug #382646.
    text[NORMAL] = "#000000"
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    engine "sugar" {
        hint = "comboboxentry"
    }
}

style "frame"
{
    bg[NORMAL] = "#404040"
}

style "notebook"
{
    GtkNotebook::tab-overlap = -2

    xthickness = 0
    ythickness = 0
}

style "toolbutton"
{
    color["focus_line"] = "#000000"

    #bg[NORMAL] = "#404040"
    bg[PRELIGHT] = "#000000"
    bg[ACTIVE] = "#808080"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"
    fg[PRELIGHT] = "#ffffff"

    engine "sugar" {
        max_radius = 5.0
    }
}

style "toolbox"
{
    color["bg_color"] = "#404040"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"

    bg[NORMAL] = @bg_color
}

style "toolbox-content"
{
    GtkToolbar::shadow-type = GTK_SHADOW_NONE

    color["bg_color"] = "#404040"

    bg[INSENSITIVE] = @bg_color
}

style "panel"
{
    bg[NORMAL] = "#C0C0C0"
    fg[NORMAL] = "#000000"
}

style "entry"
{
    # small inner border and a large x/ythickness for entries
    # to reduce the number of hacks needed :-)
    xthickness = $(thickness*3)
    ythickness = $(thickness*3)

    # This tries to get a height of exactly 45 pixel for the entry.
    GtkEntry::inner-border = { $(subcell_size - thickness*3), $(subcell_size - thickness*3),
                               $(my_floor((3*subcell_size - font_height - thickness*3*2)/2)), $(my_ceil((3*subcell_size - font_height - thickness*3*2)/2)) }

    GtkWidget::focus-line-width = 0
}

style "button"
{
    fg[NORMAL]        = "#ffffff"
}

style "combobox"
{
    # Work around GTK+ bug #382646
    text[NORMAL]      = "#FFFFFF"
    text[ACTIVE]      = "#FFFFFF"
    text[PRELIGHT]    = "#ffffff"
}

style "checkbutton"
{
    fg[NORMAL]        = "#000000"
    fg[PRELIGHT]      = "#000000"
    fg[ACTIVE]        = "#000000"

    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    # I won't get the exact sizing, but this should be pretty close
    GtkCheckButton::indicator-size = $radio_size
    GtkCheckButton::indicator-spacing = 3
    GtkWidget::focus-padding = 3
}

style "progressbar"
{
    xthickness = 0
    ythickness = 0

    # Make the bar visible (only until the engine implements it!)
    bg[PRELIGHT] = "#ffffff"
}

style "menu"
{
    color["bg_color"] = "#000000"

    fg[NORMAL]   = "#ffffff"
    fg[PRELIGHT] = "#ffffff"
    bg[NORMAL] = "#808080"

    # The following colors are for the check and radio menu items
    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    GtkMenu::horizontal-padding = 0
    GtkMenu::vertical-padding   = 0

    xthickness = 0
    ythickness = 0
}

style "menuitem"
{
    GtkCheckMenuItem::indicator-size = $radio_size

    bg[PRELIGHT] = "#808080"

    # For check/radio menu items
    text[NORMAL] = "#FFFFFF"
    text[PRELIGHT] = "#FFFFFF"

    GtkMenuItem::horizontal-padding = $line_width
    xthickness = $(my_ceil(line_width * 2))
    ythickness = $thickness
}

style "separatormenuitem"
{
    GtkMenuItem::horizontal-padding = 0
    xthickness = 0
}

class "GtkWidget"      style "default"
class "GtkWindow"      style "window"
class "GtkEventBox"    style "window"
class "GtkNotebook"    style "notebook"
class "GtkEntry"       style "entry"
class "GtkSpinButton"  style "spinbutton"
class "GtkScrollbar"   style "scrollbar"
class "GtkHScale"      style "hscale"
class "GtkVScale"      style "vscale"
class "GtkProgressBar" style "progressbar"

widget_class "<GtkWindow>.*"                style "window-content"

widget_class "*<SugarToolbox>*"             style "toolbox"
widget_class "*<SugarToolbox>.GtkNotebook"  style "toolbox"
widget_class "*<SugarToolbox>*"             style "toolbox-content"
widget_class "*<GtkToolButton>*"            style "toolbutton"

widget_class "*<GtkMenu>*"                style "menu"
widget_class "*<GtkMenuItem>*"            style "menuitem"
widget_class "*<GtkSeparatorMenuItem>*"   style "menuitem"

widget_class "*<GtkComboBox>*"         style "combobox"
widget_class "*<GtkComboBoxEntry>*"    style "comboboxentry"
widget_class "*<GtkCombo>*"            style "comboboxentry"
widget_class "*<GtkButton>*"           style "button"
widget_class "*<GtkCheckButton>*"      style "checkbutton"

widget_class "*<SugarPanel>"           style "panel"

widget_class "*<SugarFrameWindow>*"    style "frame"


use templated bootstrap tools install

use templated bootstrap tools install

Signed-off-by: Mikael Arguedas <a16f295d1139a1392bb19262902c32cf3e999ce4@gmail.com>

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'dirmngr',
    'gnupg2',
    'lsb-release',
    'wget',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-latest.list

@(TEMPLATE(
    'snippet/install_ros_bootstrap_tools.Dockerfile.em',
    ros_version=version,
))@

# setup environment
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@

# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN mkdir -p /opt/ros/$ROS_DISTRO
ENV ROS2_BINARY_URL @ros2_binary_url
RUN wget -q $ROS2_BINARY_URL -O - | \
    tar -xj --strip-components=1 -C /opt/ros/$ROS_DISTRO

# install dependencies
RUN apt-get update && rosdep install -y \
    --from-paths /opt/ros/$ROS_DISTRO/share \
    --ignore-src \
    --skip-keys " \
      @(' \\\n      '.join(skip_keys))@ " \
    && rm -rf /var/lib/apt/lists/*

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'dirmngr',
    'gnupg2',
    'lsb-release',
    'wget',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-latest.list

# install bootstrap tools
RUN apt-get update && apt-get install --no-install-recommends -y \
    python3-rosdep \
    python3-rosinstall \
    python3-vcstools \
    wget \
    && rm -rf /var/lib/apt/lists/*

# setup environment
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@

# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN mkdir -p /opt/ros/$ROS_DISTRO
ENV ROS2_BINARY_URL @ros2_binary_url
RUN wget -q $ROS2_BINARY_URL -O - | \
    tar -xj --strip-components=1 -C /opt/ros/$ROS_DISTRO

# install dependencies
RUN apt-get update && rosdep install -y \
    --from-paths /opt/ros/$ROS_DISTRO/share \
    --ignore-src \
    --skip-keys " \
      @(' \\\n      '.join(skip_keys))@ " \
    && rm -rf /var/lib/apt/lists/*

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]


remove ros-workspace workaround

remove ros-workspace workaround

Signed-off-by: Mikael Arguedas <a16f295d1139a1392bb19262902c32cf3e999ce4@gmail.com>

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'cmake',
    'dirmngr',
    'git',
    'gnupg2',
    'lsb-release',
    'wget',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2-testing/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-testing.list

@(TEMPLATE(
    'snippet/install_ros_bootstrap_tools.Dockerfile.em',
    ros_version=ros_version,
))@

@[if 'env_before' in locals()]@
# setup environment
@[  for env_var, env_val in env_before.items()]@
ENV @(env_var) @(env_val)
@[  end for]@

@[end if]@
@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@
@(TEMPLATE(
    'snippet/check_pytest_regression.Dockerfile.em',
))@
@
# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN mkdir -p /opt/ros/$ROS_DISTRO
ARG ROS2_BINARY_URL=@ros2_binary_url
RUN wget -q $ROS2_BINARY_URL -O - | \
    tar -xj --strip-components=1 -C /opt/ros/$ROS_DISTRO

@(TEMPLATE(
    'snippet/setup_colcon_mixin_metadata.Dockerfile.em',
))@

@[if 'rosdep' in locals()]@
# bootstrap rosdep
RUN rosdep init

@[  if 'override_rule_files' in rosdep]@
# add custom rosdep rule files
@[    for rule_file in rosdep['override_rule_files']]@
COPY @rule_file /etc/ros/rosdep/
RUN echo "yaml file:///etc/ros/rosdep/@rule_file" | \
    cat - /etc/ros/rosdep/sources.list.d/20-default.list > temp && \
    mv temp /etc/ros/rosdep/sources.list.d/20-default.list
@[    end for]@
@[  end if]@
RUN rosdep update

@{
if 'path' not in rosdep:
  rosdep['path']='/opt/ros/$ROS_DISTRO/share'
}@
# install dependencies
RUN . /opt/ros/$ROS_DISTRO/setup.sh \
    && apt-get update \
    && rosdep install -y \
    --from-paths @(rosdep['path']) \
    --ignore-src \
    --skip-keys " \
      @(' \\\n      '.join(rosdep['skip_keys']))@ " \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@
@[if 'env_after' in locals()]@
# setup environment
@[  for env_var, env_val in env_after.items()]@
ENV @(env_var) @(env_val)
@[  end for]@

@[end if]@
@
@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'cmake',
    'dirmngr',
    'git',
    'gnupg2',
    'lsb-release',
    'wget',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2-testing/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-testing.list

@(TEMPLATE(
    'snippet/install_ros_bootstrap_tools.Dockerfile.em',
    ros_version=ros_version,
))@

@[if 'env_before' in locals()]@
# setup environment
@[  for env_var, env_val in env_before.items()]@
ENV @(env_var) @(env_val)
@[  end for]@

@[end if]@
@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@
@(TEMPLATE(
    'snippet/check_pytest_regression.Dockerfile.em',
))@
@
# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN mkdir -p /opt/ros/$ROS_DISTRO
ARG ROS2_BINARY_URL=@ros2_binary_url
RUN wget -q $ROS2_BINARY_URL -O - | \
    tar -xj --strip-components=1 -C /opt/ros/$ROS_DISTRO

# Overwrite setup scripts with ones that point to /opt/ros/$ROS_DISTRO
RUN mkdir -p /tmp/dir/build \
 && cd /tmp/dir \
 && git clone --depth 1 https://github.com/ros2/ros_workspace.git -b latest \
 && cd /tmp/dir/build \
 && COLCON_CURRENT_PREFIX=/opt/ros/$ROS_DISTRO . /opt/ros/$ROS_DISTRO/local_setup.sh \
 && cmake -DCMAKE_INSTALL_PREFIX=/opt/ros/$ROS_DISTRO ../ros_workspace \
 && make install \
 && rm -r /tmp/dir

@(TEMPLATE(
    'snippet/setup_colcon_mixin_metadata.Dockerfile.em',
))@

@[if 'rosdep' in locals()]@
# bootstrap rosdep
RUN rosdep init

@[  if 'override_rule_files' in rosdep]@
# add custom rosdep rule files
@[    for rule_file in rosdep['override_rule_files']]@
COPY @rule_file /etc/ros/rosdep/
RUN echo "yaml file:///etc/ros/rosdep/@rule_file" | \
    cat - /etc/ros/rosdep/sources.list.d/20-default.list > temp && \
    mv temp /etc/ros/rosdep/sources.list.d/20-default.list
@[    end for]@
@[  end if]@
RUN rosdep update

@{
if 'path' not in rosdep:
  rosdep['path']='/opt/ros/$ROS_DISTRO/share'
}@
# install dependencies
RUN . /opt/ros/$ROS_DISTRO/setup.sh \
    && apt-get update \
    && rosdep install -y \
    --from-paths @(rosdep['path']) \
    --ignore-src \
    --skip-keys " \
      @(' \\\n      '.join(rosdep['skip_keys']))@ " \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@
@[if 'env_after' in locals()]@
# setup environment
@[  for env_var, env_val in env_after.items()]@
ENV @(env_var) @(env_val)
@[  end for]@

@[end if]@
@
@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]


update another plugin version

update another plugin version

<hudson.plugins.view.dashboard.Dashboard plugin="dashboard-view@@2.9.10">
  <name>@view_name</name>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
  <filterExecutors>false</filterExecutors>
  <filterQueue>@('true' if filter_queue else 'false')</filterQueue>
  <properties class="hudson.model.View$PropertyList"/>
  <jobNames>
    <comparator class="hudson.util.CaseInsensitiveComparator"/>
  </jobNames>
  <jobFilters/>
  <columns>
    <hudson.views.StatusColumn/>
    <hudson.views.WeatherColumn/>
    <hudson.views.JobColumn/>
    <hudson.views.LastSuccessColumn/>
    <hudson.views.LastFailureColumn/>
    <hudson.views.LastDurationColumn/>
    <jenkins.plugins.extracolumns.BuildDescriptionColumn plugin="extra-columns@@1.18">
      <columnWidth>80</columnWidth>
      <forceWidth>true</forceWidth>
    </jenkins.plugins.extracolumns.BuildDescriptionColumn>
    <hudson.views.BuildButtonColumn/>
    <jenkins.plugins.extracolumns.TestResultColumn plugin="extra-columns@@1.18">
      <testResultFormat>1</testResultFormat>
    </jenkins.plugins.extracolumns.TestResultColumn>
    <hudson.plugins.warnings.WarningsColumn plugin="warnings@@4.62"/>
  </columns>
@[if include_regex]@
  <includeRegex>@include_regex</includeRegex>
@[end if]@
  <recurse>false</recurse>
  <useCssStyle>false</useCssStyle>
  <includeStdJobList>false</includeStdJobList>
  <hideJenkinsPanels>false</hideJenkinsPanels>
  <leftPortletWidth>50%</leftPortletWidth>
  <rightPortletWidth>50%</rightPortletWidth>
  <leftPortlets>
    <hudson.plugins.view.dashboard.stats.StatBuilds>
      <id>dashboard_portlet_5357</id>
      <name>Build statistics</name>
    </hudson.plugins.view.dashboard.stats.StatBuilds>
  </leftPortlets>
  <rightPortlets>
    <hudson.plugins.view.dashboard.test.TestTrendChart>
      <id>dashboard_portlet_6555</id>
      <name>Test Trend Chart</name>
      <graphWidth>500</graphWidth>
      <graphHeight>220</graphHeight>
      <dateRange>0</dateRange>
      <dateShift>0</dateShift>
      <displayStatus>ALL</displayStatus>
    </hudson.plugins.view.dashboard.test.TestTrendChart>
  </rightPortlets>
  <topPortlets/>
  <bottomPortlets>
    <hudson.plugins.view.dashboard.core.HudsonStdJobsPortlet>
      <id>dashboard_portlet_14122</id>
      <name>Jenkins jobs list</name>
    </hudson.plugins.view.dashboard.core.HudsonStdJobsPortlet>
  </bottomPortlets>
</hudson.plugins.view.dashboard.Dashboard>

<hudson.plugins.view.dashboard.Dashboard plugin="dashboard-view@@2.9.10">
  <name>@view_name</name>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
  <filterExecutors>false</filterExecutors>
  <filterQueue>@('true' if filter_queue else 'false')</filterQueue>
  <properties class="hudson.model.View$PropertyList"/>
  <jobNames>
    <comparator class="hudson.util.CaseInsensitiveComparator"/>
  </jobNames>
  <jobFilters/>
  <columns>
    <hudson.views.StatusColumn/>
    <hudson.views.WeatherColumn/>
    <hudson.views.JobColumn/>
    <hudson.views.LastSuccessColumn/>
    <hudson.views.LastFailureColumn/>
    <hudson.views.LastDurationColumn/>
    <jenkins.plugins.extracolumns.BuildDescriptionColumn plugin="extra-columns@@1.17">
      <columnWidth>80</columnWidth>
      <forceWidth>true</forceWidth>
    </jenkins.plugins.extracolumns.BuildDescriptionColumn>
    <hudson.views.BuildButtonColumn/>
    <jenkins.plugins.extracolumns.TestResultColumn plugin="extra-columns@@1.17">
      <testResultFormat>1</testResultFormat>
    </jenkins.plugins.extracolumns.TestResultColumn>
    <hudson.plugins.warnings.WarningsColumn plugin="warnings@@4.62"/>
  </columns>
@[if include_regex]@
  <includeRegex>@include_regex</includeRegex>
@[end if]@
  <recurse>false</recurse>
  <useCssStyle>false</useCssStyle>
  <includeStdJobList>false</includeStdJobList>
  <hideJenkinsPanels>false</hideJenkinsPanels>
  <leftPortletWidth>50%</leftPortletWidth>
  <rightPortletWidth>50%</rightPortletWidth>
  <leftPortlets>
    <hudson.plugins.view.dashboard.stats.StatBuilds>
      <id>dashboard_portlet_5357</id>
      <name>Build statistics</name>
    </hudson.plugins.view.dashboard.stats.StatBuilds>
  </leftPortlets>
  <rightPortlets>
    <hudson.plugins.view.dashboard.test.TestTrendChart>
      <id>dashboard_portlet_6555</id>
      <name>Test Trend Chart</name>
      <graphWidth>500</graphWidth>
      <graphHeight>220</graphHeight>
      <dateRange>0</dateRange>
      <dateShift>0</dateShift>
      <displayStatus>ALL</displayStatus>
    </hudson.plugins.view.dashboard.test.TestTrendChart>
  </rightPortlets>
  <topPortlets/>
  <bottomPortlets>
    <hudson.plugins.view.dashboard.core.HudsonStdJobsPortlet>
      <id>dashboard_portlet_14122</id>
      <name>Jenkins jobs list</name>
    </hudson.plugins.view.dashboard.core.HudsonStdJobsPortlet>
  </bottomPortlets>
</hudson.plugins.view.dashboard.Dashboard>


always apt-get update before searching for dependencies in doc jobs

# generated from @template_name

FROM ubuntu:trusty
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

VOLUME ["/var/cache/apt/archives"]

ENV DEBIAN_FRONTEND noninteractive
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV TZ @timezone

RUN useradd -u @uid -m buildfarm

@(TEMPLATE(
    'snippet/add_distribution_repositories.Dockerfile.em',
    distribution_repository_keys=distribution_repository_keys,
    distribution_repository_urls=distribution_repository_urls,
    os_code_name='trusty',
    add_source=False,
))@

@(TEMPLATE(
    'snippet/add_wrapper_scripts.Dockerfile.em',
    wrapper_scripts=wrapper_scripts,
))@

# automatic invalidation once every day
RUN echo "@today_str"

RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y git mercurial python3-apt python3-catkin-pkg python3-empy python3-rosdep python3-rosdistro subversion

# always invalidate to actually have the latest apt and rosdep state
RUN echo "@now_str"
RUN python3 -u /tmp/wrapper_scripts/apt-get.py update

ENV ROSDISTRO_INDEX_URL @rosdistro_index_url
RUN rosdep init

USER buildfarm

ENTRYPOINT ["sh", "-c"]
@{
cmds = [
    'rosdep update',

    'PYTHONPATH=/tmp/ros_buildfarm:$PYTHONPATH python3 -u' + \
    ' /tmp/ros_buildfarm/scripts/doc/create_doc_task_generator.py' + \
    ' ' + config_url + \
    ' --rosdistro-name ' + rosdistro_name + \
    ' ' + doc_build_name + \
    ' --workspace-root /tmp/catkin_workspace' + \
    ' --rosdoc-lite-dir /tmp/rosdoc_lite' + \
    ' --catkin-sphinx-dir /tmp/catkin-sphinx' + \
    ' --rosdoc-index-dir /tmp/rosdoc_index' + \
    ' ' + repository_name + \
    ' --os-name ' + os_name + \
    ' --os-code-name ' + os_code_name + \
    ' --arch ' + arch + \
    ' --vcs-info "%s"' % vcs_info + \
    ' --distribution-repository-urls ' + ' '.join(distribution_repository_urls) + \
    ' --distribution-repository-key-files ' + ' ' .join(['/tmp/keys/%d.key' % i for i in range(len(distribution_repository_keys))]) + \
    (' --force' if force else '') + \
    ' --output-dir /tmp/generated_documentation' + \
    ' --dockerfile-dir /tmp/docker_doc',
]
}@
CMD ["@(' && '.join([c.replace('"', '\\"') for c in cmds]))"]

# generated from @template_name

FROM ubuntu:trusty
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

VOLUME ["/var/cache/apt/archives"]

ENV DEBIAN_FRONTEND noninteractive
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV TZ @timezone

RUN useradd -u @uid -m buildfarm

@(TEMPLATE(
    'snippet/add_distribution_repositories.Dockerfile.em',
    distribution_repository_keys=distribution_repository_keys,
    distribution_repository_urls=distribution_repository_urls,
    os_code_name='trusty',
    add_source=False,
))@

@(TEMPLATE(
    'snippet/add_wrapper_scripts.Dockerfile.em',
    wrapper_scripts=wrapper_scripts,
))@

# automatic invalidation once every day
RUN echo "@today_str"

RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y git mercurial python3-apt python3-catkin-pkg python3-empy python3-rosdep python3-rosdistro subversion

# always invalidate to actually have the latest rosdep state
RUN echo "@now_str"
ENV ROSDISTRO_INDEX_URL @rosdistro_index_url
RUN rosdep init

USER buildfarm

ENTRYPOINT ["sh", "-c"]
@{
cmds = [
    'rosdep update',

    'PYTHONPATH=/tmp/ros_buildfarm:$PYTHONPATH python3 -u' + \
    ' /tmp/ros_buildfarm/scripts/doc/create_doc_task_generator.py' + \
    ' ' + config_url + \
    ' --rosdistro-name ' + rosdistro_name + \
    ' ' + doc_build_name + \
    ' --workspace-root /tmp/catkin_workspace' + \
    ' --rosdoc-lite-dir /tmp/rosdoc_lite' + \
    ' --catkin-sphinx-dir /tmp/catkin-sphinx' + \
    ' --rosdoc-index-dir /tmp/rosdoc_index' + \
    ' ' + repository_name + \
    ' --os-name ' + os_name + \
    ' --os-code-name ' + os_code_name + \
    ' --arch ' + arch + \
    ' --vcs-info "%s"' % vcs_info + \
    ' --distribution-repository-urls ' + ' '.join(distribution_repository_urls) + \
    ' --distribution-repository-key-files ' + ' ' .join(['/tmp/keys/%d.key' % i for i in range(len(distribution_repository_keys))]) + \
    (' --force' if force else '') + \
    ' --output-dir /tmp/generated_documentation' + \
    ' --dockerfile-dir /tmp/docker_doc',
]
}@
CMD ["@(' && '.join([c.replace('"', '\\"') for c in cmds]))"]


cmake: add explicit lib dependency for projects built under catkin_make

Somehow, the target_link_library is not enough in this case to create
a dependency.

add_definitions(-DROS_PACKAGE_NAME=\"${PROJECT_NAME}\")

#
# Add a Catch executable target.
#
# An executable target is created with the source files, it is linked
# against Catch. It is also registered as dependency of the run_tests target.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_test target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	# If catch_ros_standalone is built in this CMake instance, add a dependency on it
	if(TARGET catch_ros_standalone)
		add_dependencies(${target} catch_ros_standalone)
	endif()

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_standalone.so
	)

	if(TARGET ${target})
		# make sure the target is built before running tests
		add_dependencies(tests ${target})

		get_target_property(_target_path ${target} RUNTIME_OUTPUT_DIRECTORY)
		set(cmd "${_target_path}/${target} -r ros_junit -o ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/catch-${target}.xml")
		catkin_run_tests_target("catch" ${target} "catch-${target}.xml" COMMAND ${cmd} DEPENDENCIES ${target})
	endif()
endfunction()

#
# Add a Catch rostest executable target.
#
# An executable target is created with the source files, it is linked
# against Catch.
# In contrast to catch_add_test, this function links against a main() function
# which also calls ros::init(). Also, the test is not registered with the
# run_tests target, because it is expected that you use the test inside of
# a rostest.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_rostest_node target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	# If catch_ros_rostest is built in this CMake instance, add a dependency on it
	if(TARGET catch_ros_rostest)
		add_dependencies(${target} catch_ros_rostest)
	endif()

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_rostest.so
	)
endfunction()

add_definitions(-DROS_PACKAGE_NAME=\"${PROJECT_NAME}\")

#
# Add a Catch executable target.
#
# An executable target is created with the source files, it is linked
# against Catch. It is also registered as dependency of the run_tests target.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_test target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_standalone.so
	)

	if(TARGET ${target})
		# make sure the target is built before running tests
		add_dependencies(tests ${target})

		get_target_property(_target_path ${target} RUNTIME_OUTPUT_DIRECTORY)
		set(cmd "${_target_path}/${target} -r ros_junit -o ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/catch-${target}.xml")
		catkin_run_tests_target("catch" ${target} "catch-${target}.xml" COMMAND ${cmd} DEPENDENCIES ${target})
	endif()
endfunction()

#
# Add a Catch rostest executable target.
#
# An executable target is created with the source files, it is linked
# against Catch.
# In contrast to catch_add_test, this function links against a main() function
# which also calls ros::init(). Also, the test is not registered with the
# run_tests target, because it is expected that you use the test inside of
# a rostest.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_rostest_node target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_rostest.so
	)
endfunction()


fix groovy script to trigger jobs

fix groovy script to trigger jobs

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=365,
    num_to_keep=10,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_job-priority',
    priority=40,
))@
    <hudson.model.ParametersDefinitionProperty>
      <parameterDefinitions>
        <hudson.model.ChoiceParameterDefinition>
          <name>filter</name>
          <description>Select jobs based on their latest build result</description>
          <choices class="java.util.Arrays$ArrayList">
            <a class="string-array">
              <string>not_stable</string>
              <string>worse_than_unstable</string>
              <string>all</string>
              <string>stable</string>
              <string>unstable</string>
              <string>failure</string>
              <string>aborted</string>
              <string>not_built</string>
            </a>
          </choices>
        </hudson.model.ChoiceParameterDefinition>
@[if has_force_parameter]@
        <hudson.model.BooleanParameterDefinition>
          <name>force</name>
          <description>Run documentation generation even if neither the source repository nor any of the tools have changes</description>
          <defaultValue>false</defaultValue>
        </hudson.model.BooleanParameterDefinition>
@[end if]@
      </parameterDefinitions>
    </hudson.model.ParametersDefinitionProperty>
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_null',
))@
  <assignedNode>master</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_system-groovy',
    command=
"""import java.util.regex.Matcher
import java.util.regex.Pattern
import hudson.model.AbstractProject
import hudson.model.BooleanParameterValue
import hudson.model.Cause.UserIdCause
import hudson.model.ParametersAction
import hudson.model.Result

build = Thread.currentThread().executable
resolver = build.buildVariableResolver

filter = resolver.resolve("filter")
println "Filter: " + filter

has_force_parameter = %s
if (has_force_parameter) {
    boolean force = resolver.resolve("force")
    println "Force: " + force + type(force)
}

pattern = Pattern.compile("%s")
for (p in hudson.model.Hudson.instance.getAllItems(AbstractProject)) {
    if (!pattern.matcher(p.name).matches()) continue
    if (p.isDisabled()) continue
    if (p.isBuilding()) continue
    if (p.isInQueue()) continue

    if (filter != "all") {
        def lb = p.lastBuild
        if (!lb) {
            // job has never been built
            if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
        } else {
            def r = lb.result
            def pb = lb
            while (!r) {
              pb = pb.previousBuild
              if (!pb) {
                // no finished build yet
                break
              }
              r = pb.result
            }
            if (r == Result.SUCCESS) {
                if (filter != "stable") continue
            } else if (r == Result.UNSTABLE) {
                if (filter != "unstable" && filter != "not_stable") continue
            } else if (r == Result.FAILURE) {
                if (filter != "failure" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.ABORTED) {
                if (filter != "aborted" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (!r) {
                if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.NOT_BUILT) {
              // this should never happen for the result of a build
              assert false
            } else {
              // unknown result value
              println("Job '" + p.name + "'' has unknown result: " + r)
              assert false
            }
        }
    }
    println p.name
    if (has_force_parameter) {
        p.scheduleBuild(1, new UserIdCause(), new ParametersAction(new BooleanParameterValue("force", force)))
    } else {
        p.scheduleBuild()
    }
}
""" % ('true' if has_force_parameter else 'false', project_name_pattern),
    script_file=None,
    classpath='',
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
@(SNIPPET(
    'build-wrapper_disk-check',
))@
  </buildWrappers>
</project>

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=365,
    num_to_keep=10,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_job-priority',
    priority=40,
))@
    <hudson.model.ParametersDefinitionProperty>
      <parameterDefinitions>
        <hudson.model.ChoiceParameterDefinition>
          <name>filter</name>
          <description>Select jobs based on their latest build result</description>
          <choices class="java.util.Arrays$ArrayList">
            <a class="string-array">
              <string>not_stable</string>
              <string>worse_than_unstable</string>
              <string>all</string>
              <string>stable</string>
              <string>unstable</string>
              <string>failure</string>
              <string>aborted</string>
              <string>not_built</string>
            </a>
          </choices>
        </hudson.model.ChoiceParameterDefinition>
@[if has_force_parameter]@
        <hudson.model.BooleanParameterDefinition>
          <name>force</name>
          <description>Run documentation generation even if neither the source repository nor any of the tools have changes</description>
          <defaultValue>false</defaultValue>
        </hudson.model.BooleanParameterDefinition>
@[end if]@
      </parameterDefinitions>
    </hudson.model.ParametersDefinitionProperty>
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_null',
))@
  <assignedNode>master</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_system-groovy',
    command=
"""import java.util.regex.Matcher
import java.util.regex.Pattern
import hudson.model.AbstractProject
import hudson.model.BooleanParameterValue
import hudson.model.Cause.UserIdCause
import hudson.model.ParametersAction
import hudson.model.Result

build = Thread.currentThread().executable
resolver = build.buildVariableResolver

filter = resolver.resolve("filter")
println "Filter: " + filter

@[if has_force_parameter]@
boolean force = resolver.resolve("force")
println "Force: " + force + type(force)
@[end if]@

pattern = Pattern.compile("%s")
for (p in hudson.model.Hudson.instance.getAllItems(AbstractProject)) {
    if (!pattern.matcher(p.name).matches()) continue
    if (p.isDisabled()) continue
    if (p.isBuilding()) continue
    if (p.isInQueue()) continue

    if (filter != "all") {
        def lb = p.lastBuild
        if (!lb) {
            // job has never been built
            if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
        } else {
            def r = lb.result
            def pb = lb
            while (!r) {
              pb = pb.previousBuild
              if (!pb) {
                // no finished build yet
                break
              }
              r = pb.result
            }
            if (r == Result.SUCCESS) {
                if (filter != "stable") continue
            } else if (r == Result.UNSTABLE) {
                if (filter != "unstable" && filter != "not_stable") continue
            } else if (r == Result.FAILURE) {
                if (filter != "failure" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.ABORTED) {
                if (filter != "aborted" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (!r) {
                if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.NOT_BUILT) {
              // this should never happen for the result of a build
              assert false
            } else {
              // unknown result value
              println("Job '" + p.name + "'' has unknown result: " + r)
              assert false
            }
        }
    }
    println p.name
@[if has_force_parameter]@
    p.scheduleBuild(1, new UserIdCause(), new ParametersAction(new BooleanParameterValue("force", force)))
@[else]@
    p.scheduleBuild()
@[end if]@
}
""" % project_name_pattern,
    script_file=None,
    classpath='',
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
@(SNIPPET(
    'build-wrapper_disk-check',
))@
  </buildWrappers>
</project>