class FRACTAL_MODEL_WORLD

(source code)

description

Fractal image model world

(First class to make use of EL_BOOLEAN_OPTION)

note
	description: "[
		Fractal image model world
		
		(First class to make use of ${EL_BOOLEAN_OPTION})
	]"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-01-20 19:18:24 GMT (Saturday 20th January 2024)"
	revision: "14"

class
	FRACTAL_MODEL_WORLD

inherit
	EV_MODEL_WORLD

	EL_MODULE_COLOR

	SHARED_FRACTAL_CONFIG

create
	make

feature {NONE} -- Initialization

	make (initial_width_cms: REAL; a_layer_list: like master_list)
		local
			l_dimensions: EL_RECTANGLE
		do
			default_create
			master_list := a_layer_list; layer_list := a_layer_list

			create background_image
			background_image.set_with_named_file (fractal_config.background_image_path)
			relative_background_height := background_image.height / background_image.width

			create l_dimensions.make_cms (0, 0, initial_width_cms, 0)
			l_dimensions.set_height ((background_image.height * l_dimensions.width / background_image.width).rounded)

			create root_image
			create opacity_graduation
			create root_image_at_top.make_with_action (True, agent invert_layers)

			create rectangle.make_rectangle (0, 0, l_dimensions.width, l_dimensions.height)
			rectangle.set_background_color (Color.Gray)
			rectangle.set_foreground_color (Color.White)
		end

feature -- Access

	dimensions: EL_RECTANGLE
		do
			create Result.make (0, 0, rectangle.width, rectangle.height)
		end

	rectangle: EV_MODEL_RECTANGLE
		-- back ground rectangle

	relative_background_height: DOUBLE
		-- background height relative to the background width

	root_image: REPLICATED_IMAGE_MODEL

feature -- Status query

	opacity_graduation: EL_BOOLEAN_OPTION

	root_image_at_top: EL_BOOLEAN_OPTION
		-- if enabled, root image is the final layer to be drawn

feature -- Element change

	resize_rectangle (cell: EL_RECTANGLE)
		local
			l_height, l_width: INTEGER
		do
			if relative_background_height > cell.height / cell.width then
				l_height := cell.height
				l_width := (background_image.width * cell.height / background_image.height).rounded
			else
				l_width := cell.width
				l_height := (background_image.height * cell.width / background_image.width).rounded
			end
			if l_width /= rectangle.width or l_height /= rectangle.height then
				rectangle.set_width (l_width); rectangle.set_height (l_height)
				rescale
			end
		end

feature -- Basic operations

	add_layer
		do
			master_list.add_layer
			rescale
		end

	drawable_rectangle: EL_RECTANGLE
		local
			border_width: INTEGER
		do
			Result := rectangle.bounding_box
			border_width := (Result.height * fractal_config.border_percent / 100).rounded

			Result.grow_top (border_width.opposite)
			Result.grow_bottom (border_width.opposite)
			Result.grow_left (border_width.opposite)
			Result.grow_right (border_width.opposite)
		end

	refill
		do
			wipe_out
			extend (rectangle)
			across layer_list as layer loop
				layer.item.fill_world (Current)
			end
		end

	rescale
		do
			layer_list := master_list.scaled (drawable_rectangle)
			if root_image_at_top.is_enabled then
				layer_list.reverse
			end
			refill
		end

	reset_layers
		do
			master_list.reset
			add_layer
		end

feature -- Conversion

	as_picture: EV_MODEL_PICTURE
		do
			create Result.make_with_pixmap (rendered_drawing.to_pixmap)
		end

feature {NONE} -- Implementation

	invert_layers (reversed: BOOLEAN)
		do
			layer_list.reverse
			refill
		end

	rendered_drawing: CAIRO_DRAWING_AREA
		local
			opacity, minimum_opacity, decrement: DOUBLE
		do
			create Result.make_with_size (rectangle.width, rectangle.height)
			Result.draw_scaled_pixmap ({EL_DIRECTION}.By_width, 0, 0, rectangle.width, background_image)

			opacity := fractal_config.fading.maximum / 100
			minimum_opacity := fractal_config.fading.minimum / 100
			decrement := (opacity - minimum_opacity) / (layer_list.count - 1)

			across layer_list as layer loop
				if opacity_graduation.is_enabled then
					Result.set_opacity ((100 * opacity).rounded.min (100))
					opacity := opacity - decrement
				else
					Result.set_opaque
				end
				layer.item.do_all (agent {REPLICATED_IMAGE_MODEL}.render (Result))
			end
		end

feature {NONE} -- Internal attributes

	background_image: EV_PIXMAP

	layer_list: FRACTAL_LAYER_LIST

	master_list: FRACTAL_LAYER_LIST

end