indexing description: "[ Iso-orriented (orthogonal, axis-parallel) rectangle that can be drawn in EiffelMedia, possibly with rounded corners (see `rounded_corner_radius'). ]" date: "$Date$" revision: "$Revision$" class EM_RECTANGLE inherit EM_CLOSED_FIGURE undefine out redefine width, height, update_bounding_box end EM_ORTHOGONAL_RECTANGLE rename width as exact_width, height as exact_height export {NONE} out undefine default_create redefine make, process_changes end create make, make_from_coordinates, make_from_position_and_size, make_from_rectangle feature {NONE} -- Initialization make (a_point_a, a_point_b: EM_VECTOR_2D) is -- Initialize with `a_point_a' and `a_point_b' as corners of the rectangle. do default_create initialize_events rounded_corner_radius := 0.0 Precursor (a_point_a, a_point_b) set_visible (True) ensure then is_visible: is_visible end feature -- Status report rounded_corner_radius: DOUBLE -- Radius used to draw corners of `Current' rounded. -- (a value of 0.0 means no rounded corners) width: INTEGER is -- Width of `Current'. do Result := (right_bound + line_width / 2).ceiling - x end height: INTEGER is -- Height of `Current'. do Result := (lower_bound + line_width / 2).ceiling - y end feature -- Status setting set_rounded_corner_radius (a_radius: DOUBLE) is -- Set `rounded_corner_radius' to `a_radius'. do rounded_corner_radius := a_radius process_changes ensure rounded_corner_radius_set: rounded_corner_radius = a_radius end update_bounding_box is -- Recalculate `bounding_box' (`x', `y', `width', `height') -- to surround `Current' rectangle. -- (Should be called whenever `rectangle' has changed). do x := (left_bound - line_width / 2).floor y := (upper_bound - line_width / 2).floor -- Only `x' and `y' needs to be updates, -- since `width' and `height' are calculated now. end feature -- Drawing draw (surface: EM_SURFACE) is -- Draw `Current' onto `surface'. local polypoints: DS_LINKED_LIST [EM_VECTOR_2D] do if is_visible then if rounded_corner_radius = 0.0 then -- Just draw unrounded rectangle. if is_filled then surface.set_drawing_color (fill_color) surface.fill_rectangle (Current) end if line_width > 0 then surface.set_drawing_color (line_color) surface.set_line_width (line_width) surface.draw_rectangle (Current) end else -- Otherwise just draw polygon for `Current'. polypoints := polygon_points if is_filled then surface.set_drawing_color (fill_color) surface.fill_polygon (polypoints) end if line_width > 0 then surface.set_drawing_color (line_color) surface.set_line_width (line_width) surface.draw_polygon (polypoints) end end end end feature {NONE} -- Implementation process_changes is -- Process changes of `Current's state. -- Whenever `Current's state is changed -- this feature is called. -- (Can be redefined by descendants to do something -- whenever the state of `Current' changes) do -- Update bounding box update_bounding_box -- Recalculate all `points'. points.wipe_out points.put_last (point_a) points.put_last (point_b) end polygon_points: DS_LINKED_LIST [EM_VECTOR_2D] is -- Points for polygon representing `Current' with rounded corners. local ul, lr: EM_VECTOR_2D x1, y1, x2, y2: DOUBLE r, d: DOUBLE do -- Get relevant corner coordinates ul := upper_left lr := lower_right x1 := ul.x y1 := ul.y x2 := lr.x y2 := lr.y -- Calculate polygon for rounded rectangle. r := rounded_corner_radius.min (exact_width / 2).min (exact_height / 2) d := r * Radius_offset create Result.make Result.put_last (create {EM_VECTOR_2D}.make (x1 + r, y1)) Result.put_last (create {EM_VECTOR_2D}.make (x1 + d, y1 + d)) Result.put_last (create {EM_VECTOR_2D}.make (x1, y1 + r)) Result.put_last (create {EM_VECTOR_2D}.make (x1, y2 - r)) Result.put_last (create {EM_VECTOR_2D}.make (x1 + d, y2 - d)) Result.put_last (create {EM_VECTOR_2D}.make (x1 + r, y2)) Result.put_last (create {EM_VECTOR_2D}.make (x2 - r, y2)) Result.put_last (create {EM_VECTOR_2D}.make (x2 - d, y2 - d)) Result.put_last (create {EM_VECTOR_2D}.make (x2, y2 - r)) Result.put_last (create {EM_VECTOR_2D}.make (x2, y1 + r)) Result.put_last (create {EM_VECTOR_2D}.make (x2 - d, y1 + d)) Result.put_last (create {EM_VECTOR_2D}.make (x2 - r, y1)) end Radius_offset: DOUBLE is 0.2928932188134 -- 1 - (sqrt (2)) / 2 invariant rounded_corner_radius_not_negative: rounded_corner_radius >= 0.0 end