Repository: godotengine/godot
File: editor/plugins/gradient_texture_2d_editor_plugin.cpp (C++)

Code before:
			}
		} else {
			_update_fill_position();
			handle = HANDLE_NONE;
		}
	}

	// Move handle.
	const Ref<InputEventMouseMotion> mm = p_event;
	if (mm.is_valid()) {
		_update_fill_position();
	}
}

void GradientTexture2DEditorRect::set_texture(Ref<GradientTexture2D> &p_texture) {
	texture = p_texture;
	texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}

void GradientTexture2DEditorRect::set_snap_enabled(bool p_snap_enabled) {
	snap_enabled = p_snap_enabled;
	queue_redraw();
}

void GradientTexture2DEditorRect::set_snap_size(float p_snap_size) {
	snap_size = p_snap_size;
	queue_redraw();
}

void GradientTexture2DEditorRect::_notification(int p_what) {
	switch (p_what) {
		case NOTIFICATION_ENTER_TREE:
		case NOTIFICATION_THEME_CHANGED: {
			checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")));
		} break;

		case NOTIFICATION_DRAW: {
			if (texture.is_null()) {
				return;
			}

			const Ref<Texture2D> fill_from_icon = get_theme_icon(SNAME("EditorPathSmoothHandle"), SNAME("EditorIcons"));
			const Ref<Texture2D> fill_to_icon = get_theme_icon(SNAME("EditorPathSharpHandle"), SNAME("EditorIcons"));
			handle_size = fill_from_icon->get_size();

			Size2 rect_size = get_size();

			// Get the size and position to draw the texture and handles at.
			// Subtract handle sizes so they stay inside the preview, but keep the texture's aspect ratio.
			Size2 available_size = rect_size - handle_size;
			Size2 ratio = available_size / texture->get_size();

Review comment (suggestion):
Not very important, but you could store `get_handle_at()` in a variable to avoid calling it twice.

Code after:
	const Ref<InputEventMouseButton> mb = p_event;
	if (mb.is_valid()) {
		if (mb->get_button_index() == MouseButton::LEFT) {
			if (mb->is_pressed()) {
				grabbed = get_handle_at(mb->get_position() - offset);

				if (grabbed != HANDLE_NONE) {
					initial_grab_pos = _get_handle_pos(grabbed) / size;
					queue_redraw();
				}
			} else {
				// Release the handle.
				if (grabbed != HANDLE_NONE) {
					set_fill_pos(_get_handle_pos(grabbed) / size);
					grabbed = HANDLE_NONE;
					queue_redraw();
				}
			}
		}

		if (grabbed != HANDLE_NONE && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
			texture->set((grabbed == HANDLE_FROM) ? SNAME("fill_from") : SNAME("fill_to"), initial_grab_pos);
			grabbed = HANDLE_NONE;
			queue_redraw();
		}
	}

	// Move handle.
	const Ref<InputEventMouseMotion> mm = p_event;
	if (mm.is_valid()) {
		Vector2 mpos = mm->get_position() - offset;

		Handle handle_at_mpos = get_handle_at(mpos);
		if (hovered != handle_at_mpos) {
			hovered = handle_at_mpos;
			queue_redraw();
		}

		if (grabbed == HANDLE_NONE) {
			return;
		}

		Vector2 new_pos = (mpos / size).clamp(Vector2(0, 0), Vector2(1, 1));
		if (snap_enabled || mm->is_ctrl_pressed()) {
			new_pos = new_pos.snapped(Vector2(1.0 / snap_count, 1.0 / snap_count));
		}

		// Allow to snap to an axis with Shift.
		if (mm->is_shift_pressed()) {
			Vector2 initial_mpos = initial_grab_pos * size;
			if (Math::abs(mpos.x - initial_mpos.x) > Math::abs(mpos.y - initial_mpos.y)) {