Style insensitive text - SL #4139

Style insensitive text - SL #4139

This is the same as in GTK2 gtkrc rule: fg[INSENSITIVE] = $button_grey

Signed-off-by: Manuel Quiñones <6f5069c5b6be23302a13accec56587944be09079@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: false;
    -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: 55px;
    -GtkWidget-text-handle-height: 55px;
}

*: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;
}

/* Handle this differently? */
.window *:insensitive {
    background-color: @panel_grey;
}

/* 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: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;
}

/* 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;
}

.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;}

/* Menus and palettes */

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

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;
    color: @button_grey;
}

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: @white;
    border-radius: 10px;
    border-style: solid;
    border-width: 0px;
}

GtkProgressBar.trough {
    background-color: alpha (@black, 0.0);
    border-style: solid;
    border-radius: 10px;
    border-color: @button_grey;
    border-width: 2px;
}

/* Separators */

GtkVSeparator, GtkHSeparator,
.toolbar GtkSeparatorToolItem {
    color: @button_grey;
}

/* 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 GtkToolButton .button,
.toolbar SugarRadioToolButton *,
SugarPaletteWindowWidget SugarRadioToolButton *,
SugarPaletteWindowWidget GtkToolButton .button {
    background-color: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding)px;
}

.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 {
    color: @black;
}

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

.toolbar GtkCheckButton *:active,
SugarPaletteWindowWidget GtkCheckButton *:active {
    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.insert-cursor {
    background-image: url("assets/cursor-handle-insert.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: false;
    -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: 55px;
    -GtkWidget-text-handle-height: 55px;
}

/* 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;
}

/* Handle this differently? */
.window *:insensitive {
    background-color: @panel_grey;
}

/* 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: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;
    color: @black;
}

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;
}

/* 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;
}

.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;}

/* Menus and palettes */

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

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;
    color: @button_grey;
}

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: @white;
    border-radius: 10px;
    border-style: solid;
    border-width: 0px;
}

GtkProgressBar.trough {
    background-color: alpha (@black, 0.0);
    border-style: solid;
    border-radius: 10px;
    border-color: @button_grey;
    border-width: 2px;
}

/* Separators */

GtkVSeparator, GtkHSeparator,
.toolbar GtkSeparatorToolItem {
    color: @button_grey;
}

/* 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 GtkToolButton .button,
.toolbar SugarRadioToolButton *,
SugarPaletteWindowWidget SugarRadioToolButton *,
SugarPaletteWindowWidget GtkToolButton .button {
    background-color: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding)px;
}

.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 {
    color: @black;
}

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

.toolbar GtkCheckButton *:active,
SugarPaletteWindowWidget GtkCheckButton *:active {
    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.insert-cursor {
    background-image: url("assets/cursor-handle-insert.svg");
}

/* Application specific properties */

EvView {
    background-color: @panel_grey;
}

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


Disable a bunch of UIs in default GUI to speed up loading.

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

system.require('graphics.em');
system.require('undo.em');
system.require('std/movement/pursue.em');
system.require('std/script/scripter.em');
system.require('inputbinding.em');
system.require('defaultcamera.em');
system.require('drag/move.em');
system.require('drag/rotate.em');
system.require('drag/scale.em');
system.require('std/graphics/chat.em');
system.require('std/graphics/physics.em');
system.require('std/graphics/propertybox.em');
system.require('std/graphics/presenceList.em');
system.require('std/graphics/setMesh.em');
system.require('std/graphics/axes.em');
system.require('std/graphics/flatlandViewer.em');

