Add profiling with Remotery

This commit is contained in:
David 2021-08-24 20:55:39 +02:00
commit 6331a2bf79
50 changed files with 16864 additions and 11 deletions

View file

@ -0,0 +1,131 @@
namespace("WM");
WM.Button = (function()
{
var template_html = "<div class='Button notextsel'></div>";
function Button(text, x, y, opts)
{
this.OnClick = null;
this.Toggle = opts && opts.toggle;
this.Node = DOM.Node.CreateHTML(template_html);
// Set node dimensions
this.SetPosition(x, y);
if (opts && opts.w && opts.h)
this.SetSize(opts.w, opts.h);
// Override the default class name
if (opts && opts.class)
this.Node.className = opts.class;
this.SetText(text);
// Create the mouse press event handlers
DOM.Event.AddHandler(this.Node, "mousedown", Bind(OnMouseDown, this));
this.OnMouseOutDelegate = Bind(OnMouseUp, this, false);
this.OnMouseUpDelegate = Bind(OnMouseUp, this, true);
}
Button.prototype.SetPosition = function(x, y)
{
this.Position = [ x, y ];
DOM.Node.SetPosition(this.Node, this.Position);
}
Button.prototype.SetSize = function(w, h)
{
this.Size = [ w, h ];
DOM.Node.SetSize(this.Node, this.Size);
}
Button.prototype.SetText = function(text)
{
this.Node.innerHTML = text;
}
Button.prototype.SetOnClick = function(on_click)
{
this.OnClick = on_click;
}
Button.prototype.SetState = function(pressed)
{
if (pressed)
DOM.Node.AddClass(this.Node, "ButtonHeld");
else
DOM.Node.RemoveClass(this.Node, "ButtonHeld");
}
Button.prototype.ToggleState = function()
{
if (DOM.Node.HasClass(this.Node, "ButtonHeld"))
this.SetState(false);
else
this.SetState(true);
}
Button.prototype.IsPressed = function()
{
return DOM.Node.HasClass(this.Node, "ButtonHeld");
}
function OnMouseDown(self, evt)
{
// Decide how to set the button state
if (self.Toggle)
self.ToggleState();
else
self.SetState(true);
// Activate release handlers
DOM.Event.AddHandler(self.Node, "mouseout", self.OnMouseOutDelegate);
DOM.Event.AddHandler(self.Node, "mouseup", self.OnMouseUpDelegate);
DOM.Event.StopAll(evt);
}
function OnMouseUp(self, confirm, evt)
{
if (confirm)
{
// Only release for non-toggles
if (!self.Toggle)
self.SetState(false);
}
else
{
// Decide how to set the button state
if (self.Toggle)
self.ToggleState();
else
self.SetState(false);
}
// Remove release handlers
DOM.Event.RemoveHandler(self.Node, "mouseout", self.OnMouseOutDelegate);
DOM.Event.RemoveHandler(self.Node, "mouseup", self.OnMouseUpDelegate);
// Call the click handler if this is a button press
if (confirm && self.OnClick)
self.OnClick(self);
DOM.Event.StopAll(evt);
}
return Button;
})();

View file

@ -0,0 +1,237 @@
namespace("WM");
WM.ComboBoxPopup = (function()
{
var body_template_html = "<div class='ComboBoxPopup'></div>";
var item_template_html = " \
<div class='ComboBoxPopupItem notextsel'> \
<div class='ComboBoxPopupItemText'></div> \
<div class='ComboBoxPopupItemIcon'><img src='BrowserLibImages/tick.gif'></div> \
<div style='clear:both'></div> \
</div>";
function ComboBoxPopup(combo_box)
{
this.ComboBox = combo_box;
this.ParentNode = combo_box.Node;
this.ValueNodes = [ ];
// Create the template node
this.Node = DOM.Node.CreateHTML(body_template_html);
DOM.Event.AddHandler(this.Node, "mousedown", Bind(SelectItem, this));
this.CancelDelegate = Bind(this, "Cancel");
}
ComboBoxPopup.prototype.SetValues = function(values)
{
// Clear existing values
this.Node.innerHTML = "";
// Generate HTML nodes for each value
this.ValueNodes = [ ];
for (var i in values)
{
var item_node = DOM.Node.CreateHTML(item_template_html);
var text_node = DOM.Node.FindWithClass(item_node, "ComboBoxPopupItemText");
item_node.Value = values[i];
text_node.innerHTML = values[i];
this.Node.appendChild(item_node);
this.ValueNodes.push(item_node);
}
}
ComboBoxPopup.prototype.Show = function(selection_index)
{
// Initially match the position of the parent node
var pos = DOM.Node.GetPosition(this.ParentNode);
DOM.Node.SetPosition(this.Node, pos);
// Take the width/z-index from the parent node
this.Node.style.width = this.ParentNode.offsetWidth;
this.Node.style.zIndex = this.ParentNode.style.zIndex + 1;
// Setup event handlers
DOM.Event.AddHandler(document.body, "mousedown", this.CancelDelegate);
// Show the popup so that the HTML layout engine kicks in before
// the layout info is used below
this.ParentNode.appendChild(this.Node);
// Show/hide the tick image based on which node is selected
for (var i in this.ValueNodes)
{
var node = this.ValueNodes[i];
var icon_node = DOM.Node.FindWithClass(node, "ComboBoxPopupItemIcon");
if (i == selection_index)
{
icon_node.style.display = "block";
// Also, shift the popup up so that the mouse is over the selected item and is highlighted
var item_pos = DOM.Node.GetPosition(this.ValueNodes[selection_index]);
var diff_pos = [ item_pos[0] - pos[0], item_pos[1] - pos[1] ];
pos = [ pos[0] - diff_pos[0], pos[1] - diff_pos[1] ];
}
else
{
icon_node.style.display = "none";
}
}
DOM.Node.SetPosition(this.Node, pos);
}
ComboBoxPopup.prototype.Hide = function()
{
DOM.Event.RemoveHandler(document.body, "mousedown", this.CancelDelegate);
this.ParentNode.removeChild(this.Node);
}
function SelectItem(self, evt)
{
// Search for which item node is being clicked on
var node = DOM.Event.GetNode(evt);
for (var i in self.ValueNodes)
{
var value_node = self.ValueNodes[i];
if (DOM.Node.Contains(node, value_node))
{
// Set the value on the combo box
self.ComboBox.SetValue(value_node.Value);
self.Hide();
break;
}
}
}
function Cancel(self, evt)
{
// Don't cancel if the mouse up is anywhere on the popup or combo box
var node = DOM.Event.GetNode(evt);
if (!DOM.Node.Contains(node, self.Node) &&
!DOM.Node.Contains(node, self.ParentNode))
{
self.Hide();
}
DOM.Event.StopAll(evt);
}
return ComboBoxPopup;
})();
WM.ComboBox = (function()
{
var template_html = " \
<div class='ComboBox'> \
<div class='ComboBoxText notextsel'></div> \
<div class='ComboBoxIcon'><img src='BrowserLibImages/up_down.gif'></div> \
<div style='clear:both'></div> \
</div>";
function ComboBox()
{
this.OnChange = null;
// Create the template node and locate key nodes
this.Node = DOM.Node.CreateHTML(template_html);
this.TextNode = DOM.Node.FindWithClass(this.Node, "ComboBoxText");
// Create a reusable popup
this.Popup = new WM.ComboBoxPopup(this);
// Set an empty set of values
this.SetValues([]);
this.SetValue("&lt;empty&gt;");
// Create the mouse press event handlers
DOM.Event.AddHandler(this.Node, "mousedown", Bind(OnMouseDown, this));
this.OnMouseOutDelegate = Bind(OnMouseUp, this, false);
this.OnMouseUpDelegate = Bind(OnMouseUp, this, true);
}
ComboBox.prototype.SetOnChange = function(on_change)
{
this.OnChange = on_change;
}
ComboBox.prototype.SetValues = function(values)
{
this.Values = values;
this.Popup.SetValues(values);
}
ComboBox.prototype.SetValue = function(value)
{
// Set the value and its HTML rep
var old_value = this.Value;
this.Value = value;
this.TextNode.innerHTML = value;
// Call change handler
if (this.OnChange)
this.OnChange(value, old_value);
}
ComboBox.prototype.GetValue = function()
{
return this.Value;
}
function OnMouseDown(self, evt)
{
// If this check isn't made, the click will trigger from the popup, too
var node = DOM.Event.GetNode(evt);
if (DOM.Node.Contains(node, self.Node))
{
// Add the depression class and activate release handlers
DOM.Node.AddClass(self.Node, "ComboBoxPressed");
DOM.Event.AddHandler(self.Node, "mouseout", self.OnMouseOutDelegate);
DOM.Event.AddHandler(self.Node, "mouseup", self.OnMouseUpDelegate);
DOM.Event.StopAll(evt);
}
}
function OnMouseUp(self, confirm, evt)
{
// Remove depression class and remove release handlers
DOM.Node.RemoveClass(self.Node, "ComboBoxPressed");
DOM.Event.RemoveHandler(self.Node, "mouseout", self.OnMouseOutDelegate);
DOM.Event.RemoveHandler(self.Node, "mouseup", self.OnMouseUpDelegate);
// If this is a confirmed press and there are some values in the list, show the popup
if (confirm && self.Values.length > 0)
{
var selection_index = self.Values.indexOf(self.Value);
self.Popup.Show(selection_index);
}
DOM.Event.StopAll(evt);
}
return ComboBox;
})();

