diff --git a/src/Autoload/DrawingAlgos.gd b/src/Autoload/DrawingAlgos.gd
index acd3b97c0..995189958 100644
--- a/src/Autoload/DrawingAlgos.gd
+++ b/src/Autoload/DrawingAlgos.gd
@@ -454,9 +454,9 @@ func generate_outline(image : Image, outline_color : Color, thickness : int, dia
 	Global.canvas.handle_redo("Draw")
 
 
-func adjust_hsv(img: Image, delta_h : float, delta_s : float, delta_v : float) -> void:
+func adjust_hsv(img: Image, delta_h : float, delta_s : float, delta_v : float, pixels : Array) -> void:
 	img.lock()
-	for i in Global.current_project.selected_pixels:
+	for i in pixels:
 		var c : Color = img.get_pixelv(i)
 		# Hue
 		var hue = range_lerp(c.h,0,1,-180,180)
diff --git a/src/Canvas.gd b/src/Canvas.gd
index 593ba31f7..899f83e7f 100644
--- a/src/Canvas.gd
+++ b/src/Canvas.gd
@@ -129,50 +129,78 @@ func new_empty_frame(first_time := false, single_layer := false, size := Global.
 	return frame
 
 
-func handle_undo(action : String) -> void:
+func handle_undo(action : String, project : Project = Global.current_project, layer_index := -2, frame_index := -2) -> void:
 	if !can_undo:
 		return
+
+	if layer_index <= -2:
+		layer_index = project.current_layer
+	if frame_index <= -2:
+		frame_index = project.current_frame
+
+	var cels := []
 	var frames := []
-	var frame_index := -1
-	var layer_index := -1
-	if Global.animation_timer.is_stopped(): # if we're not animating, store only the current canvas
-		frames.append(Global.current_project.frames[Global.current_project.current_frame])
-		frame_index = Global.current_project.current_frame
-		layer_index = Global.current_project.current_layer
-	else: # If we're animating, store all frames
-		frames = Global.current_project.frames
-	Global.current_project.undos += 1
-	Global.current_project.undo_redo.create_action(action)
+	var layers := []
+	if frame_index == -1:
+		frames = project.frames
+	else:
+		frames.append(project.frames[frame_index])
+
+	if layer_index == -1:
+		layers = project.layers
+	else:
+		layers.append(project.layers[layer_index])
+
 	for f in frames:
-		# I'm not sure why I have to unlock it, but...
-		# ...if I don't, it doesn't work properly
-		f.cels[Global.current_project.current_layer].image.unlock()
-		var data = f.cels[Global.current_project.current_layer].image.data
-		f.cels[Global.current_project.current_layer].image.lock()
-		Global.current_project.undo_redo.add_undo_property(f.cels[Global.current_project.current_layer].image, "data", data)
-	Global.current_project.undo_redo.add_undo_method(Global, "undo", frame_index, layer_index)
+		for l in layers:
+			var index = project.layers.find(l)
+			cels.append(f.cels[index])
+
+	project.undos += 1
+	project.undo_redo.create_action(action)
+	for cel in cels:
+		# If we don't unlock the image, it doesn't work properly
+		cel.image.unlock()
+		var data = cel.image.data
+		cel.image.lock()
+		project.undo_redo.add_undo_property(cel.image, "data", data)
+	project.undo_redo.add_undo_method(Global, "undo", frame_index, layer_index)
 
 	can_undo = false
 
 
-func handle_redo(_action : String) -> void:
+func handle_redo(_action : String, project : Project = Global.current_project, layer_index := -2, frame_index := -2) -> void:
 	can_undo = true
-
-	if Global.current_project.undos < Global.current_project.undo_redo.get_version():
+	if project.undos < project.undo_redo.get_version():
 		return
+
+	if layer_index <= -2:
+		layer_index = project.current_layer
+	if frame_index <= -2:
+		frame_index = project.current_frame
+
+	var cels := []
 	var frames := []
-	var frame_index := -1
-	var layer_index := -1
-	if Global.animation_timer.is_stopped():
-		frames.append(Global.current_project.frames[Global.current_project.current_frame])
-		frame_index = Global.current_project.current_frame
-		layer_index = Global.current_project.current_layer
+	var layers := []
+	if frame_index == -1:
+		frames = project.frames
 	else:
-		frames = Global.current_project.frames
+		frames.append(project.frames[frame_index])
+
+	if layer_index == -1:
+		layers = project.layers
+	else:
+		layers.append(project.layers[layer_index])
+
 	for f in frames:
-		Global.current_project.undo_redo.add_do_property(f.cels[Global.current_project.current_layer].image, "data", f.cels[Global.current_project.current_layer].image.data)
-	Global.current_project.undo_redo.add_do_method(Global, "redo", frame_index, layer_index)
-	Global.current_project.undo_redo.commit_action()
+		for l in layers:
+			var index = project.layers.find(l)
+			cels.append(f.cels[index])
+
+	for cel in cels:
+		project.undo_redo.add_do_property(cel.image, "data", cel.image.data)
+	project.undo_redo.add_do_method(Global, "redo", frame_index, layer_index)
+	project.undo_redo.commit_action()
 
 
 func update_texture(layer_index : int, frame_index := -1) -> void:
diff --git a/src/UI/Dialogs/HSVDialog.gd b/src/UI/Dialogs/HSVDialog.gd
index a67345859..768196859 100644
--- a/src/UI/Dialogs/HSVDialog.gd
+++ b/src/UI/Dialogs/HSVDialog.gd
@@ -1,5 +1,10 @@
 extends WindowDialog
 
+
+enum {CEL, FRAME, ALL_FRAMES, ALL_PROJECTS}
+
+var affect : int = CEL
+var pixels := []
 var current_cel : Image
 var preview_image : Image
 var preview_texture : ImageTexture
@@ -13,6 +18,7 @@ onready var sat_spinbox = $MarginContainer/VBoxContainer/HBoxContainer/TextBoxes
 onready var val_spinbox = $MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Value
 
 onready var preview = $MarginContainer/VBoxContainer/TextureRect
+onready var selection_checkbox : CheckBox = $MarginContainer/VBoxContainer/AffectHBoxContainer/SelectionCheckBox
 
 
 func _ready() -> void:
@@ -25,6 +31,7 @@ func _ready() -> void:
 func _on_HSVDialog_about_to_show() -> void:
 	current_cel = Global.current_project.frames[Global.current_project.current_frame].cels[Global.current_project.current_layer].image
 	preview_image.copy_from(current_cel)
+	_on_SelectionCheckBox_toggled(selection_checkbox.pressed)
 	update_preview()
 
 
@@ -34,10 +41,15 @@ func _on_Cancel_pressed() -> void:
 
 
 func _on_Apply_pressed() -> void:
-	Global.canvas.handle_undo("Draw")
-	DrawingAlgos.adjust_hsv(current_cel, hue_slider.value, sat_slider.value, val_slider.value)
-	Global.canvas.update_texture(Global.current_project.current_layer)
-	Global.canvas.handle_redo("Draw")
+	if affect == CEL:
+		Global.canvas.handle_undo("Draw")
+		DrawingAlgos.adjust_hsv(current_cel, hue_slider.value, sat_slider.value, val_slider.value, pixels)
+		Global.canvas.handle_redo("Draw")
+	elif affect == FRAME:
+		Global.canvas.handle_undo("Draw", Global.current_project, -1)
+		for cel in Global.current_project.frames[Global.current_project.current_frame].cels:
+			DrawingAlgos.adjust_hsv(cel.image, hue_slider.value, sat_slider.value, val_slider.value, pixels)
+		Global.canvas.handle_redo("Draw", Global.current_project, -1)
 	reset()
 	visible = false
 
@@ -55,7 +67,7 @@ func reset() -> void:
 
 func update_preview() -> void:
 	preview_image.copy_from(current_cel)
-	DrawingAlgos.adjust_hsv(preview_image, hue_slider.value, sat_slider.value, val_slider.value)
+	DrawingAlgos.adjust_hsv(preview_image, hue_slider.value, sat_slider.value, val_slider.value, pixels)
 	preview_texture.create_from_image(preview_image, 0)
 	preview.texture = preview_texture
 
@@ -94,3 +106,19 @@ func _on_Value_value_changed(value : float) -> void:
 	val_spinbox.value = value
 	val_slider.value = value
 	update_preview()
+
+
+func _on_SelectionCheckBox_toggled(button_pressed : bool) -> void:
+	pixels.clear()
+	if button_pressed:
+		pixels = Global.current_project.selected_pixels.duplicate()
+	else:
+		for x in Global.current_project.size.x:
+			for y in Global.current_project.size.y:
+				pixels.append(Vector2(x, y))
+
+	update_preview()
+
+
+func _on_AffectOptionButton_item_selected(index : int) -> void:
+	affect = index
diff --git a/src/UI/Dialogs/HSVDialog.tscn b/src/UI/Dialogs/HSVDialog.tscn
index da9fc3fc1..fbbb3eb4e 100644
--- a/src/UI/Dialogs/HSVDialog.tscn
+++ b/src/UI/Dialogs/HSVDialog.tscn
@@ -33,15 +33,15 @@ __meta__ = {
 
 [node name="TextureRect" type="TextureRect" parent="MarginContainer/VBoxContainer"]
 margin_right = 453.0
-margin_bottom = 197.0
+margin_bottom = 169.0
 size_flags_vertical = 3
 expand = true
 stretch_mode = 6
 
 [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
-margin_top = 201.0
+margin_top = 173.0
 margin_right = 453.0
-margin_bottom = 285.0
+margin_bottom = 257.0
 custom_constants/separation = 10
 __meta__ = {
 "_edit_use_anchors_": false
@@ -132,6 +132,27 @@ margin_bottom = 84.0
 mouse_default_cursor_shape = 1
 min_value = -100.0
 
+[node name="AffectHBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+margin_top = 261.0
+margin_right = 453.0
+margin_bottom = 285.0
+
+[node name="SelectionCheckBox" type="CheckBox" parent="MarginContainer/VBoxContainer/AffectHBoxContainer"]
+margin_right = 160.0
+margin_bottom = 24.0
+mouse_default_cursor_shape = 2
+pressed = true
+text = "Only affect selection"
+
+[node name="AffectOptionButton" type="OptionButton" parent="MarginContainer/VBoxContainer/AffectHBoxContainer"]
+margin_left = 164.0
+margin_right = 263.0
+margin_bottom = 24.0
+mouse_default_cursor_shape = 2
+text = "Current cel"
+items = [ "Current cel", null, false, 0, null, "Current frame", null, false, 1, null, "All frames", null, true, 2, null, "All projects", null, true, 3, null ]
+selected = 0
+
 [node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
 margin_top = 289.0
 margin_right = 453.0
@@ -162,5 +183,7 @@ text = "Cancel"
 [connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Hue" to="." method="_on_Hue_value_changed"]
 [connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Saturation" to="." method="_on_Saturation_value_changed"]
 [connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Value" to="." method="_on_Value_value_changed"]
+[connection signal="toggled" from="MarginContainer/VBoxContainer/AffectHBoxContainer/SelectionCheckBox" to="." method="_on_SelectionCheckBox_toggled"]
+[connection signal="item_selected" from="MarginContainer/VBoxContainer/AffectHBoxContainer/AffectOptionButton" to="." method="_on_AffectOptionButton_item_selected"]
 [connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer2/Apply" to="." method="_on_Apply_pressed"]
 [connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer2/Cancel" to="." method="_on_Cancel_pressed"]