(
function() {

    var ns = std.graphics;

    /** @namespace
     *  The DefaultGraphics class just contains some sane defaults for
     *  interaction, allowing you to get a decent, baseline client
     *  that only requires built-in functionality. You still define
     *  the presence and which underlying graphics system to use, but
     *  this class takes care of defining all other UI and interaction.
     */
    std.graphics.DefaultGraphics = function(pres, name, cb) {
        this._pres = pres;

        this._simulator = new std.graphics.Graphics(pres, name, std.core.bind(this.finishedGraphicsInit, this, cb), std.core.bind(this.finishedGraphicsUIReset, this));
    };

    std.graphics.DefaultGraphics.prototype.finishedGraphicsInit = function(cb, gfx, alreadyInitialized) {
        this._camera = new std.graphics.DefaultCamera(this._simulator, system.self);

        this._selected = null;
        this._loadingUIs = 0;

        this._alreadyInitialized = alreadyInitialized;
        if (! this._alreadyInitialized)
        {
            var ui_finish_cb = std.core.bind(this.finishedUIInit, this, cb);
            this._loadingUIs++; this._scripter = new std.script.Scripter(this, ui_finish_cb);
            //this._loadingUIs++; this._chat = new std.graphics.Chat(this._pres, this._simulator, ui_finish_cb);
            //this._loadingUIs++; this._physics = new std.graphics.PhysicsProperties(this._simulator, ui_finish_cb);
            //this._loadingUIs++; this._propertybox = new std.propertybox.PropertyBox(this, ui_finish_cb);
            //this._loadingUIs++; this._presenceList = new std.graphics.PresenceList(this._pres, this._simulator, this._scripter, ui_finish_cb);
            //this._loadingUIs++; this._setMesh = new std.graphics.SetMesh(this._simulator, ui_finish_cb);
            //this._loadingUIs++; this._flatland = new std.fl.FL(this, ui_finish_cb);
        }
        else
            this.finishedUIInit(cb);

    };

    std.graphics.DefaultGraphics.prototype.finishedGraphicsUIReset = function(gfx) {
        this._camera.reinit();

        var ui_finish_cb = std.core.bind(this.finishedUIInit, this);
        this._loadingUIs++; this._scripter.onReset(ui_finish_cb);
        //this._loadingUIs++; this._chat.onReset(ui_finish_cb);
        //this._loadingUIs++; this._physics.onReset(ui_finish_cb);
        //this._loadingUIs++; this._propertybox.onReset(ui_finish_cb);
        //this._loadingUIs++; this._presenceList.onReset(ui_finish_cb);
        //this._loadingUIs++; this._setMesh.onReset(ui_finish_cb);
        //this._loadingUIs++; this._flatland.onReset(ui_finish_cb);
    };

    /**
     this._alreadyInitialized is true or false.  If true, means that we
     already had a graphics viewer completely initialized before going
     through this initialization process.  If false, means that we
     are doing initialization for the first time.
     */
    std.graphics.DefaultGraphics.prototype.finishedUIInit = function(cb) {
        this._loadingUIs--;
        if (this._loadingUIs > 0) return;

        if (! this._alreadyInitialized)
            this._simulator.hideLoadScreen();

        this._moverot = new std.movement.MoveAndRotate(this._pres, std.core.bind(this.updateCameraOffset, this), 'rotation');

        this._draggers = {
            move: new std.graphics.MoveDragHandler(this._simulator),
            rotate: new std.graphics.RotateDragHandler(this._simulator),
            scale: new std.graphics.ScaleDragHandler(this._simulator)
        };

        this._binding = new std.graphics.InputBinding();
        this._simulator.inputHandler.onAnything = std.core.bind(this._binding.dispatch, this._binding);

        this._binding.addFloat2Action('pickObject', std.core.bind(this.pickObject, this));

        if (! this._alreadyInitialized)
        {
            this._binding.addAction('quit', std.core.bind(this._simulator.quit, this._simulator));
            this._binding.addAction('screenshot', std.core.bind(this._simulator.screenshot, this._simulator));
            this._binding.addAction('toggleSuspend', std.core.bind(this._simulator.toggleSuspend, this._simulator));
            this._binding.addAction('scriptSelectedObject', std.core.bind(this.scriptSelectedObject, this));
            this._binding.addAction('scriptSelf', std.core.bind(this.scriptSelf, this));

            this._binding.addAction('togglePropertyBox', std.core.bind(this.togglePropertyBox, this));
            this._binding.addAction('toggleChat', std.core.bind(this.toggleChat, this));
            //this._binding.addAction('togglePhysicsProperties', std.core.bind(this._physics.toggle, this._physics));
            //this._binding.addAction('togglePresenceList', std.core.bind(this._presenceList.toggle, this._presenceList));
            //this._binding.addAction('toggleSetMesh', std.core.bind(this._setMesh.toggle, this._setMesh));
            //this._binding.addFloat2Action('showFlatland', std.core.bind(this.showFlatland, this));
            //this._binding.addAction('hideFlatland', std.core.bind(this.hideFlatland, this));

            this._binding.addAction('toggleCameraMode', std.core.bind(this.toggleCameraMode, this));

            this._binding.addAction('actOnObject', std.core.bind(this.actOnObject, this));
            this._binding.addAction('teleportToObj', std.core.bind(this.teleportToObj, this));

            this._binding.addToggleAction('moveForward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, -1)), 1, -1);
            this._binding.addToggleAction('moveBackward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, 1)), 1, -1);
            this._binding.addToggleAction('moveLeft', std.core.bind(this.moveSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
            this._binding.addToggleAction('moveRight', std.core.bind(this.moveSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
            this._binding.addToggleAction('moveUp', std.core.bind(this.moveSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
            this._binding.addToggleAction('moveDown', std.core.bind(this.moveSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

            this._binding.addToggleAction('rotateUp', std.core.bind(this.rotateSelf, this, new util.Vec3(1, 0, 0), "_rotate_up_handle_"), true, false);
            this._binding.addToggleAction('rotateDown', std.core.bind(this.rotateSelf, this, new util.Vec3(-1, 0, 0), "_rotate_down_handle_"), true, false);
            this._binding.addToggleAction('rotateLeft', std.core.bind(this.rotateSelf, this, new util.Vec3(0, 1, 0), "_rotate_left_handle_"), true, false);
            this._binding.addToggleAction('rotateRight', std.core.bind(this.rotateSelf, this, new util.Vec3(0, -1, 0), "_rotate_right_handle_"), true, false);

            this._binding.addFloat2Action('turnOffAxis', std.core.bind(this.turnOffAxis, this));

            this._binding.addAction('axesSnapLocal', std.core.bind(this.setAxesInheritOrient, this, true));
            this._binding.addAction('axesSnapGlobal', std.core.bind(this.setAxesInheritOrient, this, false));

            this._binding.addAction('updatePhysicsProperties', std.core.bind(this.updatePhysicsProperties, this));

            this._binding.addAction('startMoveDrag', std.core.bind(this.startDrag, this, this._draggers.move));
            this._binding.addAction('startRotateDrag', std.core.bind(this.startDrag, this, this._draggers.rotate));
            this._binding.addAction('startScaleDrag', std.core.bind(this.startDrag, this, this._draggers.scale));
            this._binding.addAction('forwardMousePressToDragger', std.core.bind(this.forwardMousePressToDragger, this));
            this._binding.addAction('forwardMouseDragToDragger', std.core.bind(this.forwardMouseDragToDragger, this));
            this._binding.addAction('updatePropertyBox', std.core.bind(this.updatePropertyBox, this));
            this._binding.addAction('forwardMouseReleaseToDragger', std.core.bind(this.forwardMouseReleaseToDragger, this));
            this._binding.addAction('stopDrag', std.core.bind(this.stopDrag, this));

            this._binding.addAction('startFreeRotate', std.core.bind(this.startFreeRotate, this));
            this._binding.addAction('freeRotateDrag', std.core.bind(this.freeRotateDrag, this));
            this._binding.addAction('freeRotateRelease', std.core.bind(this.freeRotateRelease, this));
            this._binding.addAction('undo', std.core.bind(this.undo, this));
            this._binding.addAction('redo', std.core.bind(this.redo, this));
        }

        /** Bindings are an *ordered* list of keys and actions. Keys
         *  are a combination of the type of event, the primary key
         *  for the event (key or mouse button), and modifiers.
         *  Modifiers are tricky to handle. You can specify a string
         *  indicating which to filter on. If you omit the string, it
         *  is equivalent to 'none'. The special values '*' and 'any'
         *  are equivalent and will match any modifier, i.e. the event
         *  will always be triggered. There isn't support
         *  for matching combinations of modifiers.
         */
        var bindings = [{ key: ['mouse-press', 1 ], action: 'pickObject' },
                        { key: ['mouse-click', 2], action: 'pickObject' }];

        if (!this._alreadyInitialized)
        {
            bindings = bindings.concat([{ key: ['button-pressed', 'escape'], action: 'quit' },
                                        { key: ['button-pressed', 'i'], action: 'screenshot' },
                                        { key: ['button-pressed', 'm'], action: 'toggleSuspend' },
                                        { key: ['button-pressed', 's', 'alt' ], action: 'scriptSelectedObject' },
                                        { key: ['button-pressed', 's', 'ctrl' ], action: 'scriptSelf' },
                                        { key: ['button-pressed', 'c', 'ctrl' ], action: 'toggleChat' },
                                        { key: ['button-pressed', 'p', 'ctrl' ], action: 'togglePhysicsProperties' },
                                        { key: ['button-pressed', 'p', 'alt' ], action: 'togglePropertyBox' },
                                        { key: ['button-pressed', 'l', 'ctrl' ], action: 'togglePresenceList' },
                                        { key: ['button-pressed', 'j', 'ctrl' ], action: 'toggleSetMesh' },

                                        { key: ['button-pressed', 'g', 'alt' ], action: 'axesSnapLocal' },
                                        { key: ['button-pressed', 'g', 'ctrl' ], action: 'axesSnapGlobal' },

                                        { key: ['button-pressed', 'z', 'ctrl' ], action: 'undo' },
                                        { key: ['button-pressed', 'y', 'ctrl' ], action: 'redo' },

                                        { key: ['mouse-click', 1, 'shift'], action: 'turnOffAxis' },
                                        { key: ['mouse-click', 2], action: 'scriptSelectedObject' },
                                        { key: ['button-pressed', 'return'], action: 'actOnObject' },
                                        { key: ['button-pressed', 't', 'ctrl' ], action: 'teleportToObj' },

                                        { key: ['button-pressed', 'c' ], action: 'toggleCameraMode' },

                                        { key: ['button', 'w' ], action: 'moveForward' },
                                        { key: ['button', 'up' ], action: 'moveForward' },
                                        { key: ['button', 's' ], action: 'moveBackward' },
                                        { key: ['button', 'down' ], action: 'moveBackward' },
                                        { key: ['button', 'a' ], action: 'moveLeft' },
                                        { key: ['button', 'd' ], action: 'moveRight' },
                                        { key: ['button', 'q' ], action: 'moveUp' },
                                        { key: ['button', 'z' ], action: 'moveDown' },

                                        { key: ['button', 'up', 'shift' ], action: 'rotateUp' },
                                        { key: ['button', 'down', 'shift' ], action: 'rotateDown' },
                                        { key: ['button', 'left' ], action: 'rotateLeft' },
                                        { key: ['button', 'right' ], action: 'rotateRight' },

                                        { key: ['mouse-press', 1 ], action: 'updatePhysicsProperties' },

                                        // Note that the ordering of registration here is critical.
                                        { key: ['mouse-press', 1, 'none' ], action: 'startMoveDrag' },
                                        { key: ['mouse-press', 1, 'ctrl' ], action: 'startRotateDrag' },
                                        { key: ['mouse-press', 1, 'alt' ], action: 'startScaleDrag' },
                                        { key: ['mouse-press', 1, '*'], action: 'forwardMousePressToDragger' },
                                        { key: ['mouse-press', 1, '*'], action: 'updatePropertyBox' },
                                        { key: ['mouse-drag', 1, '*'], action: 'forwardMouseDragToDragger' },
                                        { key: ['mouse-release', 1, '*'], action: 'forwardMouseReleaseToDragger' },
                                        { key: ['mouse-release', 1, '*'], action: 'stopDrag' },
                                        { key: ['mouse-press', 3, 'none'], action: 'showFlatland' },
                                        { key: ['mouse-press', 3, 'none' ], action: 'startFreeRotate' },
                                        { key: ['mouse-drag', 3, 'none'], action: 'freeRotateDrag' },
                                        { key: ['mouse-release', 3, 'none'], action: 'freeRotateRelease' }
                                       ]);
        }

        this._binding.addBindings(bindings);
        std.graphics.axes.init(this._simulator);
        this._axesInheritOrient = true;

        if (cb && typeof(cb) === "function")
            cb(this);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.simulator = function() {
        return this._simulator;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.invoke = function() {
        // Just forward manual invoke commands directly
        return this._simulator.invoke.apply(this._simulator, arguments);
    };

    /** Request that the given URL be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUIModule = function(name, url, cb) {
        return this._simulator.addGUIModule(name, url, cb);
    };

    /** Request that the given script text be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUITextModule = function(name, js_text, cb) {
        return this._simulator.addGUITextModule(name, js_text, cb);
    };

    /** Get the GUI for a previously loaded GUI module. */
    std.graphics.DefaultGraphics.prototype.getGUIModule = function(name) {
        return this._simulator.getGUIModule(name);
    };

    /** Request that the given URL be presented as a widget. */
    std.graphics.DefaultGraphics.prototype.createBrowser = function(name, url, cb) {
        return this._simulator.createBrowser(name, url, cb);
    };

    /** Get a list of animations associated with this entity. */
    std.graphics.DefaultGraphics.prototype.getAnimationList = function(vis) {
        if (!vis)
          vis = system.self;

        return this._simulator.getAnimationList(vis);
    };

    /** Start the animation on this entity given by the specified animation name. */
    std.graphics.DefaultGraphics.prototype.startAnimation = function(vis, anim) {
        return this._simulator.startAnimation(vis, anim);
    };

    /** Stop the animation on this entity. */
    std.graphics.DefaultGraphics.prototype.stopAnimation = function(vis) {
        return this._simulator.stopAnimation(vis);
    };

    //by default how to scale translational velocity from keypresses.  (movement
    //is agonizingly slow if just set this to 1.  I really recommend 5.)
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultVelocityScaling = 5;
    //by default how to scale rotational velocity from keypresses
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultRotationalVelocityScaling = .5;

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleChat = function() {
        this._chat.toggle();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelf = function() {
        this._scripter.script(system.self);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.togglePropertyBox = function() {
        this._propertybox.TogglePropertyBox();
    };

    std.graphics.DefaultGraphics.prototype.setAxesInheritOrient = function(inheritOrient) {
        if (this._axesInheritOrient === inheritOrient) {
            return;
        }

        this._axesInheritOrient = inheritOrient;

        if (this._selected) {
            std.graphics.axes.setInheritOrientAll(this._selected, inheritOrient);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelectedObject = function() {
        if (this._selected == null)
            return;
        this._presenceList.addObject(this._selected.toString(), 'Scripted');
        this._scripter.script(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleCameraMode = function(evt) {
        var newmode = this._camera.mode() == 'first' ? 'third' : 'first';
        this._camera.setMode(newmode);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updateCameraOffset = function(evt) {
        if (this._camera.mode() == 'third') {
            var orient = this._pres.getOrientation();
            this._camera.setOffset(orient.mul(<0, 1.5, 4>));
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.moveSelf = function(dir, val) {
        this._moverot.move(dir, this.defaultVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.rotateSelf = function(about, name, val) {
        if (val) {
            this[name] = this._moverot.rotate(about, this.defaultRotationalVelocityScaling);
        }
        else {
            this._moverot.cancelRotate(this[name]);
            delete this[name];
        }
    };

    std.graphics.DefaultGraphics.prototype.turnOffAxis = function(x, y) {
        if (!this._selected) {
            return;
        }
        var axis = std.graphics.axes.pick(this._selected, x, y);
        if (axis < 0) {
            return;
        } else {
            std.graphics.axes.setVisible(this._selected, axis, false);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.pickObject = function(x, y)
    {
        var ignore_self = this._camera.mode() == 'first';
        var clicked = this._simulator.pick(x, y, ignore_self);
        if (clicked) {
            if (this._selected) {
                if (this._selected.toString() != clicked.toString()) {
                    if (!this._alreadyInitialized)
                    {
                        this._simulator.bbox(this._selected, false);
                        std.graphics.axes.setVisibleAll(this._selected, false);
                    }
                } else {
                    return;
                }
            }

            this._selected = clicked;
            if (!this._alreadyInitialized)
            {
                this._simulator.bbox(this._selected, true);
                std.graphics.axes.setInheritOrientAll(this._selected, this._axesInheritOrient);
                std.graphics.axes.setVisibleAll(this._selected, true);
            }
        } else if (this._selected) {
            if (!this._alreadyInitialized)
            {
                this._simulator.bbox(this._selected, false);
                std.graphics.axes.setVisibleAll(this._selected, false);
            }
            this._selected = null;
        }

    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.actOnObject = function(evt) {
        if (this._selected)
            { 'action' : 'touch' } >> this._selected >> [];
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.teleportToObj = function(evt) {
        if (this._selected) {
            var dir = this._selected.getPosition() - this._pres.getPosition();
            dir = dir.normal();
            var self = this;
            this._selected.loadMesh(function() {
                var hit = std.raytrace.raytrace(null, self._pres.getPosition(), dir, self._selected, null);
                if (hit) {
                    self._pres.setPosition(hit.sub(dir.scale(3)));
                } else {
                    self._pres.setPosition(this._selected.getPosition());
                }
                self._pres.setOrientation(util.Quaternion.fromLookAt(dir));
            });
        }
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePhysicsProperties = function() {
        // Update even if not selected so display can be disabled
        //this._physics.update(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startDrag = function(dragger, evt) {
        if (this._selected)
            this._dragger = dragger;
        if (this._dragger)
            this._dragger.selected(this._selected, this._simulator.pickedPosition(), evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMousePressToDragger = function(evt) {
        if (this._dragger) this._dragger.onMousePress(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseDragToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseDrag(evt);
        //this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePropertyBox = function(evt) {
        //this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseReleaseToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseRelease(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.stopDrag = function() {
        delete this._dragger;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startFreeRotate = function(evt) {
        this.startX = evt.x;
        this.startY = evt.y;
        this.startOrientation = this._pres.getOrientation();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateDrag = function(evt) {
        if (this.startX == null || this.startY == null)
            return;

        var SCALE = 1;
        var dx = evt.x - this.startX;
        var dy = evt.y - this.startY;
        var dXAngle = dx * SCALE;
        var dYAngle = dy * SCALE;
        var newQuat = this.startOrientation
            .mul(new util.Quaternion(<0, 1, 0>, -dXAngle))
            .mul(new util.Quaternion(<1, 0, 0>, dYAngle));
        this._pres.setOrientation(newQuat);

        // Reorient self so up is up.
        this._pres.setOrientation(util.Quaternion.fromLookAt(
            this._pres.getOrientation().zAxis().scale(-1), <0, 1, 0>));
        this.updateCameraOffset();
        this._moverot.reeval();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateRelease = function(evt) {
        this.startX = null;
        this.startY = null;
        this.startOrientation = null;
    };

    std.graphics.DefaultGraphics.prototype.undo = function(evt) {
        this._simulator.undo();
    };

    std.graphics.DefaultGraphics.prototype.redo = function(evt) {
        this._simulator.redo();
    };

    std.graphics.DefaultGraphics.prototype.orientDefault = function(evt) {
        var vis = this._selected;
        if(!vis)
            return;
        var orient = vis.orientation;
        var movable = new std.movement.MovableRemote(vis);
        movable.setOrientation(new util.Quaternion());
        this._simulator.addUndoAction({}, {
            undo: function(action) {
                movable.setOrientation(orient);
            },
            redo: function(action) {
                movable.setOrientation(new util.Quaternion());
            }
        });
    };

    std.graphics.DefaultGraphics.prototype.setMaxObjects = function(maxobjs) {
        this._simulator.setMaxObjects(maxobjs);
    };

    std.graphics.DefaultGraphics.prototype.showFlatland = function (x, y) {
        var ignore_self = this._camera.mode() == 'first';
        var clicked = this._simulator.pick(x, y, ignore_self);
        this._flatland.show(clicked, x, y);
    };

    std.graphics.DefaultGraphics.prototype.hideFlatland = function () {
        this._flatland.hide();
    };

})();

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

system.require('graphics.em');
system.require('undo.em');
system.require('std/movement/pursue.em');
system.require('std/script/scripter.em');
system.require('inputbinding.em');
system.require('defaultcamera.em');
system.require('drag/move.em');
system.require('drag/rotate.em');
system.require('drag/scale.em');
system.require('std/graphics/chat.em');
system.require('std/graphics/physics.em');
system.require('std/graphics/propertybox.em');
system.require('std/graphics/presenceList.em');
system.require('std/graphics/setMesh.em');
system.require('std/graphics/axes.em');
system.require('std/graphics/flatlandViewer.em');

(
function() {

    var ns = std.graphics;

    /** @namespace
     *  The DefaultGraphics class just contains some sane defaults for
     *  interaction, allowing you to get a decent, baseline client
     *  that only requires built-in functionality. You still define
     *  the presence and which underlying graphics system to use, but
     *  this class takes care of defining all other UI and interaction.
     */
    std.graphics.DefaultGraphics = function(pres, name, cb) {
        this._pres = pres;

        this._simulator = new std.graphics.Graphics(pres, name, std.core.bind(this.finishedGraphicsInit, this, cb), std.core.bind(this.finishedGraphicsUIReset, this));
    };

    std.graphics.DefaultGraphics.prototype.finishedGraphicsInit = function(cb, gfx, alreadyInitialized) {
        this._camera = new std.graphics.DefaultCamera(this._simulator, system.self);

        this._selected = null;
        this._loadingUIs = 0;

        this._alreadyInitialized = alreadyInitialized;
        if (! this._alreadyInitialized)
        {
            var ui_finish_cb = std.core.bind(this.finishedUIInit, this, cb);
            this._loadingUIs++; this._scripter = new std.script.Scripter(this, ui_finish_cb);
            this._loadingUIs++; this._chat = new std.graphics.Chat(this._pres, this._simulator, ui_finish_cb);
            this._loadingUIs++; this._physics = new std.graphics.PhysicsProperties(this._simulator, ui_finish_cb);
            this._loadingUIs++; this._propertybox = new std.propertybox.PropertyBox(this, ui_finish_cb);
            this._loadingUIs++; this._presenceList = new std.graphics.PresenceList(this._pres, this._simulator, this._scripter, ui_finish_cb);
            this._loadingUIs++; this._setMesh = new std.graphics.SetMesh(this._simulator, ui_finish_cb);
            this._loadingUIs++; this._flatland = new std.fl.FL(this, ui_finish_cb);
        }
        else
            this.finishedUIInit(cb);

    };

    std.graphics.DefaultGraphics.prototype.finishedGraphicsUIReset = function(gfx) {
        this._camera.reinit();

        var ui_finish_cb = std.core.bind(this.finishedUIInit, this);
        this._loadingUIs++; this._scripter.onReset(ui_finish_cb);
        this._loadingUIs++; this._chat.onReset(ui_finish_cb);
        this._loadingUIs++; this._physics.onReset(ui_finish_cb);
        this._loadingUIs++; this._propertybox.onReset(ui_finish_cb);
        this._loadingUIs++; this._presenceList.onReset(ui_finish_cb);
        this._loadingUIs++; this._setMesh.onReset(ui_finish_cb);
        this._loadingUIs++; this._flatland.onReset(ui_finish_cb);
    };

    /**
     this._alreadyInitialized is true or false.  If true, means that we
     already had a graphics viewer completely initialized before going
     through this initialization process.  If false, means that we
     are doing initialization for the first time.
     */
    std.graphics.DefaultGraphics.prototype.finishedUIInit = function(cb) {
        this._loadingUIs--;
        if (this._loadingUIs > 0) return;

        if (! this._alreadyInitialized)
            this._simulator.hideLoadScreen();

        this._moverot = new std.movement.MoveAndRotate(this._pres, std.core.bind(this.updateCameraOffset, this), 'rotation');

        this._draggers = {
            move: new std.graphics.MoveDragHandler(this._simulator),
            rotate: new std.graphics.RotateDragHandler(this._simulator),
            scale: new std.graphics.ScaleDragHandler(this._simulator)
        };

        this._binding = new std.graphics.InputBinding();
        this._simulator.inputHandler.onAnything = std.core.bind(this._binding.dispatch, this._binding);

        this._binding.addFloat2Action('pickObject', std.core.bind(this.pickObject, this));

        if (! this._alreadyInitialized)
        {
            this._binding.addAction('quit', std.core.bind(this._simulator.quit, this._simulator));
            this._binding.addAction('screenshot', std.core.bind(this._simulator.screenshot, this._simulator));
            this._binding.addAction('toggleSuspend', std.core.bind(this._simulator.toggleSuspend, this._simulator));
            this._binding.addAction('scriptSelectedObject', std.core.bind(this.scriptSelectedObject, this));
            this._binding.addAction('scriptSelf', std.core.bind(this.scriptSelf, this));

            this._binding.addAction('togglePropertyBox', std.core.bind(this.togglePropertyBox, this));
            this._binding.addAction('toggleChat', std.core.bind(this.toggleChat, this));
            this._binding.addAction('togglePhysicsProperties', std.core.bind(this._physics.toggle, this._physics));
            this._binding.addAction('togglePresenceList', std.core.bind(this._presenceList.toggle, this._presenceList));
            this._binding.addAction('toggleSetMesh', std.core.bind(this._setMesh.toggle, this._setMesh));
            this._binding.addFloat2Action('showFlatland', std.core.bind(this.showFlatland, this));
            this._binding.addAction('hideFlatland', std.core.bind(this.hideFlatland, this));

            this._binding.addAction('toggleCameraMode', std.core.bind(this.toggleCameraMode, this));

            this._binding.addAction('actOnObject', std.core.bind(this.actOnObject, this));
            this._binding.addAction('teleportToObj', std.core.bind(this.teleportToObj, this));

            this._binding.addToggleAction('moveForward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, -1)), 1, -1);
            this._binding.addToggleAction('moveBackward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, 1)), 1, -1);
            this._binding.addToggleAction('moveLeft', std.core.bind(this.moveSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
            this._binding.addToggleAction('moveRight', std.core.bind(this.moveSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
            this._binding.addToggleAction('moveUp', std.core.bind(this.moveSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
            this._binding.addToggleAction('moveDown', std.core.bind(this.moveSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

            this._binding.addToggleAction('rotateUp', std.core.bind(this.rotateSelf, this, new util.Vec3(1, 0, 0), "_rotate_up_handle_"), true, false);
            this._binding.addToggleAction('rotateDown', std.core.bind(this.rotateSelf, this, new util.Vec3(-1, 0, 0), "_rotate_down_handle_"), true, false);
            this._binding.addToggleAction('rotateLeft', std.core.bind(this.rotateSelf, this, new util.Vec3(0, 1, 0), "_rotate_left_handle_"), true, false);
            this._binding.addToggleAction('rotateRight', std.core.bind(this.rotateSelf, this, new util.Vec3(0, -1, 0), "_rotate_right_handle_"), true, false);

            this._binding.addFloat2Action('turnOffAxis', std.core.bind(this.turnOffAxis, this));

            this._binding.addAction('axesSnapLocal', std.core.bind(this.setAxesInheritOrient, this, true));
            this._binding.addAction('axesSnapGlobal', std.core.bind(this.setAxesInheritOrient, this, false));

            this._binding.addAction('updatePhysicsProperties', std.core.bind(this.updatePhysicsProperties, this));

            this._binding.addAction('startMoveDrag', std.core.bind(this.startDrag, this, this._draggers.move));
            this._binding.addAction('startRotateDrag', std.core.bind(this.startDrag, this, this._draggers.rotate));
            this._binding.addAction('startScaleDrag', std.core.bind(this.startDrag, this, this._draggers.scale));
            this._binding.addAction('forwardMousePressToDragger', std.core.bind(this.forwardMousePressToDragger, this));
            this._binding.addAction('forwardMouseDragToDragger', std.core.bind(this.forwardMouseDragToDragger, this));
            this._binding.addAction('updatePropertyBox', std.core.bind(this.updatePropertyBox, this));
            this._binding.addAction('forwardMouseReleaseToDragger', std.core.bind(this.forwardMouseReleaseToDragger, this));
            this._binding.addAction('stopDrag', std.core.bind(this.stopDrag, this));

            this._binding.addAction('startFreeRotate', std.core.bind(this.startFreeRotate, this));
            this._binding.addAction('freeRotateDrag', std.core.bind(this.freeRotateDrag, this));
            this._binding.addAction('freeRotateRelease', std.core.bind(this.freeRotateRelease, this));
            this._binding.addAction('undo', std.core.bind(this.undo, this));
            this._binding.addAction('redo', std.core.bind(this.redo, this));
        }

        /** Bindings are an *ordered* list of keys and actions. Keys
         *  are a combination of the type of event, the primary key
         *  for the event (key or mouse button), and modifiers.
         *  Modifiers are tricky to handle. You can specify a string
         *  indicating which to filter on. If you omit the string, it
         *  is equivalent to 'none'. The special values '*' and 'any'
         *  are equivalent and will match any modifier, i.e. the event
         *  will always be triggered. There isn't support
         *  for matching combinations of modifiers.
         */
        var bindings = [{ key: ['mouse-press', 1 ], action: 'pickObject' },
                        { key: ['mouse-click', 2], action: 'pickObject' }];

        if (!this._alreadyInitialized)
        {
            bindings = bindings.concat([{ key: ['button-pressed', 'escape'], action: 'quit' },
                                        { key: ['button-pressed', 'i'], action: 'screenshot' },
                                        { key: ['button-pressed', 'm'], action: 'toggleSuspend' },
                                        { key: ['button-pressed', 's', 'alt' ], action: 'scriptSelectedObject' },
                                        { key: ['button-pressed', 's', 'ctrl' ], action: 'scriptSelf' },
                                        { key: ['button-pressed', 'c', 'ctrl' ], action: 'toggleChat' },
                                        { key: ['button-pressed', 'p', 'ctrl' ], action: 'togglePhysicsProperties' },
                                        { key: ['button-pressed', 'p', 'alt' ], action: 'togglePropertyBox' },
                                        { key: ['button-pressed', 'l', 'ctrl' ], action: 'togglePresenceList' },
                                        { key: ['button-pressed', 'j', 'ctrl' ], action: 'toggleSetMesh' },

                                        { key: ['button-pressed', 'g', 'alt' ], action: 'axesSnapLocal' },
                                        { key: ['button-pressed', 'g', 'ctrl' ], action: 'axesSnapGlobal' },

                                        { key: ['button-pressed', 'z', 'ctrl' ], action: 'undo' },
                                        { key: ['button-pressed', 'y', 'ctrl' ], action: 'redo' },

                                        { key: ['mouse-click', 1, 'shift'], action: 'turnOffAxis' },
                                        { key: ['mouse-click', 2], action: 'scriptSelectedObject' },
                                        { key: ['button-pressed', 'return'], action: 'actOnObject' },
                                        { key: ['button-pressed', 't', 'ctrl' ], action: 'teleportToObj' },

                                        { key: ['button-pressed', 'c' ], action: 'toggleCameraMode' },

                                        { key: ['button', 'w' ], action: 'moveForward' },
                                        { key: ['button', 'up' ], action: 'moveForward' },
                                        { key: ['button', 's' ], action: 'moveBackward' },
                                        { key: ['button', 'down' ], action: 'moveBackward' },
                                        { key: ['button', 'a' ], action: 'moveLeft' },
                                        { key: ['button', 'd' ], action: 'moveRight' },
                                        { key: ['button', 'q' ], action: 'moveUp' },
                                        { key: ['button', 'z' ], action: 'moveDown' },

                                        { key: ['button', 'up', 'shift' ], action: 'rotateUp' },
                                        { key: ['button', 'down', 'shift' ], action: 'rotateDown' },
                                        { key: ['button', 'left' ], action: 'rotateLeft' },
                                        { key: ['button', 'right' ], action: 'rotateRight' },

                                        { key: ['mouse-press', 1 ], action: 'updatePhysicsProperties' },

                                        // Note that the ordering of registration here is critical.
                                        { key: ['mouse-press', 1, 'none' ], action: 'startMoveDrag' },
                                        { key: ['mouse-press', 1, 'ctrl' ], action: 'startRotateDrag' },
                                        { key: ['mouse-press', 1, 'alt' ], action: 'startScaleDrag' },
                                        { key: ['mouse-press', 1, '*'], action: 'forwardMousePressToDragger' },
                                        { key: ['mouse-press', 1, '*'], action: 'updatePropertyBox' },
                                        { key: ['mouse-drag', 1, '*'], action: 'forwardMouseDragToDragger' },
                                        { key: ['mouse-release', 1, '*'], action: 'forwardMouseReleaseToDragger' },
                                        { key: ['mouse-release', 1, '*'], action: 'stopDrag' },
                                        { key: ['mouse-press', 3, 'none'], action: 'showFlatland' },
                                        { key: ['mouse-press', 3, 'none' ], action: 'startFreeRotate' },
                                        { key: ['mouse-drag', 3, 'none'], action: 'freeRotateDrag' },
                                        { key: ['mouse-release', 3, 'none'], action: 'freeRotateRelease' }
                                       ]);
        }

        this._binding.addBindings(bindings);
        std.graphics.axes.init(this._simulator);
        this._axesInheritOrient = true;

        if (cb && typeof(cb) === "function")
            cb(this);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.simulator = function() {
        return this._simulator;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.invoke = function() {
        // Just forward manual invoke commands directly
        return this._simulator.invoke.apply(this._simulator, arguments);
    };

    /** Request that the given URL be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUIModule = function(name, url, cb) {
        return this._simulator.addGUIModule(name, url, cb);
    };

    /** Request that the given script text be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUITextModule = function(name, js_text, cb) {
        return this._simulator.addGUITextModule(name, js_text, cb);
    };

    /** Get the GUI for a previously loaded GUI module. */
    std.graphics.DefaultGraphics.prototype.getGUIModule = function(name) {
        return this._simulator.getGUIModule(name);
    };

    /** Request that the given URL be presented as a widget. */
    std.graphics.DefaultGraphics.prototype.createBrowser = function(name, url, cb) {
        return this._simulator.createBrowser(name, url, cb);
    };

    /** Get a list of animations associated with this entity. */
    std.graphics.DefaultGraphics.prototype.getAnimationList = function(vis) {
        if (!vis)
          vis = system.self;

        return this._simulator.getAnimationList(vis);
    };

    /** Start the animation on this entity given by the specified animation name. */
    std.graphics.DefaultGraphics.prototype.startAnimation = function(vis, anim) {
        return this._simulator.startAnimation(vis, anim);
    };

    /** Stop the animation on this entity. */
    std.graphics.DefaultGraphics.prototype.stopAnimation = function(vis) {
        return this._simulator.stopAnimation(vis);
    };

    //by default how to scale translational velocity from keypresses.  (movement
    //is agonizingly slow if just set this to 1.  I really recommend 5.)
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultVelocityScaling = 5;
    //by default how to scale rotational velocity from keypresses
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultRotationalVelocityScaling = .5;

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleChat = function() {
        this._chat.toggle();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelf = function() {
        this._scripter.script(system.self);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.togglePropertyBox = function() {
        this._propertybox.TogglePropertyBox();
    };

    std.graphics.DefaultGraphics.prototype.setAxesInheritOrient = function(inheritOrient) {
        if (this._axesInheritOrient === inheritOrient) {
            return;
        }

        this._axesInheritOrient = inheritOrient;

        if (this._selected) {
            std.graphics.axes.setInheritOrientAll(this._selected, inheritOrient);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelectedObject = function() {
        if (this._selected == null)
            return;
        this._presenceList.addObject(this._selected.toString(), 'Scripted');
        this._scripter.script(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleCameraMode = function(evt) {
        var newmode = this._camera.mode() == 'first' ? 'third' : 'first';
        this._camera.setMode(newmode);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updateCameraOffset = function(evt) {
        if (this._camera.mode() == 'third') {
            var orient = this._pres.getOrientation();
            this._camera.setOffset(orient.mul(<0, 1.5, 4>));
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.moveSelf = function(dir, val) {
        this._moverot.move(dir, this.defaultVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.rotateSelf = function(about, name, val) {
        if (val) {
            this[name] = this._moverot.rotate(about, this.defaultRotationalVelocityScaling);
        }
        else {
            this._moverot.cancelRotate(this[name]);
            delete this[name];
        }
    };

    std.graphics.DefaultGraphics.prototype.turnOffAxis = function(x, y) {
        if (!this._selected) {
            return;
        }
        var axis = std.graphics.axes.pick(this._selected, x, y);
        if (axis < 0) {
            return;
        } else {
            std.graphics.axes.setVisible(this._selected, axis, false);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.pickObject = function(x, y)
    {
        var ignore_self = this._camera.mode() == 'first';
        var clicked = this._simulator.pick(x, y, ignore_self);
        if (clicked) {
            if (this._selected) {
                if (this._selected.toString() != clicked.toString()) {
                    if (!this._alreadyInitialized)
                    {
                        this._simulator.bbox(this._selected, false);
                        std.graphics.axes.setVisibleAll(this._selected, false);
                    }
                } else {
                    return;
                }
            }

            this._selected = clicked;
            if (!this._alreadyInitialized)
            {
                this._simulator.bbox(this._selected, true);
                std.graphics.axes.setInheritOrientAll(this._selected, this._axesInheritOrient);
                std.graphics.axes.setVisibleAll(this._selected, true);
            }
        } else if (this._selected) {
            if (!this._alreadyInitialized)
            {
                this._simulator.bbox(this._selected, false);
                std.graphics.axes.setVisibleAll(this._selected, false);
            }
            this._selected = null;
        }

    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.actOnObject = function(evt) {
        if (this._selected)
            { 'action' : 'touch' } >> this._selected >> [];
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.teleportToObj = function(evt) {
        if (this._selected) {
            var dir = this._selected.getPosition() - this._pres.getPosition();
            dir = dir.normal();
            var self = this;
            this._selected.loadMesh(function() {
                var hit = std.raytrace.raytrace(null, self._pres.getPosition(), dir, self._selected, null);
                if (hit) {
                    self._pres.setPosition(hit.sub(dir.scale(3)));
                } else {
                    self._pres.setPosition(this._selected.getPosition());
                }
                self._pres.setOrientation(util.Quaternion.fromLookAt(dir));
            });
        }
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePhysicsProperties = function() {
        // Update even if not selected so display can be disabled
        this._physics.update(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startDrag = function(dragger, evt) {
        if (this._selected)
            this._dragger = dragger;
        if (this._dragger)
            this._dragger.selected(this._selected, this._simulator.pickedPosition(), evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMousePressToDragger = function(evt) {
        if (this._dragger) this._dragger.onMousePress(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseDragToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseDrag(evt);
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePropertyBox = function(evt) {
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseReleaseToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseRelease(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.stopDrag = function() {
        delete this._dragger;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startFreeRotate = function(evt) {
        this.startX = evt.x;
        this.startY = evt.y;
        this.startOrientation = this._pres.getOrientation();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateDrag = function(evt) {
        if (this.startX == null || this.startY == null)
            return;

        var SCALE = 1;
        var dx = evt.x - this.startX;
        var dy = evt.y - this.startY;
        var dXAngle = dx * SCALE;
        var dYAngle = dy * SCALE;
        var newQuat = this.startOrientation
            .mul(new util.Quaternion(<0, 1, 0>, -dXAngle))
            .mul(new util.Quaternion(<1, 0, 0>, dYAngle));
        this._pres.setOrientation(newQuat);

        // Reorient self so up is up.
        this._pres.setOrientation(util.Quaternion.fromLookAt(
            this._pres.getOrientation().zAxis().scale(-1), <0, 1, 0>));
        this.updateCameraOffset();
        this._moverot.reeval();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateRelease = function(evt) {
        this.startX = null;
        this.startY = null;
        this.startOrientation = null;
    };

    std.graphics.DefaultGraphics.prototype.undo = function(evt) {
        this._simulator.undo();
    };

    std.graphics.DefaultGraphics.prototype.redo = function(evt) {
        this._simulator.redo();
    };

    std.graphics.DefaultGraphics.prototype.orientDefault = function(evt) {
        var vis = this._selected;
        if(!vis)
            return;
        var orient = vis.orientation;
        var movable = new std.movement.MovableRemote(vis);
        movable.setOrientation(new util.Quaternion());
        this._simulator.addUndoAction({}, {
            undo: function(action) {
                movable.setOrientation(orient);
            },
            redo: function(action) {
                movable.setOrientation(new util.Quaternion());
            }
        });
    };

    std.graphics.DefaultGraphics.prototype.setMaxObjects = function(maxobjs) {
        this._simulator.setMaxObjects(maxobjs);
    };

    std.graphics.DefaultGraphics.prototype.showFlatland = function (x, y) {
        var ignore_self = this._camera.mode() == 'first';
        var clicked = this._simulator.pick(x, y, ignore_self);
        this._flatland.show(clicked, x, y);
    };

    std.graphics.DefaultGraphics.prototype.hideFlatland = function () {
        this._flatland.hide();
    };

})();


Kill some dead code in Emerson nameService.

if (typeof(std.persist) === 'undefined')
    throw new Error('Error.  Do not import this file directly.  Only import it from persistService.em');

/*Create a separate namespace for name service;*/
std.persist.NameService = function()
{
    /**
     Keys are object references; values are unique integers
     ("names").
     */
    // var objectsToNames  =  {  };

    /**
     Keys are integers ("names") each unique to a single object.
     Values are object references
     */
    var namesToObjects  = {  };

    /**
     Keys are object references.  Values are single objects that
     contain the references and names for every object that is
     reachable from that object.  Not all objects that are stored in
     objectsToNames and namesToObjects will have entries in
     hierarchyMap.  Just those that were the roots for a request to
     persist.
     */
    var hierarchyMap    = {  };

     var whichNameOn = 0;

     /**
      Does Not Exist.
      Returned when maps calling lookup on do not have a record for
      the index searching for.
      */
     this.DNE = -99;

     /**
      Prints all objects that we're responsible for and their names
      */
     this.__debugPrint = function ()
     {
         system.print('\nPrinting in name service\'s debug print\n');
         for (var s in namesToObjects)
         {
             system.print('\n');
             system.print(s);
             system.print(namesToObjects[s]);
         }
         system.print('\nDone\n');
     };

     /**
      @param name to lookup.  (name will be an integer starting at
      zero).
      @returns if object exists, returns the object.  If it does not,
      returns DNE
      */
     this.lookupObject = function(name)
     {
         if (name in namesToObjects)
             return namesToObjects[name];

         return this.DNE;
     };

     /**
      @param obj to lookup name of.  (name will be an integer starting
      at zero).
      @returns if object exists, returns the object.  If it does not,
      returns DNE
      */
     this.lookupName = function (obj)
     {
         for (var s in namesToObjects)
         {
             if (obj == namesToObjects[s])
                 return s;
         }

         return this.DNE;
     };

      /**
       @param objToInsert into name service.
       @return Returns the name for the object.
       */
      this.insertObject = function (objToInsert)
      {
          var ind = this.lookupName(objToInsert);
          if (ind != this.DNE)
          {
              system.print('\nAlready had inserted object\n');
              return ind;
          }

          namesToObjects[whichNameOn] = objToInsert;
          return whichNameOn++;
      };

    /**
     @param objToInsert into name service
     @param nameToUse How to index into the new name in the service.

     Note.  If nameToUse is greater than or equal to which name to
     insert into next, we increase the value for which name to insert
     into next to avoid possible collisions.
     */
     this.insertObjectWithName = function (objToInsert,nameToUse)
     {
         namesToObjects[nameToUse]    = objToInsert;

         if (nameToUse >= whichNameOn)
             whichNameOn = nameToUse + 1;
     };

 };

if (typeof(std.persist) === 'undefined')
    throw new Error('Error.  Do not import this file directly.  Only import it from persistService.em');

/*Create a separate namespace for name service;*/
std.persist.NameService = function()
{
    /**
     Keys are object references; values are unique integers
     ("names").
     */
    // var objectsToNames  =  {  };

    /**
     Keys are integers ("names") each unique to a single object.
     Values are object references
     */
    var namesToObjects  = {  };

    /**
     Keys are object references.  Values are single objects that
     contain the references and names for every object that is
     reachable from that object.  Not all objects that are stored in
     objectsToNames and namesToObjects will have entries in
     hierarchyMap.  Just those that were the roots for a request to
     persist.
     */
    var hierarchyMap    = {  };

     var whichNameOn = 0;

     /**
      Does Not Exist.
      Returned when maps calling lookup on do not have a record for
      the index searching for.
      */
     this.DNE = -99;

     /**
      Prints all objects that we're responsible for and their names
      */
     this.__debugPrint = function ()
     {
         system.print('\nPrinting in name service\'s debug print\n');
         for (var s in namesToObjects)
         {
             system.print('\n');
             system.print(s);
             system.print(namesToObjects[s]);
         }
         system.print('\nDone\n');
     };

     /**
      @param name to lookup.  (name will be an integer starting at
      zero).
      @returns if object exists, returns the object.  If it does not,
      returns DNE
      */
     this.lookupObject = function(name)
     {
         if (name in namesToObjects)
             return namesToObjects[name];

         return this.DNE;
     };

     /**
      @param obj to lookup name of.  (name will be an integer starting
      at zero).
      @returns if object exists, returns the object.  If it does not,
      returns DNE
      */
     this.lookupName = function (obj)
     {
         for (var s in namesToObjects)
         {
             if (obj == namesToObjects[s])
                 return s;
         }

         return this.DNE;
     };

     /**
      @param objIndex object reference to index into hierarchyMap
      @param markedMap contains a map indexed on object references
      that point to all the names of objects that are marked
      @throw Throws an exception if the object that we're entering a
      markedMap for does not have an entry in objectsToNames.
      */
      this.enterSubtreeObjects = function (objIndex, markedMap)
      {
          if (this.lookupName(objIndex) == this.DNE)
              throw new Error('Error.  Not tracking this object in nameService when calling enterMarkedMap');

          hierarchyMap[objIndex] = markedMap; //marked map includes current object
      };

      /**
       Checks hierarchyMap to see if objIndex has an entry in it that
       contains all the objects that are in its subtree.  If it does,
       returns subtree.  If it does not, returns DNE.

       @param objIndex object refernce to index into hierarchyMap
       @returns DNE if have no record for objIndex in hierarchyMap.
       Returns a map containing all the object references (as keys) and
       names (as values) of the objects reachable from this object.
       */
     this.lookupSubtreeObjects = function(objIndex)
     {
         throw new Error('Error in lookupSubtreeObjects');
          if (objIndex in hierarchyMap)
              return hierarchyMap[objIndex];

          return this.DNE;
      };

      /**
       @param objToInsert into name service.
       @return Returns the name for the object.
       */
      this.insertObject = function (objToInsert)
      {
          var ind = this.lookupName(objToInsert);
          if (ind != this.DNE)
          {
              system.print('\nAlready had inserted object\n');
              return ind;
          }

          namesToObjects[whichNameOn] = objToInsert;
          return whichNameOn++;
      };

    /**
     @param objToInsert into name service
     @param nameToUse How to index into the new name in the service.

     Note.  If nameToUse is greater than or equal to which name to
     insert into next, we increase the value for which name to insert
     into next to avoid possible collisions.
     */
     this.insertObjectWithName = function (objToInsert,nameToUse)
     {
         namesToObjects[nameToUse]    = objToInsert;

         if (nameToUse >= whichNameOn)
             whichNameOn = nameToUse + 1;
     };

 };