View file

@ -0,0 +1,48 @@
namespace("WM");
WM.Container = (function()
{
var template_html = "<div class='Container'></div>";
function Container(x, y, w, h)
{
// Create a simple container node
this.Node = DOM.Node.CreateHTML(template_html);
this.SetPosition(x, y);
this.SetSize(w, h);
}
Container.prototype.SetPosition = function(x, y)
{
this.Position = [ x, y ];
DOM.Node.SetPosition(this.Node, this.Position);
}
Container.prototype.SetSize = function(w, h)
{
this.Size = [ w, h ];
DOM.Node.SetSize(this.Node, this.Size);
}
Container.prototype.AddControlNew = function(control)
{
control.ParentNode = this.Node;
this.Node.appendChild(control.Node);
return control;
}
Container.prototype.ClearControls = function()
{
this.Node.innerHTML = "";
}
return Container;
})();

View file

@ -0,0 +1,119 @@
namespace("WM");
WM.EditBox = (function()
{
var template_html = " \
<div class='EditBoxContainer'> \
<div class='EditBoxLabel'>Label</div> \
<input class='EditBox'> \
</div>";
function EditBox(x, y, w, h, label, text)
{
this.ChangeHandler = null;
// Create node and locate its internal nodes
this.Node = DOM.Node.CreateHTML(template_html);
this.LabelNode = DOM.Node.FindWithClass(this.Node, "EditBoxLabel");
this.EditNode = DOM.Node.FindWithClass(this.Node, "EditBox");
// Set label and value
this.LabelNode.innerHTML = label;
this.SetValue(text);
this.SetPosition(x, y);
this.SetSize(w, h);
this.PreviousValue = "";
// Hook up the event handlers
DOM.Event.AddHandler(this.EditNode, "focus", Bind(OnFocus, this));
DOM.Event.AddHandler(this.EditNode, "keypress", Bind(OnKeyPress, this));
DOM.Event.AddHandler(this.EditNode, "keydown", Bind(OnKeyDown, this));
}
EditBox.prototype.SetPosition = function(x, y)
{
this.Position = [ x, y ];
DOM.Node.SetPosition(this.Node, this.Position);
}
EditBox.prototype.SetSize = function(w, h)
{
this.Size = [ w, h ];
DOM.Node.SetSize(this.EditNode, this.Size);
}
EditBox.prototype.SetChangeHandler = function(handler)
{
this.ChangeHandler = handler;
}
EditBox.prototype.SetValue = function(value)
{
if (this.EditNode)
this.EditNode.value = value;
}
EditBox.prototype.GetValue = function()
{
if (this.EditNode)
return this.EditNode.value;
return null;
}
EditBox.prototype.LoseFocus = function()
{
if (this.EditNode)
this.EditNode.blur();
}
function OnFocus(self, evt)
{
// Backup on focus
self.PreviousValue = self.EditNode.value;
}
function OnKeyPress(self, evt)
{
// Allow enter to confirm the text only when there's data
if (evt.keyCode == 13 && self.EditNode.value != "" && self.ChangeHandler)
{
var focus = self.ChangeHandler(self.EditNode);
if (!focus)
self.EditNode.blur();
self.PreviousValue = "";
}
}
function OnKeyDown(self, evt)
{
// Allow escape to cancel any text changes
if (evt.keyCode == 27)
{
// On initial edit of the input, escape should NOT replace with the empty string
if (self.PreviousValue != "")
{
self.EditNode.value = self.PreviousValue;
}
self.EditNode.blur();
}
}
return EditBox;
})();

View file

