indexing description: "Projectors for widgets." legal: "See notice at end of class." status: "See notice at end of class." keywords: "projector, events" date: "$Date$" revision: "$Revision$" deferred class EV_MODEL_WIDGET_PROJECTOR inherit EV_MODEL_PROJECTOR EV_MODEL_DRAWER EV_MODEL_PROJECTION_ROUTINES EV_SHARED_APPLICATION feature {NONE} -- Initialization make_with_drawable_widget (a_world: like world; a_drawable: EV_DRAWABLE; a_widget: like widget) is -- Create with `a_world' and `a_drawable' (= `a_widget'). require a_world_not_void: a_world /= Void a_drawable_not_void: a_drawable /= Void a_widget_not_void: a_widget /= Void do make_with_drawable (a_drawable) create draw_routines.make (0, 20) make_with_world (a_world) register_basic_figures widget := a_widget area_x := 0 area_y := 0 widget.pointer_motion_actions.extend (agent mouse_move) widget.pointer_button_press_actions.extend (agent button_press) widget.pointer_double_press_actions.extend (agent double_press) widget.pointer_button_release_actions.extend (agent button_release) widget.pointer_leave_actions.extend (agent pointer_leave) widget.set_pebble_function (agent on_pebble_request) widget.set_actual_drop_target_agent (agent on_drop_target_request) end make_with_drawable_widget_and_buffer ( a_world: like world; a_drawable: EV_DRAWABLE; a_buffer: EV_PIXMAP; a_widget: like widget) is -- Create with `a_world', `a_drawable' (= `a_widget') and `a_buffer'. require a_world_not_void: a_world /= Void a_drawable_not_void: a_drawable /= Void a_buffer_not_void: a_buffer /= Void a_widget_not_void: a_widget /= Void do make_with_drawable_widget (a_world, a_buffer, a_widget) area := a_drawable end feature -- Access widget: EV_WIDGET -- `device' if conforms to EV_WIDGET. -- `Void' otherwise. area: EV_DRAWABLE -- Area associated with `widget'. -- `Void' if no buffer is used. area_x, area_y: INTEGER -- Coordinates of top-left corner of displayed part of `drawable'. -- (0, 0) when no buffer is used. feature -- Status report buffer_used: BOOLEAN is -- Is `drawable' only a buffer area for `area'? do Result := area /= Void end is_figure_selected: BOOLEAN -- Was button pointer pressed on a figure? feature -- Element change change_area_position (a_x, a_y: INTEGER) is -- `area' has moved to (`a_x', `a_y') of `drawable'. local u: EV_RECTANGLE do area_x := a_x area_y := a_y create u.make (0, 0, area.width, area.height) update_rectangle (u, 0, 0) end feature -- Basic operations project is -- Make a standard projection of world on device. local e, u: EV_RECTANGLE do if not is_projecting then is_projecting := True if world.is_redraw_needed then full_project world.full_redraw_performed else e := world.invalid_rectangle if e /= Void then u := world.update_rectangle if u /= Void then e.merge (u) end project_rectangle (e) end end end is_projecting := False end project_rectangle (u: EV_RECTANGLE) is -- Project area under `u'. local pixmap: EV_PIXMAP do drawable.set_background_color (world.background_color) drawable.clear_rectangle (u.left, u.top, u.width, u.height) if world.grid_visible then draw_grid end if world.is_show_requested then project_figure_group (world, u) end if has_mouse then change_current (figure_on_position (world, last_pointer_x, last_pointer_y)) end if world.points_visible then draw_points (world) end world.validate if buffer_used then -- Flush `drawable' on `area'. pixmap ?= drawable if pixmap /= Void then u.set_x (area_x) u.set_y (area_y) u.set_width (area.width) u.set_height (area.height) area.draw_sub_pixmap (0, 0, pixmap, u) end end end full_project is -- Project entire area. local pixmap: EV_PIXMAP do drawable.set_background_color (world.background_color) drawable.clear_rectangle (0, 0, drawable.width, drawable.height) if world.grid_visible then draw_grid end if world.is_show_requested then project_figure_group_full (world) end if has_mouse then change_current (figure_on_position (world, last_pointer_x, last_pointer_y)) end if world.points_visible then draw_points (world) end world.validate if buffer_used then -- Flush `drawable' on `area'. pixmap ?= drawable if pixmap /= Void then area.draw_pixmap (0, 0, pixmap) end end end update_rectangle (u: EV_RECTANGLE; a_x, a_y: INTEGER) is -- Flush `u' on `area' at (`a_x', `a_y'). require buffer_used: buffer_used local pixmap: EV_PIXMAP do pixmap ?= drawable if pixmap /= Void then u.set_x (u.x + area_x) u.set_y (u.y + area_y) area.draw_sub_pixmap (a_x, a_y, pixmap, u) end end clear_device is -- Erase entire canvas. do drawable.set_background_color (world.background_color) drawable.clear end feature {NONE} -- Event implementation current_figure: EV_MODEL -- Figure mouse is currently on. --| To generate leave and enter actions. last_pointer_x, last_pointer_y: INTEGER -- Last mouse coordinates. --| Used when world changes using `project'. has_mouse: BOOLEAN -- Does canvas have mouse on it? figure_on_position (group: EV_MODEL_GROUP; x, y: INTEGER): EV_MODEL is -- Figure mouse-cursor is on. local grp: EV_MODEL_GROUP gritem: EV_MODEL i: INTEGER found_closed_figure, closed_figure: EV_MODEL_CLOSED do if world.capture_figure /= Void then Result := world.capture_figure else from group.finish i := group.count until Result /= Void or else i < 1 loop gritem := group.i_th (i) grp ?= gritem if grp /= Void and then grp.is_sensitive then if grp.position_on_figure (x, y) then Result := grp else Result := figure_on_position (grp, x, y) end elseif gritem.position_on_figure (x, y) and then gritem.is_sensitive then Result := gritem end closed_figure ?= Result if closed_figure /= Void and then closed_figure.background_color = Void then -- is a not closed_figure under it? Result := Void if found_closed_figure = Void then -- if not take the first closed_figure found. found_closed_figure := closed_figure end end i := i - 1 end if Result = Void and then found_closed_figure /= Void then Result := found_closed_figure end end end button_press (x, y, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; screen_x, screen_y: INTEGER) is -- Pointer button down happened. local event_fig: EV_MODEL p: BOOLEAN w_x, w_y: INTEGER action: EV_LITE_ACTION_SEQUENCE [TUPLE] do w_x := x + area_x w_y := y + area_y from event_fig := figure_on_position (world, w_x, w_y) if event_fig = Void then event_fig := world is_figure_selected := False else is_figure_selected := True end until event_fig = Void loop action := event_fig.internal_pointer_button_press_actions if action /= Void and then event_fig.is_sensitive then action.call ([w_x, w_y, button,x_tilt, y_tilt, pressure, screen_x, screen_y]) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end if p then project end end double_press (x, y, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; screen_x, screen_y: INTEGER) is -- Pointer double click happened. local event_fig: EV_MODEL p: BOOLEAN w_x, w_y: INTEGER action: EV_LITE_ACTION_SEQUENCE [TUPLE] do w_x := x + area_x w_y := y + area_y from event_fig := figure_on_position (world, w_x, w_y) if event_fig = Void then event_fig := world end until event_fig = Void loop action := event_fig.internal_pointer_double_press_actions if action /= Void and then event_fig.is_sensitive then action.call ([w_x, w_y, button,x_tilt, y_tilt, pressure, screen_x, screen_y]) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end if p then project end end button_release (x, y, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; screen_x, screen_y: INTEGER) is -- Pointer button up happened. local event_fig: EV_MODEL p: BOOLEAN w_x, w_y: INTEGER action: EV_LITE_ACTION_SEQUENCE [TUPLE] do w_x := x + area_x w_y := y + area_y is_figure_selected := False from event_fig := figure_on_position (world, w_x, w_y) if event_fig = Void then event_fig := world end until event_fig = Void loop action := event_fig.internal_pointer_button_release_actions if action /= Void and then event_fig.is_sensitive then action.call ([w_x, w_y, button, x_tilt, y_tilt, pressure, screen_x, screen_y]) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end if p then project end end pointer_leave is -- Pointer left canvas. do has_mouse := False end has_focus (a_figure: EV_MODEL): BOOLEAN is -- Is mouse cursor on `a_figure'? local grp: EV_MODEL_GROUP do if current_figure = a_figure then Result := True else grp ?= a_figure if grp /= Void then from grp.start until Result or grp.after loop Result := has_focus (grp.item) grp.forth end end end end change_current (new_current_figure: EV_MODEL) is -- Change current to `new_focused_figure'. --| Generate leave and/or enter events accordingly. local old_figure: EV_MODEL event_fig: EV_MODEL same_fig: EV_MODEL p: BOOLEAN action: EV_LITE_ACTION_SEQUENCE [TUPLE] do if current_figure /= new_current_figure then if new_current_figure /= Void and new_current_figure.pointer_style /= Void and new_current_figure.is_sensitive then widget.set_pointer_style (new_current_figure.pointer_style) else widget.set_pointer_style (default_cursor) end old_figure := current_figure current_figure := new_current_figure if old_figure /= Void then from event_fig := old_figure until event_fig = Void or else has_focus (event_fig) loop action := event_fig.internal_pointer_leave_actions if action /= Void and then event_fig.is_sensitive then action.call (Void) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end end same_fig := event_fig if current_figure /= Void then from event_fig := current_figure until event_fig = same_fig loop action := event_fig.internal_pointer_enter_actions if action /= Void and then event_fig.is_sensitive then action.call (Void) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end end end if p then project end ensure -- current_figure_assigned: current_figure = new_current_figure end mouse_move (x, y: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; screen_x, screen_y: INTEGER) is -- Fire events that belong to mouse movement. --| i.e. leave, enter, motion. local event_fig: EV_MODEL p: BOOLEAN w_x, w_y: INTEGER action: EV_LITE_ACTION_SEQUENCE [TUPLE] do w_x := x + area_x w_y := y + area_y has_mouse := True last_pointer_x := w_x last_pointer_y := w_y from event_fig := figure_on_position (world, w_x, w_y) change_current (event_fig) if event_fig = Void then event_fig := world end until event_fig = Void loop action := event_fig.internal_pointer_motion_actions if action /= Void and then event_fig.is_sensitive then action.call ([w_x, w_y, x_tilt, y_tilt, pressure, screen_x, screen_y]) if event_fig.are_events_sended_to_group then event_fig := event_fig.group else event_fig := Void end else event_fig := event_fig.group end p := True end if p then project end end on_pebble_request (a_x, a_y: INTEGER): ANY is -- Pebble of current figure. -- If figure is `Void', return pebble of world. --| Because when a context menu is up, no events are sent --| to the world, first simulate a mouse motion to update --| the projection. local fig: EV_MODEL do mouse_move (a_x, a_y, 0.0, 0.0, 0.0, 0, 0) fig := current_figure if fig = Void or else ev_application.ctrl_pressed then Result := world.real_pebble (a_x, a_y) elseif fig.is_sensitive then from until Result /= Void or fig = Void loop Result := fig.real_pebble (a_x, a_y) if Result = Void then fig := fig.group end end if Result /= Void and then fig /= Void then if fig.accept_cursor /= Void then widget.set_accept_cursor (fig.accept_cursor) else widget.set_accept_cursor (fig.default_accept_cursor) end if fig.deny_cursor /= Void then widget.set_deny_cursor (fig.deny_cursor) else widget.set_deny_cursor (fig.default_deny_cursor) end end end end on_drop_target_request (a_x, a_y: INTEGER): EV_ABSTRACT_PICK_AND_DROPABLE is -- Find actual drop target. local event_fig: EV_MODEL w_x, w_y: INTEGER do w_x := a_x + area_x w_y := a_y + area_y event_fig := figure_on_position (world, w_x, w_y) if event_fig = Void and then not world.drop_actions.is_empty then Result := world else from until Result /= Void or event_fig = Void loop if not event_fig.drop_actions.is_empty then Result := event_fig end event_fig := event_fig.group end end end feature {NONE} -- Implementation default_cursor: EV_POINTER_STYLE is -- Default cursor on world. do Result := default_pixmaps.standard_cursor end axle_length: INTEGER is 15 -- Length of x and y axles when points are displayed. draw_points (figure: EV_MODEL) is -- Draw representation of all points in `figure' to canvas. require figure_not_void: figure /= Void local group: EV_MODEL_GROUP l_points: SPECIAL [EV_COORDINATE] i, nb: INTEGER bbox: EV_RECTANGLE l_item: EV_COORDINATE do bbox := figure.bounding_box drawable.set_foreground_color (default_colors.red) drawable.fill_ellipse (figure.x-5 + offset_x, figure.y-5 + offset_y, 11, 11) drawable.set_foreground_color (default_colors.black) drawable.draw_rectangle (bbox.left + offset_x, bbox.top + offset_y, bbox.width, bbox.height) group ?= figure if group = Void then l_points := figure.point_array from i := 0 nb := l_points.count - 1 until i > nb loop l_item := l_points.item (i) drawable.draw_segment (l_item.x + offset_x, l_item.y + offset_y, figure.x + offset_x, figure.y + offset_y) drawable.fill_ellipse (l_item.x - 5 + offset_x, l_item.y - 5 + offset_y, 11, 11) i := i + 1 end end group ?= figure if group /= Void then from group.start until group.after loop draw_points (group.item) group.forth end end end indexing copyright: "Copyright (c) 1984-2006, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 356 Storke Road, Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class EV_MODEL_WIDGET_PROJECTOR