diff --git a/deluge/plugins/scheduler/scheduler/data/scheduler.js b/deluge/plugins/scheduler/scheduler/data/scheduler.js
index 7963903..8275cf4 100644
--- a/deluge/plugins/scheduler/scheduler/data/scheduler.js
+++ b/deluge/plugins/scheduler/scheduler/data/scheduler.js
@@ -1,17 +1,55 @@
-ScheduleSelectPanel = Ext.extend(Ext.form.FieldSet, {
-	constructor: function(config) {
-		config = Ext.apply({
-			title: _('Schedule'),
-			autoHeight: true
-		}, config);
-		ScheduleSelectPanel.superclass.constructor.call(this, config);
+Ext.ns('Deluge.ux');
+
+Deluge.ux.ScheduleSelector = Ext.extend(Ext.form.FieldSet, {
+	
+	title: _('Schedule'),
+	autoHeight: true,
+	style: 'margin-bottom: 0px; padding-bottom: 0px;',
+	border: false,
+	
+	states: [
+		{
+			name: 'Normal',
+			backgroundColor: 'LightGreen',
+			borderColor: 'DarkGreen',
+			value: 0
+		},
+		{
+			name: 'Throttled',
+			backgroundColor: 'Yellow',
+			borderColor: 'Gold',
+			value: 1
+		},
+		{
+			name: 'Paused',
+			backgroundColor: 'OrangeRed',
+			borderColor: 'FireBrick',
+			value: 2
+		}
+	],
+	daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+	
+	initComponent: function() {
+		Deluge.ux.ScheduleSelector.superclass.initComponent.call(this);
+		
+		// ExtJS' radiogroup implementation is very broken for styling.
+		/*this.stateBrush = this.add({
+			xtype: 'radiogroup',
+			fieldLabel: _('State Brush'),
+			name: 'current_state_brush',
+			submitValue: false,
+			items: [
+				{ boxLabel: 'Normal', name: 'current_state_brush', inputValue: 0 },
+				{ boxLabel: 'Throttled', name: 'current_state_brush', inputValue: 1, checked: true },
+				{ boxLabel: 'Paused', name: 'current_state_brush', inputValue: 2 },
+			]
+		});*/
 	},
 	
 	onRender: function(ct, position) {
-		ScheduleSelectPanel.superclass.onRender.call(this, ct, position);
+		Deluge.ux.ScheduleSelector.superclass.onRender.call(this, ct, position);
 		
 		var dom = this.body.dom;
-		var table = createEl(dom, 'table');
 		
 		function createEl(parent, type) {
 			var el = document.createElement(type);
@@ -19,30 +57,417 @@ ScheduleSelectPanel = Ext.extend(Ext.form.FieldSet, {
 			return el;
 		}
 		
-		Ext.each(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], function(day) {
+		// create state brushes
+		// tack a random number to the end to avoid clashes
+		this.stateBrushName = 'schedule-state-brush-' + Math.round(Math.random() * 10000);
+		
+		var el1 = createEl(dom, 'div');
+		
+		var el2 = createEl(el1, 'div');
+		this.stateBrush = el2;
+		el2.id = this.stateBrushName;
+		
+		// for webkit
+		var floatAttr = 'float';
+		if (el2.style.float == undefined) {
+			// for firefox
+			if (el2.style.cssFloat != undefined) floatAttr = 'cssFloat';
+			// for IE
+			if (el2.style.styleFloat != undefined) floatAttr = 'styleFloat';
+		}
+		el2.style[floatAttr] = 'right';
+		
+		for (var i=0; i < this.states.length; i++) {
+			var el3 = createEl(el2, 'input');
+			el3.type = 'radio';
+			el3.value = this.states[i].value;
+			el3.name = this.stateBrushName;
+			el3.id = this.stateBrushName + '-' + this.states[i].name;
+			
+			// isn't the first one
+			if (i > 0) el3.style.marginLeft = '7px';
+			
+			// assume the first is the default state, so make the 2nd one the default brush
+			if (i == 1) el3.checked = true;
+			
+			var el4 = createEl(el2, 'label');
+			el4.appendChild(document.createTextNode(this.states[i].name));
+			el4.htmlFor = el3.id;
+			el4.style.backgroundColor = this.states[i].backgroundColor;
+			el4.style.borderBottom = '2px solid ' + this.states[i].borderColor;
+			el4.style.padding = '2px 3px';
+			el4.style.marginLeft = '3px';
+		}
+		
+		el1.appendChild(document.createTextNode('Select a state brush:'));
+		
+		el1.style.marginBottom = '10px';
+		
+		// keep the radio buttons separate from the time bars
+		createEl(dom, 'div').style.clear = 'both';
+		
+		var table = createEl(dom, 'table');
+		table.cellSpacing = 0;
+		
+		// cache access to cells for easier access later
+		this.scheduleCells = { };
+		
+		Ext.each(this.daysOfWeek, function(day) {
+			var cells = [ ];
 			var row = createEl(table, 'tr');
 			var label = createEl(row, 'th');
 			label.setAttribute('style', 'font-weight: bold; padding-right: 5px;');
-			label.innerHTML = day;
+			label.appendChild(document.createTextNode(day));
 			for (var hour = 0; hour < 24; hour++) {
 				var cell = createEl(row, 'td');
-				cell.setAttribute('style', 'border: 1px solid Green; width: 16px; height: 20px; background: LightGreen;');
+				
+				// assume the first state is the default state
+				cell.currentValue = cell.oldValue = this.states[0].value;
+				cell.day = day;
+				cell.hour = hour;
+				
+				cell.width = '16px';
+				cell.height = '20px';
+				
+				cell.style.border = '1px solid #999999';
+				// don't repeat borders in between cells
+				if (hour != 23) // not the last cell
+					cell.style.borderRight = 'none';
+				
+				this.updateCell(cell);
+				
+				cells.push(cell);
+				
+				cell = Ext.get(cell);
+				cell.on('click', this.onCellClick, this);
+				cell.on('mouseover', this.onCellMouseOver, this);
+				cell.on('mouseout', this.onCellMouseOut, this);
+				cell.on('mousedown', this.onCellMouseDown, this);
+				cell.on('mouseup', this.onCellMouseUp, this);
+			}
+			
+			// insert gap row to provide visual separation
+			row = createEl(table, 'tr');
+			// blank cell to create gap
+			createEl(row, 'td').height = '3px';
+			
+			this.scheduleCells[day] = cells;
+		}, this);
+	},
+	
+	updateCell: function(cell) {
+		// sanity check
+		if (cell.currentValue == undefined) return;
+		
+		for (var i in this.states) {
+			var curState = this.states[i];
+			if (curState.value == cell.currentValue) {
+				cell.style.background = curState.backgroundColor;
+				break;
 			}
+		}
+	},
+	
+	getCurrentBrushValue: function() {
+		var v = null;
+		var brushes = Ext.get(this.body.dom).findParent('form').elements[this.stateBrushName];
+		Ext.each(brushes, function(b) {
+			if (b.checked)
+				v = b.value;
 		});
+		
+		return v;
+	},
+	
+	onCellClick: function(event, cell) {
+		cell.oldValue = cell.currentValue;
+		
+		this.dragAnchor = null;
+	},
+	
+	onCellMouseDown: function(event, cell) {
+		this.dragAnchor = cell;
+	},
+	
+	onCellMouseUp: function(event, cell) {
+		// if we're dragging...
+		if (this.dragAnchor) {
+			// set all those between here and the anchor to the new values
+			if (cell.hour > this.dragAnchor.hour)
+				this.confirmCells(cell.day, this.dragAnchor.hour, cell.hour);
+			else if (cell.hour < this.dragAnchor.hour)
+				this.confirmCells(cell.day, cell.hour, this.dragAnchor.hour);
+			else
+				this.confirmCells(cell.day, cell.hour, cell.hour);
+			
+			this.hideCellLeftTooltip();
+			this.hideCellRightTooltip();
+			this.dragAnchor = null;
+		}
+	},
+	
+	onCellMouseOver: function(event, cell) {
+		// LEFT TOOL TIP
+		// if it isn't showing and we're dragging, show it.
+		// otherwise if dragging, leave it alone unless we're dragging to the left.
+		// if we're not dragging, show it.
+		var leftTooltipCell = null;
+		if (!this.dragAnchor)
+			leftTooltipCell = cell;
+		else if ((this.dragAnchor && this.isCellLeftTooltipHidden()) ||
+			 (this.dragAnchor && this.dragAnchor.hour > cell.hour))
+			leftTooltipCell = this.dragAnchor;
+		
+		if (leftTooltipCell) {
+			var hour = leftTooltipCell.hour;
+			var pm = false;
+			
+			// convert to 12-hour time
+			if (hour >= 12) {
+				pm = true;
+				if (hour > 12) hour -= 12;
+			}
+			// change 0 hour to 12am
+			else if (hour == 0) {
+				hour = 12;
+			}
+			this.showCellLeftTooltip(hour + ' ' + (pm ? 'pm' : 'am'), leftTooltipCell);
+		}
+		
+		// RIGHT TOOL TIP
+		var rightTooltipCell = null;
+		if (this.dragAnchor) {
+			if (this.dragAnchor.hour == cell.hour)
+				this.hideCellRightTooltip();
+			else if (this.dragAnchor.hour > cell.hour && this.isCellRightTooltipHidden()) 
+				rightTooltipCell = this.dragAnchor;
+			else // cell.hour > this.dragAnchor.hour
+				rightTooltipCell = cell;
+		}
+		
+		if (rightTooltipCell) {
+			var hour = rightTooltipCell.hour;
+			var pm = false;
+			
+			// convert to 12-hour time
+			if (hour >= 12) {
+				pm = true;
+				if (hour > 12) hour -= 12;
+			}
+			// change 0 hour to 12am
+			else if (hour == 0) {
+				hour = 12;
+			}
+			this.showCellRightTooltip(hour + ' ' + (pm ? 'pm' : 'am'), rightTooltipCell);
+		}
+		
+		// preview colour change and
+		// revert state for all those on the outer side of the drag if dragging
+		if (this.dragAnchor) {
+			if (cell.day != this.dragAnchor.day) {
+				// dragged into another day. Abort! Abort!
+				Ext.each(this.daysOfWeek, function(day) {
+					this.revertCells(day, 0, 23);
+				}, this);
+				this.dragAnchor = null;
+				this.hideCellLeftTooltip();
+				this.hideCellRightTooltip();
+			}
+			else if (cell.hour > this.dragAnchor.hour) {
+				// dragging right
+				this.revertCells(cell.day, cell.hour+1, 23);
+				this.previewCells(cell.day, this.dragAnchor.hour, cell.hour);
+			}
+			else if (cell.hour < this.dragAnchor.hour) {
+				// dragging left
+				this.revertCells(cell.day, 0, cell.hour-1);
+				this.previewCells(cell.day, cell.hour, this.dragAnchor.hour);
+			}
+			else {
+				// back to anchor cell
+				// don't know if it is from right or left, so revert all except this
+				this.revertCells(cell.day, cell.hour+1, 23);
+				this.revertCells(cell.day, 0, cell.hour-1);
+			}
+		}
+		else {
+			// not dragging, just preview this cell
+			this.previewCells(cell.day, cell.hour, cell.hour);
+		}
+	},
+	
+	onCellMouseOut: function(event, cell) {
+		if (!this.dragAnchor)
+			this.hideCellLeftTooltip();
+		
+		// revert state. If new state has been set, old and new will be equal.
+		// if dragging, this will be handled by the next mouse over
+		if (this.dragAnchor == null && cell.oldValue != cell.currentValue) {
+			this.revertCells(cell.day, cell.hour, cell.hour);
+		}
+	},
+	
+	previewCells: function(day, fromHour, toHour) {
+		var cells = this.scheduleCells[day];
+		var curBrushValue = this.getCurrentBrushValue();
+		
+		if (toHour > cells.length) toHour = cells.length;
+		
+		for (var i=fromHour; i <= toHour; i++) {
+			if (cells[i].currentValue != curBrushValue) {
+				cells[i].oldValue = cells[i].currentValue;
+				cells[i].currentValue = curBrushValue;
+				this.updateCell(cells[i]);
+			}
+		}
+	},
+	
+	revertCells: function(day, fromHour, toHour) {
+		var cells = this.scheduleCells[day];
+		
+		if (toHour > cells.length) toHour = cells.length;
+		
+		for (var i=fromHour; i <= toHour; i++) {
+			cells[i].currentValue = cells[i].oldValue;
+			this.updateCell(cells[i]);
+		}
+	},
+	
+	confirmCells: function(day, fromHour, toHour) {
+		var cells = this.scheduleCells[day];
+		
+		if (toHour > cells.length) toHour = cells.length;
+		
+		for (var i=fromHour; i <= toHour; i++) {
+			if (cells[i].currentValue != cells[i].oldValue) {
+				cells[i].oldValue = cells[i].currentValue;
+			}
+		}
+	},
+	
+	showCellLeftTooltip: function(text, cell) {
+		var tooltip = this.cellLeftTooltip;
+		
+		if (!tooltip) {
+			// no cached left tooltip exists, create one
+			tooltip = document.createElement('div');
+			this.cellLeftTooltip = tooltip;
+			this.body.dom.appendChild(tooltip);
+			tooltip.style.position = 'absolute';
+			tooltip.style.backgroundColor = '#F2F2F2';
+			tooltip.style.border = '1px solid #333333';
+			tooltip.style.padding = '1px 3px';
+			tooltip.style.opacity = 0.8;
+		}
+		
+		// remove all existing children
+		while (tooltip.childNodes.length > 0) {
+			tooltip.removeChild(tooltip.firstChild);
+		}
+		// add the requested text
+		tooltip.appendChild(document.createTextNode(text));
+		
+		// place the tooltip
+		Ext.get(tooltip).alignTo(cell, 'br-tr');
+		
+		// make it visible
+		tooltip.style.visibility = 'visible';
+	},
+	
+	hideCellLeftTooltip: function() {
+		if (this.cellLeftTooltip) {
+			this.cellLeftTooltip.style.visibility = 'hidden';
+		}
+	},
+	
+	isCellLeftTooltipHidden: function() {
+		if (this.cellLeftTooltip)
+			return this.cellLeftTooltip.style.visibility == 'hidden';
+		else
+			return true;
+	},
+	
+	showCellRightTooltip: function(text, cell) {
+		var tooltip = this.cellRightTooltip;
+		
+		if (!tooltip) {
+			// no cached left tooltip exists, create one
+			tooltip = document.createElement('div');
+			this.cellRightTooltip = tooltip;
+			this.body.dom.appendChild(tooltip);
+			tooltip.style.position = 'absolute';
+			tooltip.style.backgroundColor = '#F2F2F2';
+			tooltip.style.border = '1px solid #333333';
+			tooltip.style.padding = '1px 3px';
+			tooltip.style.opacity = 0.8;
+		}
+		
+		// remove all existing children
+		while (tooltip.childNodes.length > 0) {
+			tooltip.removeChild(tooltip.firstChild);
+		}
+		// add the requested text
+		tooltip.appendChild(document.createTextNode(text));
+		
+		// place the tooltip
+		Ext.get(tooltip).alignTo(cell, 'bl-tl');
+		
+		// make it visible
+		tooltip.style.visibility = 'visible';
+	},
+	
+	hideCellRightTooltip: function() {
+		if (this.cellRightTooltip) {
+			this.cellRightTooltip.style.visibility = 'hidden';
+		}
+	},
+	
+	isCellRightTooltipHidden: function() {
+		if (this.cellRightTooltip)
+			return this.cellRightTooltip.style.visibility == 'hidden';
+		else
+			return true;
+	},
+	
+	getConfig: function() {
+		var config = [ ];
+		
+		for (var i=0; i < 24; i++) {
+			var hourConfig = [ 0, 0, 0, 0, 0, 0, 0 ];
+			
+			for (var j=0; j < this.daysOfWeek.length; j++) {
+				hourConfig[j] = parseInt(this.scheduleCells[this.daysOfWeek[j]][i].currentValue);
+			}
+			
+			config.push(hourConfig);
+		}
+		
+		return config;
+	},
+	
+	setConfig: function(config) {
+		for (var i=0; i < 24; i++) {
+			var hourConfig = config[i];
+			
+			for (var j=0; j < this.daysOfWeek.length; j++) {
+				var cell = this.scheduleCells[this.daysOfWeek[j]][i];
+				cell.currentValue = cell.oldValue = hourConfig[j];
+				this.updateCell(cell);
+			}
+		}
 	}
 });
 
-SchedulerPreferences = Ext.extend(Ext.Panel, {
-	constructor: function(config) {
-		config = Ext.apply({
-			border: false,
-			title: _('Scheduler')
-		}, config);
-		SchedulerPreferences.superclass.constructor.call(this, config);
-	},
+Ext.ns('Deluge.ux.preferences');
+
+Deluge.ux.preferences.SchedulerPage = Ext.extend(Ext.Panel, {
+	
+	border: false,
+	title: _('Scheduler'),
+	layout: 'fit',
 	
 	initComponent: function() {
-		SchedulerPreferences.superclass.initComponent.call(this);
+		Deluge.ux.preferences.SchedulerPage.superclass.initComponent.call(this);
 
 		this.form = this.add({
 			xtype: 'form',
@@ -51,56 +476,113 @@ SchedulerPreferences = Ext.extend(Ext.Panel, {
 			autoHeight: true
 		});
 		
-		this.schedule = this.form.add(new ScheduleSelectPanel());
+		this.schedule = this.form.add(new Deluge.ux.ScheduleSelector());
 		
 		this.slowSettings = this.form.add({
 			xtype: 'fieldset',
-			title: _('Slow Settings'),
+			border: false,
+			title: _('Throttled Settings'),
 			autoHeight: true,
-			defaultType: 'uxspinner'
+			defaultType: 'spinnerfield',
+			defaults: {
+				minValue: -1,
+				maxValue: 99999
+			},
+			style: 'margin-top: 5px; margin-bottom: 0px; padding-bottom: 0px;',
+			labelWidth: 200
 		});
 		
 		this.downloadLimit = this.slowSettings.add({
-			fieldLabel: _('Download Limit'),
-			name: 'download_limit'
+			fieldLabel: _('Maximum Download Speed (KiB/s)'),
+			name: 'download_limit',
+			width: 80,
+			value: -1,
+			decimalPrecision: 0
 		});
 		this.uploadLimit = this.slowSettings.add({
-			fieldLabel: _('Upload Limit'),
-			name: 'upload_limit'
+			fieldLabel: _('Maximum Upload Speed (KiB/s)'),
+			name: 'upload_limit',
+			width: 80,
+			value: -1,
+			decimalPrecision: 0
 		});
 		this.activeTorrents = this.slowSettings.add({
 			fieldLabel: _('Active Torrents'),
-			name: 'active_torrents'
+			name: 'active_torrents',
+			width: 80,
+			value: -1,
+			decimalPrecision: 0
+		});
+		this.activeDownloading = this.slowSettings.add({
+			fieldLabel: _('Active Downloading'),
+			name: 'active_downloading',
+			width: 80,
+			value: -1,
+			decimalPrecision: 0
+		});
+		this.activeSeeding = this.slowSettings.add({
+			fieldLabel: _('Active Seeding'),
+			name: 'active_seeding',
+			width: 80,
+			value: -1,
+			decimalPrecision: 0
 		});
 	},
 	
 	onRender: function(ct, position) {
-		SchedulerPreferences.superclass.onRender.call(this, ct, position);
+		Deluge.ux.preferences.SchedulerPage.superclass.onRender.call(this, ct, position);
 		this.form.layout = new Ext.layout.FormLayout();
 		this.form.layout.setContainer(this);
 		this.form.doLayout();
 	},
 	
-	onShow: function() {
-		SchedulerPreferences.superclass.onShow.call(this);
+	onApply: function() {
+		// build settings object
+		var config = { }
+		
+		config['button_state'] = this.schedule.getConfig();
+		config['low_down'] = this.downloadLimit.getValue();
+		config['low_up'] = this.uploadLimit.getValue();
+		config['low_active'] = this.activeTorrents.getValue();
+		config['low_active_down'] = this.activeDownloading.getValue();
+		config['low_active_up'] = this.activeSeeding.getValue();
+		
+		deluge.client.scheduler.set_config(config);
+	},
+	
+	afterRender: function() {
+		Deluge.ux.preferences.SchedulerPage.superclass.afterRender.call(this);
+		this.updateConfig();
+	},
+	
+	updateConfig: function() {
+		deluge.client.scheduler.get_config({
+			success: function(config) {
+				this.schedule.setConfig(config['button_state']);
+				this.downloadLimit.setValue(config['low_down']);
+				this.uploadLimit.setValue(config['low_up']);
+				this.activeTorrents.setValue(config['low_active']);
+				this.activeDownloading.setValue(config['low_active_down']);
+				this.activeSeeding.setValue(config['low_active_up']);
+			},
+			scope: this
+		});
 	}
 });
 
-SchedulerPlugin = Ext.extend(Deluge.Plugin, {
-	constructor: function(config) {
-		config = Ext.apply({
-			name: "Scheduler"
-		}, config);
-		SchedulerPlugin.superclass.constructor.call(this, config);
-	},
+Deluge.plugins.SchedulerPlugin = Ext.extend(Deluge.Plugin, {
+	
+	name: 'Scheduler',
 	
 	onDisable: function() {
-		Deluge.Preferences.removePage(this.prefsPage);
+		// use LOWERCASE for deluge.preferences to get the instance
+		// of PreferencesWindow, instead of the class.
+		deluge.preferences.removePage(this.prefsPage);
 	},
 	
 	onEnable: function() {
-		this.prefsPage = new SchedulerPreferences();
-		this.prefsPage = Deluge.Preferences.addPage(this.prefsPage);
+		this.prefsPage = deluge.preferences.addPage(new Deluge.ux.preferences.SchedulerPage());
 	}
 });
-new SchedulerPlugin();
\ No newline at end of file
+
+Deluge.registerPlugin('Scheduler', Deluge.plugins.SchedulerPlugin);
\ No newline at end of file
diff --git a/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js b/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
index f71c463..2e1fbc6 100644
--- a/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
+++ b/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
@@ -240,6 +240,11 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
 	// private
 	onOk: function() {
 		deluge.client.core.set_config(this.optionsManager.getDirty());
+		
+		for (var page in this.pages) {
+			if (this.pages[page].onApply) this.pages[page].onApply();
+		}
+		
 		this.hide();
 	}
 });