@ -0,0 +1,248 @@
namespace("WM");
WM.GridRows = (function()
{
function GridRows(parent_object)
{
this.ParentObject = parent_object;
// Array of rows in the order they were added
this.Rows = [ ];
// Collection of custom row indexes for fast lookup
this.Indexes = { };
}
GridRows.prototype.AddIndex = function(cell_field_name)
{
var index = { };
// Go through existing rows and add to the index
for (var i in this.Rows)
{
var row = this.Rows[i];
if (cell_field_name in row.CellData)
{
var cell_field = row.CellData[cell_field_name];
index[cell_field] = row;
}
}
this.Indexes[cell_field_name] = index;
}
GridRows.prototype.ClearIndex = function(index_name)
{
this.Indexes[index_name] = { };
}
GridRows.prototype.AddRowToIndex = function(index_name, cell_data, row)
{
this.Indexes[index_name][cell_data] = row;
}
GridRows.prototype.Add = function(cell_data, row_classes, cell_classes)
{
var row = new WM.GridRow(this.ParentObject, cell_data, row_classes, cell_classes);
this.Rows.push(row);
return row;
}
GridRows.prototype.GetBy = function(cell_field_name, cell_data)
{
var index = this.Indexes[cell_field_name];
return index[cell_data];
}
GridRows.prototype.Clear = function()
{
// Remove all node references from the parent
for (var i in this.Rows)
{
var row = this.Rows[i];
row.Parent.BodyNode.removeChild(row.Node);
}
// Clear all indexes
for (var i in this.Indexes)
this.Indexes[i] = { };
this.Rows = [ ];
}
return GridRows;
})();
WM.GridRow = (function()
{
var template_html = "<div class='GridRow'></div>";
//
// 'cell_data' is an object with a variable number of fields.
// Any fields prefixed with an underscore are hidden.
//
function GridRow(parent, cell_data, row_classes, cell_classes)
{
// Setup data
this.Parent = parent;
this.IsOpen = true;
this.AnimHandle = null;
this.Rows = new WM.GridRows(this);
this.CellData = cell_data;
this.CellNodes = { }
// Create the main row node
this.Node = DOM.Node.CreateHTML(template_html);
if (row_classes)
DOM.Node.AddClass(this.Node, row_classes);
// Embed a pointer to the row in the root node so that it can be clicked
this.Node.GridRow = this;
// Create nodes for each required cell
for (var attr in this.CellData)
{
if (this.CellData.hasOwnProperty(attr))
{
var data = this.CellData[attr];
// Update any grid row index references
if (attr in parent.Rows.Indexes)
parent.Rows.AddRowToIndex(attr, data, this);
// Hide any cells with underscore prefixes
if (attr[0] == "_")
continue;
// Create a node for the cell and add any custom classes
var node = DOM.Node.AppendHTML(this.Node, "<div class='GridRowCell'></div>");
if (cell_classes && attr in cell_classes)
DOM.Node.AddClass(node, cell_classes[attr]);
this.CellNodes[attr] = node;
// If this is a Window Control, add its node to the cell
if (data instanceof Object && "Node" in data && DOM.Node.IsNode(data.Node))
{
data.ParentNode = node;
node.appendChild(data.Node);
}
else
{
// Otherwise just assign the data as text
node.innerHTML = data;
}
}
}
// Add the body node for any children
if (!this.Parent.BodyNode)
this.Parent.BodyNode = DOM.Node.AppendHTML(this.Parent.Node, "<div class='GridRowBody'></div>");
// Add the row to the parent
this.Parent.BodyNode.appendChild(this.Node);
}
GridRow.prototype.Open = function()
{
// Don't allow open while animating
if (this.AnimHandle == null || this.AnimHandle.Complete)
{
this.IsOpen = true;
// Kick off open animation
var node = this.BodyNode;
this.AnimHandle = Anim.Animate(
function (val) { DOM.Node.SetHeight(node, val) },
0, this.Height, 0.2);
}
}
GridRow.prototype.Close = function()
{
// Don't allow close while animating
if (this.AnimHandle == null || this.AnimHandle.Complete)
{
this.IsOpen = false;
// Record height for the next open request
this.Height = this.BodyNode.offsetHeight;
// Kick off close animation
var node = this.BodyNode;
this.AnimHandle = Anim.Animate(
function (val) { DOM.Node.SetHeight(node, val) },
this.Height, 0, 0.2);
}
}
GridRow.prototype.Toggle = function()
{
if (this.IsOpen)
this.Close();
else
this.Open();
}
return GridRow;
})();
WM.Grid = (function()
{
var template_html = " \
<div class='Grid'> \
<div class='GridBody'></div> \
</div>";
function Grid()
{
this.Rows = new WM.GridRows(this);
this.Node = DOM.Node.CreateHTML(template_html);
this.BodyNode = DOM.Node.FindWithClass(this.Node, "GridBody");
DOM.Event.AddHandler(this.Node, "dblclick", OnDblClick);
var mouse_wheel_event = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
DOM.Event.AddHandler(this.Node, mouse_wheel_event, Bind(OnMouseScroll, this));
}
function OnDblClick(evt)
{
// Clicked on a header?
var node = DOM.Event.GetNode(evt);
if (DOM.Node.HasClass(node, "GridRowName"))
{
// Toggle rows open/close
var row = node.parentNode.GridRow;
if (row)
row.Toggle();
}
}
function OnMouseScroll(self, evt)
{
var mouse_state = new Mouse.State(evt);
self.Node.scrollTop -= mouse_state.WheelDelta * 20;
}
return Grid;
})();

View file

@ -0,0 +1,31 @@
namespace("WM");
WM.Label = (function()
{
var template_html = "<div class='Label'></div>";
function Label(x, y, text)
{
// Create the node
this.Node = DOM.Node.CreateHTML(template_html);
// Allow position to be optional
if (x != null && y != null)
DOM.Node.SetPosition(this.Node, [x, y]);
this.SetText(text);
}
Label.prototype.SetText = function(text)
{
if (text != null)
this.Node.innerHTML = text;
}
return Label;
})();

View file

@ -0,0 +1,352 @@
namespace("WM");
WM.Treeview = (function()
{
var Margin = 10;
var tree_template_html = " \
<div class='Treeview'> \
<div class='TreeviewItemChildren' style='width:90%;float:left'></div> \
<div class='TreeviewScrollbarInset'> \
<div class='TreeviewScrollbar'></div> \
</div> \
<div style='clear:both'></div> \
</div>";
var item_template_html = " \
<div class='TreeViewItem basicfont notextsel'> \
<img src='' class='TreeviewItemImage'> \
<div class='TreeviewItemText'></div> \
<div style='clear:both'></div> \
<div class='TreeviewItemChildren'></div> \
<div style='clear:both'></div> \
</div>";
// TODO: Remove parent_node (required for stuff that doesn't use the WM yet)
function Treeview(x, y, width, height, parent_node)
{
// Cache initialisation options
this.ParentNode = parent_node;
this.Position = [ x, y ];
this.Size = [ width, height ];
this.Node = null;
this.ScrollbarNode = null;
this.SelectedItem = null;
this.ContentsNode = null;
// Setup options
this.HighlightOnHover = false;
this.EnableScrollbar = true;
this.HorizontalLayoutDepth = 1;
// Generate an empty tree
this.Clear();
}
Treeview.prototype.SetHighlightOnHover = function(highlight)
{
this.HighlightOnHover = highlight;
}
Treeview.prototype.SetEnableScrollbar = function(enable)
{
this.EnableScrollbar = enable;
}
Treeview.prototype.SetHorizontalLayoutDepth = function(depth)
{
this.HorizontalLayoutDepth = depth;
}
Treeview.prototype.SetNodeSelectedHandler = function(handler)
{
this.NodeSelectedHandler = handler;
}
Treeview.prototype.Clear = function()
{
this.RootItem = new WM.TreeviewItem(this, null, null, null, null);
this.GenerateHTML();
}
Treeview.prototype.Root = function()
{
return this.RootItem;
}
Treeview.prototype.ClearSelection = function()
{
if (this.SelectedItem != null)
{
DOM.Node.RemoveClass(this.SelectedItem.Node, "TreeviewItemSelected");
this.SelectedItem = null;
}
}
Treeview.prototype.SelectItem = function(item, mouse_pos)
{
// Notify the select handler
if (this.NodeSelectedHandler)
this.NodeSelectedHandler(item.Node, this.SelectedItem, item, mouse_pos);
// Remove highlight from the old selection
this.ClearSelection();
// Swap in new selection and apply highlight
this.SelectedItem = item;
DOM.Node.AddClass(this.SelectedItem.Node, "TreeviewItemSelected");
}
Treeview.prototype.GenerateHTML = function()
{
// Clone the template and locate important nodes
var old_node = this.Node;
this.Node = DOM.Node.CreateHTML(tree_template_html);
this.ChildrenNode = DOM.Node.FindWithClass(this.Node, "TreeviewItemChildren");
this.ScrollbarNode = DOM.Node.FindWithClass(this.Node, "TreeviewScrollbar");
DOM.Node.SetPosition(this.Node, this.Position);
DOM.Node.SetSize(this.Node, this.Size);
// Generate the contents of the treeview
GenerateTree(this, this.ChildrenNode, this.RootItem.Children, 0);
// Cross-browser (?) means of adding a mouse wheel handler
var mouse_wheel_event = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
DOM.Event.AddHandler(this.Node, mouse_wheel_event, Bind(OnMouseScroll, this));
DOM.Event.AddHandler(this.Node, "dblclick", Bind(OnMouseDoubleClick, this));
DOM.Event.AddHandler(this.Node, "mousedown", Bind(OnMouseDown, this));
DOM.Event.AddHandler(this.Node, "mouseup", OnMouseUp);
// Swap in the newly generated control node if it's already been attached to a parent
if (old_node && old_node.parentNode)
{
old_node.parentNode.removeChild(old_node);
this.ParentNode.appendChild(this.Node);
}
if (this.EnableScrollbar)
{
this.UpdateScrollbar();
DOM.Event.AddHandler(this.ScrollbarNode, "mousedown", Bind(OnMouseDown_Scrollbar, this));
DOM.Event.AddHandler(this.ScrollbarNode, "mouseup", Bind(OnMouseUp_Scrollbar, this));
DOM.Event.AddHandler(this.ScrollbarNode, "mouseout", Bind(OnMouseUp_Scrollbar, this));
DOM.Event.AddHandler(this.ScrollbarNode, "mousemove", Bind(OnMouseMove_Scrollbar, this));
}
else
{
DOM.Node.Hide(DOM.Node.FindWithClass(this.Node, "TreeviewScrollbarInset"));
}
}
Treeview.prototype.UpdateScrollbar = function()
{
if (!this.EnableScrollbar)
return;
var scrollbar_scale = Math.min((this.Node.offsetHeight - Margin * 2) / this.ChildrenNode.offsetHeight, 1);
this.ScrollbarNode.style.height = parseInt(scrollbar_scale * 100) + "%";
// Shift the scrollbar container along with the parent window
this.ScrollbarNode.parentNode.style.top = this.Node.scrollTop;
var scroll_fraction = this.Node.scrollTop / (this.Node.scrollHeight - this.Node.offsetHeight);
var max_height = this.Node.offsetHeight - Margin;
var max_scrollbar_offset = max_height - this.ScrollbarNode.offsetHeight;
var scrollbar_offset = scroll_fraction * max_scrollbar_offset;
this.ScrollbarNode.style.top = scrollbar_offset;
}
function GenerateTree(self, parent_node, items, depth)
{
if (items.length == 0)
return null;
for (var i in items)
{
var item = items[i];
// Create the node for this item and locate important nodes
var node = DOM.Node.CreateHTML(item_template_html);
var img = DOM.Node.FindWithClass(node, "TreeviewItemImage");
var text = DOM.Node.FindWithClass(node, "TreeviewItemText");
var children = DOM.Node.FindWithClass(node, "TreeviewItemChildren");
// Attach the item to the node
node.TreeviewItem = item;
item.Node = node;
// Add the class which highlights selection on hover
if (self.HighlightOnHover)
DOM.Node.AddClass(node, "TreeviewItemHover");
// Instruct the children to wrap around
if (depth >= self.HorizontalLayoutDepth)
node.style.cssFloat = "left";
if (item.OpenImage == null || item.CloseImage == null)
{
// If there no images, remove the image node
node.removeChild(img);
}
else
{
// Set the image source to open
img.src = item.OpenImage.src;
img.style.width = item.OpenImage.width;
img.style.height = item.OpenImage.height;
item.ImageNode = img;
}
// Setup the text to display
text.innerHTML = item.Label;
// Add the div to the parent and recurse into children
parent_node.appendChild(node);
GenerateTree(self, children, item.Children, depth + 1);
item.ChildrenNode = children;
}
// Clear the wrap-around
if (depth >= self.HorizontalLayoutDepth)
DOM.Node.AppendClearFloat(parent_node.parentNode);
}
function OnMouseScroll(self, evt)
{
// Get mouse wheel movement
var delta = evt.detail ? evt.detail * -1 : evt.wheelDelta;
delta *= 8;
// Scroll the main window with wheel movement and clamp
self.Node.scrollTop -= delta;
self.Node.scrollTop = Math.min(self.Node.scrollTop, (self.ChildrenNode.offsetHeight - self.Node.offsetHeight) + Margin * 2);
self.UpdateScrollbar();
}
function OnMouseDoubleClick(self, evt)
{
DOM.Event.StopDefaultAction(evt);
// Get the tree view item being clicked, if any
var node = DOM.Event.GetNode(evt);
var tvitem = GetTreeviewItemFromNode(self, node);
if (tvitem == null)
return;
if (tvitem.Children.length)
tvitem.Toggle();
}
function OnMouseDown(self, evt)
{
DOM.Event.StopDefaultAction(evt);
// Get the tree view item being clicked, if any
var node = DOM.Event.GetNode(evt);
var tvitem = GetTreeviewItemFromNode(self, node);
if (tvitem == null)
return;
// If clicking on the image, expand any children
if (node.tagName == "IMG" && tvitem.Children.length)
{
tvitem.Toggle();
}
else
{
var mouse_pos = DOM.Event.GetMousePosition(evt);
self.SelectItem(tvitem, mouse_pos);
}
}
function OnMouseUp(evt)
{
// Event handler used merely to stop events bubbling up to containers
DOM.Event.StopPropagation(evt);
}
function OnMouseDown_Scrollbar(self, evt)
{
self.ScrollbarHeld = true;
// Cache the mouse height relative to the scrollbar
self.LastY = evt.clientY;
self.ScrollY = self.Node.scrollTop;
DOM.Node.AddClass(self.ScrollbarNode, "TreeviewScrollbarHeld");
DOM.Event.StopDefaultAction(evt);
}
function OnMouseUp_Scrollbar(self, evt)
{
self.ScrollbarHeld = false;
DOM.Node.RemoveClass(self.ScrollbarNode, "TreeviewScrollbarHeld");
}
function OnMouseMove_Scrollbar(self, evt)
{
if (self.ScrollbarHeld)
{
var delta_y = evt.clientY - self.LastY;
self.LastY = evt.clientY;
var max_height = self.Node.offsetHeight - Margin;
var max_scrollbar_offset = max_height - self.ScrollbarNode.offsetHeight;
var max_contents_scroll = self.Node.scrollHeight - self.Node.offsetHeight;
var scale = max_contents_scroll / max_scrollbar_offset;
// Increment the local float variable and assign, as scrollTop is of type int
self.ScrollY += delta_y * scale;
self.Node.scrollTop = self.ScrollY;
self.Node.scrollTop = Math.min(self.Node.scrollTop, (self.ChildrenNode.offsetHeight - self.Node.offsetHeight) + Margin * 2);
self.UpdateScrollbar();
}
}
function GetTreeviewItemFromNode(self, node)
{
// Walk up toward the tree view node looking for this first item
while (node && node != self.Node)
{
if ("TreeviewItem" in node)
return node.TreeviewItem;
node = node.parentNode;
}
return null;
}
return Treeview;
})();

View file

@ -0,0 +1,109 @@
namespace("WM");
WM.TreeviewItem = (function()
{
function TreeviewItem(treeview, name, data, open_image, close_image)
{
// Assign members
this.Treeview = treeview;
this.Label = name;
this.Data = data;
this.OpenImage = open_image;
this.CloseImage = close_image;
this.Children = [ ];
// The HTML node wrapping the item and its children
this.Node = null;
// The HTML node storing the image for the open/close state feedback
this.ImageNode = null;
// The HTML node storing just the children
this.ChildrenNode = null;
// Animation handle for opening and closing the child nodes, only used
// if the tree view item as children
this.AnimHandle = null;
// Open state of the item
this.IsOpen = true;
}
TreeviewItem.prototype.AddItem = function(name, data, open_image, close_image)
{
var item = new WM.TreeviewItem(this.Treeview, name, data, open_image, close_image);
this.Children.push(item);
return item;
}
TreeviewItem.prototype.Open = function()
{
if (this.AnimHandle == null || this.AnimHandle.Complete)
{
// Swap to the open state
this.IsOpen = true;
if (this.ImageNode != null && this.OpenImage != null)
this.ImageNode.src = this.OpenImage.src;
// Cache for closure binding
var child_node = this.ChildrenNode;
var end_height = this.StartHeight;
var treeview = this.Treeview;
// Reveal the children and animate their height to max
this.ChildrenNode.style.display = "block";
this.AnimHandle = Anim.Animate(
function (val) { DOM.Node.SetHeight(child_node, val) },
0, end_height, 0.2,
function() { treeview.UpdateScrollbar(); });
// Fade the children in
Anim.Animate(function(val) { DOM.Node.SetOpacity(child_node, val) }, 0, 1, 0.2);
}
}
TreeviewItem.prototype.Close = function()
{
if (this.AnimHandle == null || this.AnimHandle.Complete)
{
// Swap to the close state
this.IsOpen = false;
if (this.ImageNode != null && this.CloseImage != null)
this.ImageNode.src = this.CloseImage.src;
// Cache for closure binding
var child_node = this.ChildrenNode;
var treeview = this.Treeview;
// Mark the height of the item for reload later
this.StartHeight = child_node.offsetHeight;
// Shrink the height of the children and hide them upon completion
this.AnimHandle = Anim.Animate(
function (val) { DOM.Node.SetHeight(child_node, val) },
this.ChildrenNode.offsetHeight, 0, 0.2,
function() { child_node.style.display = "none"; treeview.UpdateScrollbar(); });
// Fade the children out
Anim.Animate(function(val) { DOM.Node.SetOpacity(child_node, val) }, 1, 0, 0.2);
}
}
TreeviewItem.prototype.Toggle = function()
{
if (this.IsOpen)
this.Close();
else
this.Open();
}
return TreeviewItem;
})();

View file

@ -0,0 +1,314 @@
namespace("WM");
WM.Window = (function()
{
var template_html = multiline(function(){/* \
<div class='Window'>
<div class='WindowTitleBar'>
<div class='WindowTitleBarText notextsel' style='float:left'>Window Title Bar</div>
<div class='WindowTitleBarClose notextsel' style='float:right'>&#10005;</div>
</div>
<div class='WindowBody'>
</div>
<div class='WindowResizeHandle notextsel'>&#8944;</div>
</div>
*/});
function Window(manager, title, x, y, width, height, parent_node)
{
this.Manager = manager;
this.ParentNode = parent_node || document.body;
this.OnMove = null;
this.OnResize = null;
this.Visible = false;
this.AnimatedShow = false;
// Clone the window template and locate key nodes within it
this.Node = DOM.Node.CreateHTML(template_html);
this.TitleBarNode = DOM.Node.FindWithClass(this.Node, "WindowTitleBar");
this.TitleBarTextNode = DOM.Node.FindWithClass(this.Node, "WindowTitleBarText");
this.TitleBarCloseNode = DOM.Node.FindWithClass(this.Node, "WindowTitleBarClose");
this.ResizeHandleNode = DOM.Node.FindWithClass(this.Node, "WindowResizeHandle");
this.BodyNode = DOM.Node.FindWithClass(this.Node, "WindowBody");
// Setup the position and dimensions of the window
this.SetPosition(x, y);
this.SetSize(width, height);
// Set the title text
this.TitleBarTextNode.innerHTML = title;
// Hook up event handlers
DOM.Event.AddHandler(this.Node, "mousedown", Bind(this, "SetTop"));
DOM.Event.AddHandler(this.TitleBarNode, "mousedown", Bind(this, "BeginMove"));
DOM.Event.AddHandler(this.ResizeHandleNode, "mousedown", Bind(this, "BeginResize"));
DOM.Event.AddHandler(this.TitleBarCloseNode, "mouseup", Bind(this, "Hide"));
// Create delegates for removable handlers
this.MoveDelegate = Bind(this, "Move");
this.EndMoveDelegate = Bind(this, "EndMove")
this.ResizeDelegate = Bind(this, "Resize");
this.EndResizeDelegate = Bind(this, "EndResize");
}
Window.prototype.SetOnMove = function(on_move)
{
this.OnMove = on_move;
}
Window.prototype.SetOnResize = function(on_resize)
{
this.OnResize = on_resize;
}
Window.prototype.Show = function()
{
if (this.Node.parentNode != this.ParentNode)
{
this.ShowNoAnim();
Anim.Animate(Bind(this, "OpenAnimation"), 0, 1, 1);
}
}
Window.prototype.ShowNoAnim = function()
{
// Add to the document
this.ParentNode.appendChild(this.Node);
this.AnimatedShow = false;
this.Visible = true;
}
Window.prototype.Hide = function(evt)
{
if (this.Node.parentNode == this.ParentNode && evt.button == 0)
{
if (this.AnimatedShow)
{
// Trigger animation that ends with removing the window from the document
Anim.Animate(
Bind(this, "CloseAnimation"),
0, 1, 0.25,
Bind(this, "HideNoAnim"));
}
else
{
this.HideNoAnim();
}
}
}
Window.prototype.HideNoAnim = function()
{
if (this.Node.parentNode == this.ParentNode)
{
// Remove node
this.ParentNode.removeChild(this.Node);
this.Visible = false;
}
}
Window.prototype.Close = function()
{
this.HideNoAnim();
this.Manager.RemoveWindow(this);
}
Window.prototype.SetTop = function()
{
this.Manager.SetTopWindow(this);
}
Window.prototype.SetTitle = function(title)
{
this.TitleBarTextNode.innerHTML = title;
}
// TODO: Update this
Window.prototype.AddControl = function(control)
{
// Get all arguments to this function and replace the first with this window node
var args = [].slice.call(arguments);
args[0] = this.BodyNode;
// Create the control and call its Init method with the modified arguments
var instance = new control();
instance.Init.apply(instance, args);
return instance;
}
Window.prototype.AddControlNew = function(control)
{
control.ParentNode = this.BodyNode;
this.BodyNode.appendChild(control.Node);
return control;
}
Window.prototype.RemoveControl = function(control)
{
if (control.ParentNode == this.BodyNode)
{
control.ParentNode.removeChild(control.Node);
}
}
Window.prototype.Scale = function(t)
{
// Calculate window bounds centre/extents
var ext_x = this.Size[0] / 2;
var ext_y = this.Size[1] / 2;
var mid_x = this.Position[0] + ext_x;
var mid_y = this.Position[1] + ext_y;
// Scale from the mid-point
DOM.Node.SetPosition(this.Node, [ mid_x - ext_x * t, mid_y - ext_y * t ]);
DOM.Node.SetSize(this.Node, [ this.Size[0] * t, this.Size[1] * t ]);
}
Window.prototype.OpenAnimation = function(val)
{
// Power ease in
var t = 1 - Math.pow(1 - val, 8);
this.Scale(t);
DOM.Node.SetOpacity(this.Node, 1 - Math.pow(1 - val, 8));
this.AnimatedShow = true;
}
Window.prototype.CloseAnimation = function(val)
{
// Power ease out
var t = 1 - Math.pow(val, 4);
this.Scale(t);
DOM.Node.SetOpacity(this.Node, t);
}
Window.prototype.NotifyChange = function()
{
if (this.OnMove)
{
var pos = DOM.Node.GetPosition(this.Node);
this.OnMove(this, pos);
}
}
Window.prototype.BeginMove = function(evt)
{
// Calculate offset of the window from the mouse down position
var mouse_pos = DOM.Event.GetMousePosition(evt);
this.Offset = [ mouse_pos[0] - this.Position[0], mouse_pos[1] - this.Position[1] ];
// Dynamically add handlers for movement and release
DOM.Event.AddHandler(document, "mousemove", this.MoveDelegate);
DOM.Event.AddHandler(document, "mouseup", this.EndMoveDelegate);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.Move = function(evt)
{
// Use the offset at the beginning of movement to drag the window around
var mouse_pos = DOM.Event.GetMousePosition(evt);
var offset = this.Offset;
var pos = [ mouse_pos[0] - offset[0], mouse_pos[1] - offset[1] ];
this.SetPosition(pos[0], pos[1]);
if (this.OnMove)
this.OnMove(this, pos);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.EndMove = function(evt)
{
// Remove handlers added during mouse down
DOM.Event.RemoveHandler(document, "mousemove", this.MoveDelegate);
DOM.Event.RemoveHandler(document, "mouseup", this.EndMoveDelegate);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.BeginResize = function(evt)
{
// Calculate offset of the window from the mouse down position
var mouse_pos = DOM.Event.GetMousePosition(evt);
this.MousePosBeforeResize = [ mouse_pos[0], mouse_pos[1] ];
this.SizeBeforeResize = this.Size;
// Dynamically add handlers for movement and release
DOM.Event.AddHandler(document, "mousemove", this.ResizeDelegate);
DOM.Event.AddHandler(document, "mouseup", this.EndResizeDelegate);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.Resize = function(evt)
{
// Use the offset at the beginning of movement to drag the window around
var mouse_pos = DOM.Event.GetMousePosition(evt);
var offset = [ mouse_pos[0] - this.MousePosBeforeResize[0], mouse_pos[1] - this.MousePosBeforeResize[1] ];
this.SetSize(this.SizeBeforeResize[0] + offset[0], this.SizeBeforeResize[1] + offset[1]);
if (this.OnResize)
this.OnResize(this, this.Size);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.EndResize = function(evt)
{
// Remove handlers added during mouse down
DOM.Event.RemoveHandler(document, "mousemove", this.ResizeDelegate);
DOM.Event.RemoveHandler(document, "mouseup", this.EndResizeDelegate);
DOM.Event.StopDefaultAction(evt);
}
Window.prototype.SetPosition = function(x, y)
{
this.Position = [ x, y ];
DOM.Node.SetPosition(this.Node, this.Position);
}
Window.prototype.SetSize = function(w, h)
{
w = Math.max(80, w);
h = Math.max(15, h);
this.Size = [ w, h ];
DOM.Node.SetSize(this.Node, this.Size);
}
Window.prototype.GetZIndex = function()
{
return parseInt(this.Node.style.zIndex);
}
return Window;
})();

View file

@ -0,0 +1,65 @@
namespace("WM");
WM.WindowManager = (function()
{
function WindowManager()
{
// An empty list of windows under window manager control
this.Windows = [ ];
}
WindowManager.prototype.AddWindow = function(title, x, y, width, height, parent_node)
{
// Create the window and add it to the list of windows
var wnd = new WM.Window(this, title, x, y, width, height, parent_node);
this.Windows.push(wnd);
// Always bring to the top on creation
wnd.SetTop();
return wnd;
}
WindowManager.prototype.RemoveWindow = function(window)
{
// Remove from managed window list
var index = this.Windows.indexOf(window);
if (index != -1)
{
this.Windows.splice(index, 1);
}
}
WindowManager.prototype.SetTopWindow = function(top_wnd)
{
// Bring the window to the top of the window list
var top_wnd_index = this.Windows.indexOf(top_wnd);
if (top_wnd_index != -1)
this.Windows.splice(top_wnd_index, 1);
this.Windows.push(top_wnd);
// Set a CSS z-index for each visible window from the bottom up
for (var i in this.Windows)
{
var wnd = this.Windows[i];
if (!wnd.Visible)
continue;
// Ensure there's space between each window for the elements inside to be sorted
var z = (parseInt(i) + 1) * 10;
wnd.Node.style.zIndex = z;
// Notify window that its z-order has changed
wnd.NotifyChange();
}
}
return WindowManager;
})();

View file

@ -0,0 +1,652 @@
.notextsel
{
/* Disable text selection so that it doesn't interfere with button-clicking */
user-select: none;
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer */
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
-webkit-user-select: none; /* Chrome, Safari, and Opera */
-webkit-touch-callout: none; /* Disable Android and iOS callouts*/
/* Stops the text cursor over the label */
cursor:default;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Window Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
body
{
/* Clip contents to browser window without adding scrollbars */
overflow: hidden;
}
.Window
{
position:absolute;
/* Clip all contents to the window border */
overflow: hidden;
background: #555;
/*padding: 0px !important;*/
border-radius: 3px;
-moz-border-radius: 5px;
-webkit-box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
}
/*:root
{
--SideBarSize: 5px;
}
.WindowBodyDebug
{
color: #BBB;
font: 9px Verdana;
white-space: nowrap;
}
.WindowSizeLeft
{
position: absolute;
left: 0px;
top: 0px;
width: var(--SideBarSize);
height: 100%;
}
.WindowSizeRight
{
position: absolute;
left: calc(100% - var(--SideBarSize));
top:0px;
width: var(--SideBarSize);
height:100%;
}
.WindowSizeTop
{
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: var(--SideBarSize);
}
.WindowSizeBottom
{
position: absolute;
left: 0px;
top: calc(100% - var(--SideBarSize));
width: 100%;
height: var(--SideBarSize);
}*/
.Window_Transparent
{
/* Set transparency changes to fade in/out */
opacity: 0.5;
transition: opacity 0.5s ease-out;
-moz-transition: opacity 0.5s ease-out;
-webkit-transition: opacity 0.5s ease-out;
}
.Window_Transparent:hover
{
opacity: 1;
}
.WindowTitleBar
{
height: 17px;
cursor: move;
/*overflow: hidden;*/
border-bottom: 1px solid #303030;
border-radius: 5px;
}
.WindowTitleBarText
{
color: #BBB;
font: 9px Verdana;
/*white-space: nowrap;*/
padding: 3px;
cursor: move;
}
.WindowTitleBarClose
{
color: #999999;
font: 9px Verdana;
padding: 3px;
cursor: default;
}
.WindowTitleBarClose:hover {
color: #bbb;
}
.WindowResizeHandle
{
color: #999999;
font: 17px Verdana;
padding: 3px;
cursor: se-resize;
position: absolute;
bottom: -7px;
right: -3px;
}
.WindowBody {
position: absolute;
/* overflow: hidden; */
display: block;
padding: 10px;
border-top: 1px solid #606060;
top: 18px;
left: 0;
right: 0;
bottom: 0;
height: auto;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Container Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.Container
{
/* Position relative to the parent window */
position: absolute;
/* Clip contents */
/*overflow: hidden;*/
background:#2C2C2C;
border: 1px black solid;
/* Two inset box shadows to simulate depressing */
-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
}
/*.Panel
{*/
/* Position relative to the parent window */
/*position: absolute;*/
/* Clip contents */
/*overflow: hidden;
background:#2C2C2C;
border: 1px black solid;*/
/* Two inset box shadows to simulate depressing */
/*-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;*/
/*}*/
/* ------------------------------------------------------------------------------------------------------------------ */
/* Ruler Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
/*.Ruler
{
position: absolute;
border: dashed 1px;
opacity: 0.35;
}*/
/* ------------------------------------------------------------------------------------------------------------------ */
/* Treeview Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.Treeview
{
position: absolute;
background:#2C2C2C;
border: 1px solid black;
overflow:hidden;
/* Two inset box shadows to simulate depressing */
-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
}
.TreeviewItem
{
margin:1px;
padding:2px;
border:solid 1px #2C2C2C;
background-color:#2C2C2C;
}
.TreeviewItemImage
{
float: left;
}
.TreeviewItemText
{
float: left;
margin-left:4px;
}
.TreeviewItemChildren
{
overflow: hidden;
}
.TreeviewItemSelected
{
background-color:#444;
border-color:#FFF;
-webkit-transition: background-color 0.2s ease-in-out;
-moz-transition: background-color 0.2s ease-in-out;
-webkit-transition: border-color 0.2s ease-in-out;
-moz-transition: border-color 0.2s ease-in-out;
}
/* Used to populate treeviews that want highlight on hover behaviour */
.TreeviewItemHover
{
}
.TreeviewItemHover:hover
{
background-color:#111;
border-color:#444;
-webkit-transition: background-color 0.2s ease-in-out;
-moz-transition: background-color 0.2s ease-in-out;
-webkit-transition: border-color 0.2s ease-in-out;
-moz-transition: border-color 0.2s ease-in-out;
}
.TreeviewScrollbarInset
{
float: right;
position:relative;
height: 100%;
/* CRAZINESS PART A: Trying to get the inset and scrollbar to have 100% height match its container */
margin: -8px -8px 0 0;
padding: 0 1px 14px 1px;
width:20px;
background:#2C2C2C;
border: 1px solid black;
/* Two inset box shadows to simulate depressing */
-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
}
.TreeviewScrollbar
{
position:relative;
background:#2C2C2C;
border: 1px solid black;
/* CRAZINESS PART B: Trying to get the inset and scrollbar to have 100% height match its container */
padding: 0 0 10px 0;
margin: 1px 0 0 0;
width: 18px;
height: 100%;
border-radius:6px;
border-color:#000;
border-width:1px;
border-style:solid;
/* The gradient for the button background */
background-color:#666;
background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#383838));
background: -moz-linear-gradient(top, #666, #383838);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#383838');
/* A box shadow and inset box highlight */
-webkit-box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
}
.TreeviewScrollbarHeld
{
/* Reset the gradient to a full-colour background */
background:#383838;
/* Two inset box shadows to simulate depressing */
-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Edit Box Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.EditBoxContainer
{
position: absolute;
padding:2px 10px 2px 10px;
}
.EditBoxLabel
{
float:left;
padding: 3px 4px 4px 4px;
font: 9px Verdana;
}
.EditBox
{
float:left;
background:#666;
border: 1px solid;
border-radius: 6px;
padding: 3px 4px 3px 4px;
height: 20px;
box-shadow: 1px 1px 1px #222 inset;
transition: all 0.3s ease-in-out;
}
.EditBox:focus
{
background:#FFF;
outline:0;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Label Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.Label
{
/* Position relative to the parent window */
position:absolute;
color: #BBB;
font: 9px Verdana;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Combo Box Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.ComboBox
{
position:absolute;
/* TEMP! */
width:90px;
/* Height is fixed to match the font */
height:14px;
/* Align the text within the combo box */
padding: 1px 0 0 5px;
/* Solid, rounded border */
border: 1px solid #111;
border-radius: 5px;
/* http://www.colorzilla.com/gradient-editor/#e3e3e3+0,c6c6c6+22,b7b7b7+33,afafaf+50,a7a7a7+67,797979+82,414141+100;Custom */
background: #e3e3e3;
background: -moz-linear-gradient(top, #e3e3e3 0%, #c6c6c6 22%, #b7b7b7 33%, #afafaf 50%, #a7a7a7 67%, #797979 82%, #414141 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#e3e3e3), color-stop(22%,#c6c6c6), color-stop(33%,#b7b7b7), color-stop(50%,#afafaf), color-stop(67%,#a7a7a7), color-stop(82%,#797979), color-stop(100%,#414141));
background: -webkit-linear-gradient(top, #e3e3e3 0%,#c6c6c6 22%,#b7b7b7 33%,#afafaf 50%,#a7a7a7 67%,#797979 82%,#414141 100%);
background: -o-linear-gradient(top, #e3e3e3 0%,#c6c6c6 22%,#b7b7b7 33%,#afafaf 50%,#a7a7a7 67%,#797979 82%,#414141 100%);
background: -ms-linear-gradient(top, #e3e3e3 0%,#c6c6c6 22%,#b7b7b7 33%,#afafaf 50%,#a7a7a7 67%,#797979 82%,#414141 100%);
background: linear-gradient(top, #e3e3e3 0%,#c6c6c6 22%,#b7b7b7 33%,#afafaf 50%,#a7a7a7 67%,#797979 82%,#414141 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e3e3e3', endColorstr='#414141',GradientType=0 );
}
.ComboBoxPressed
{
/* The reverse of the default background, simulating depression */
background: #414141;
background: -moz-linear-gradient(top, #414141 0%, #797979 18%, #a7a7a7 33%, #afafaf 50%, #b7b7b7 67%, #c6c6c6 78%, #e3e3e3 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#414141), color-stop(18%,#797979), color-stop(33%,#a7a7a7), color-stop(50%,#afafaf), color-stop(67%,#b7b7b7), color-stop(78%,#c6c6c6), color-stop(100%,#e3e3e3));
background: -webkit-linear-gradient(top, #414141 0%,#797979 18%,#a7a7a7 33%,#afafaf 50%,#b7b7b7 67%,#c6c6c6 78%,#e3e3e3 100%);
background: -o-linear-gradient(top, #414141 0%,#797979 18%,#a7a7a7 33%,#afafaf 50%,#b7b7b7 67%,#c6c6c6 78%,#e3e3e3 100%);
background: -ms-linear-gradient(top, #414141 0%,#797979 18%,#a7a7a7 33%,#afafaf 50%,#b7b7b7 67%,#c6c6c6 78%,#e3e3e3 100%);
background: linear-gradient(top, #414141 0%,#797979 18%,#a7a7a7 33%,#afafaf 50%,#b7b7b7 67%,#c6c6c6 78%,#e3e3e3 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#414141', endColorstr='#e3e3e3',GradientType=0 );
}
.ComboBoxText
{
/* Text info */
color: #000;
font: 9px Verdana;
float:left;
}
.ComboBoxIcon
{
/* Push the image to the far right */
float:right;
/* Align the image with the combo box */
padding: 2px 5px 0 0;
}
.ComboBoxPopup
{
position: fixed;
background: #CCC;
border-radius: 5px;
padding: 1px 0 1px 0;
}
.ComboBoxPopupItem
{
/* Text info */
color: #000;
font: 9px Verdana;
padding: 1px 1px 1px 5px;
border-bottom: 1px solid #AAA;
border-top: 1px solid #FFF;
}
.ComboBoxPopupItemText
{
float:left;
}
.ComboBoxPopupItemIcon
{
/* Push the image to the far right */
float:right;
/* Align the image with the combo box */
padding: 2px 5px 0 0;
}
.ComboBoxPopupItem:first-child
{
border-top: 0px;
}
.ComboBoxPopupItem:last-child
{
border-bottom: 0px;
}
.ComboBoxPopupItem:hover
{
color:#FFF;
background: #2036E1;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Grid Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.Grid {
overflow: auto;
background: #333;
height: 100%;
border-radius: 2px;
}
.GridBody
{
overflow-x: auto;
overflow-y: auto;
height: inherit;
}
.GridRow
{
display: inline-block;
white-space: nowrap;
background:#303030;
color: #BBB;
font: 9px Verdana;
padding: 2px;
}
.GridRow.GridGroup
{
padding: 0px;
}
.GridRow:nth-child(odd)
{
background:#333;
}
.GridRowCell
{
display: inline-block;
}
.GridRowCell.GridGroup
{
color: #BBB;
/* Override default from name */
width: 100%;
padding: 1px 1px 1px 2px;
border: 1px solid;
border-radius: 2px;
border-top-color:#555;
border-left-color:#555;
border-bottom-color:#111;
border-right-color:#111;
background: #222;
}
.GridRowBody
{
/* Clip all contents for show/hide group*/
overflow: hidden;
/* Crazy CSS rules: controls for properties don't clip if this isn't set on this parent */
position: relative;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* Button Styles */
/* ------------------------------------------------------------------------------------------------------------------ */
.Button
{
/* Position relative to the parent window */
position:absolute;
border-radius:4px;
/* Padding at the top includes 2px for the text drop-shadow */
padding: 2px 5px 3px 5px;
color: #BBB;
font: 9px Verdana;
text-shadow: 1px 1px 1px black;
text-align: center;
background-color:#555;
/* A box shadow and inset box highlight */
-webkit-box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
box-shadow: 1px 1px 1px #222, 1px 1px 1px #777 inset;
}
.Button:hover {
background-color: #616161;
}
.Button.ButtonHeld
{
/* Reset the gradient to a full-colour background */
background:#383838;
/* Two inset box shadows to simulate depressing */
-webkit-box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
box-shadow: -1px -1px 1px #222 inset, 1px 1px 1px #222 inset;
}