note description: "EiffelVision pixmap. Mswindows implementation for % %widget pixmap (drawable & self-displayable)" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" class EV_PIXMAP_IMP_WIDGET inherit EV_PIXMAP_IMP_DRAWABLE undefine has_focus, is_sensitive, is_displayed, set_focus, x_position, y_position, on_parented, on_orphaned, disable_sensitive, enable_sensitive, show, pointed_target, reset_minimum_width, reset_minimum_height, reset_minimum_size, set_minimum_width, set_minimum_height, set_minimum_size, set_tooltip, screen_x, screen_y, set_size, parent, is_show_requested, minimum_width, draw_rubber_band, set_pointer_style, erase_rubber_band, disable_transport, destroy, disable_capture, pointer_position, start_transport, enable_transport, pointer_style, tooltip, has_capture, end_transport, enable_capture, minimum_height, hide, set_pebble, real_pointed_target, set_actual_drop_target_agent, has_parent, parent_is_sensitive, internal_set_pointer_style, widget_imp_at_pointer_position, internal_enable_dockable, internal_disable_dockable, update_buttons, refresh_now, init_file_drop_actions, update_for_pick_and_drop, is_tabable_from, is_tabable_to, enable_tabable_from, enable_tabable_to, disable_tabable_from, disable_tabable_to, init_resize_actions, init_dpi_changed_actions redefine interface, make, read_from_named_path, clear, stretch, clear_rectangle, draw_point, draw_text, draw_segment, draw_straight_line, draw_arc, draw_pixmap, draw_rectangle, draw_ellipse, draw_polyline, draw_pie_slice, fill_rectangle, fill_ellipse, fill_polygon, fill_pie_slice, set_with_default, flush, copy_pixmap, redraw select width, height, make end EV_PRIMITIVE_IMP rename height as display_height, width as display_width, make as widget_initialize undefine set_background_color, set_foreground_color, background_color_internal, foreground_color_internal, set_default_colors redefine interface, on_parented, on_orphaned, set_size, destroy, translate_coordinates, on_middle_button_down, on_left_button_down, on_right_button_down, on_size end EV_WEL_CONTROL_WINDOW undefine on_sys_key_down, wel_font, wel_set_font, on_getdlgcode, on_wm_dropfiles redefine on_erase_background, class_background, default_style, class_style end create make_with_simple, make_with_drawable feature {NONE} -- Initialization make_with_drawable (other: EV_PIXMAP_IMP_DRAWABLE) -- Create `Current' using attributes of `other'. local titled_window: detachable EV_TITLED_WINDOW_IMP l_internal_bitmap: like internal_bitmap do -- Create this new implementation using the -- same interface as other. if attached other.interface as l_interface then assign_interface (l_interface) else check False end end -- Create the window control background_color_internal := other.background_color clip_area := other.clip_area dashed_line_style := other.dashed_line_style foreground_color_internal := other.foreground_color internal_brush := other.internal_brush if attached internal_brush as l_internal_brush then l_internal_brush.increment_reference end if attached other.private_font as l_private_font then private_font := l_private_font end private_wel_font := other.private_wel_font internal_initialized_background_brush := other.internal_initialized_background_brush internal_background_brush := other.internal_background_brush if attached internal_background_brush as l_internal_background_brush then l_internal_background_brush.increment_reference end internal_initialized_brush := other.internal_initialized_brush internal_initialized_pen := other.internal_initialized_pen internal_pen := other.internal_pen if attached internal_pen as l_internal_pen then l_internal_pen.increment_reference end line_width := other.line_width tile := other.tile wel_drawing_mode := other.wel_drawing_mode dc := other.dc dc.increment_reference height := other.height width := other.width l_internal_bitmap := other.internal_bitmap check l_internal_bitmap /= Void then end l_internal_bitmap.increment_reference internal_bitmap := l_internal_bitmap internal_mask_bitmap := other.internal_mask_bitmap if attached internal_mask_bitmap as l_internal_mask_bitmap then l_internal_mask_bitmap.increment_reference end mask_dc := other.mask_dc if attached mask_dc as l_mask_dc then l_mask_dc.increment_reference end palette := other.palette if attached palette as l_palette then l_palette.increment_reference end transparent_color := other.transparent_color -- Pick and drop info pebble := other.pebble pebble_function := other.pebble_function -- Create the window control wel_make (default_parent, "EV_PIXMAP") -- initialize from EV_WIDGET_IMP initialize_sizeable set_default_minimum_size titled_window ?= Current; if titled_window /= void then show end -- update events from `other'. copy_events_from_other (other) -- Update navigation attribute if other.is_tabable_from then enable_tabable_from else disable_tabable_from end if other.is_tabable_to then enable_tabable_to else disable_tabable_to end -- Is_initialized should be set to True -- when the bridge pattern is linked. set_is_initialized (False) -- Destroy `other' implementation other.safe_destroy end make -- Initialize `Current'. do wel_make (default_parent, "EV_PIXMAP") Precursor {EV_PIXMAP_IMP_DRAWABLE} -- Precursor has set `is_initialized' to True -- but we are still in the middle of our -- initialization. So we set it to False. set_is_initialized (False) widget_initialize end feature -- Loading/Saving read_from_named_path (file_path: PATH) -- Load the pixmap described in `file_path'. -- -- Exceptions "Unable to retrieve icon information", -- "Unable to load the file" do -- If we have already loaded, an icon, then -- we need to remove `internal_mask_bitmap' as it is -- only required for icons. Problem occurs, if you call -- `set_with_named_path' twice, firstly with an icon, and -- then a png file, without the following line, then the -- png would be corrupted/system crash. if attached internal_mask_bitmap as l_internal_mask_bitmap then l_internal_mask_bitmap.decrement_reference internal_mask_bitmap := Void end Precursor {EV_PIXMAP_IMP_DRAWABLE} (file_path) update_display end set_with_default -- Initialize `Current' with the default -- pixmap (vision2 logo). -- -- Exceptions "Unable to retrieve icon information", do Precursor {EV_PIXMAP_IMP_DRAWABLE} update_display end feature -- Status setting stretch (new_width, new_height: INTEGER) -- Stretch `Current' to fit in size -- `new_width' by `new_height'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (new_width, new_height) update_display end set_size (new_width, new_height: INTEGER) -- Resize the `Current'. If the new size -- is smaller than the old one, the bitmap is -- clipped. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (new_width, new_height) update_display end feature -- Clearing and drawing operations redraw -- Force `Current' to redraw itself. do update_display end clear -- Erase `Current' with `background_color'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} update_display end clear_rectangle (x1, y1, a_width, a_height: INTEGER) -- Draw rectangle with upper-left corner on (`x', `y') -- with size `a_width' and `a_height' in `background_color'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x1, y1, a_width, a_height) update_display end feature -- Drawing operations flush -- Execute any delayed calls to `expose_actions' without waiting -- for next idle. do update end draw_point (x, y: INTEGER) -- Draw point at (`x', `y'). do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y) update_display end draw_text (x, y: INTEGER; a_text: READABLE_STRING_GENERAL) -- Draw `a_text' at (`x', `y') using `font'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y, a_text) update_display end draw_segment (x1, y1, x2, y2: INTEGER) -- Draw line segment from (`x1', 'y1') to (`x2', 'y2'). do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x1, y1, x2, y2) update_display end draw_straight_line (x1, y1, x2, y2: INTEGER) -- Draw infinite straight line through (`x1','y1') and (`x2','y2'). do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x1, y1, x2, y2) update_display end draw_arc ( x,y : INTEGER; a_vertical_radius, a_horizontal_radius: INTEGER; a_start_angle, an_aperture: REAL ) -- Draw a part of an ellipse centered on (`x', `y') with -- size `a_vertical_radius' and `a_horizontal_radius'. -- Start at `a_start_angle' and stop at `a_start_angle' -- + `an_aperture'. -- Angles are measured in radians. do Precursor {EV_PIXMAP_IMP_DRAWABLE} ( x, y, a_vertical_radius, a_horizontal_radius, a_start_angle, an_aperture ) update_display end draw_pixmap (x, y: INTEGER; a_pixmap: EV_PIXMAP) -- Draw `a_pixmap' with upper-left corner on (`x', `y'). do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y, a_pixmap) update_display end draw_rectangle (x, y, a_width, a_height: INTEGER) -- Draw rectangle with upper-left corner on (`x', `y') -- with size `a_width' and `a_height'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y, a_width, a_height) update_display end draw_ellipse (x, y, a_vertical_radius, a_horizontal_radius: INTEGER) -- Draw an ellipse centered on (`x', `y') with -- size `a_vertical_radius' and `a_horizontal_radius'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y, a_vertical_radius, a_horizontal_radius) update_display end draw_polyline (points: ARRAY [EV_COORDINATE]; is_closed: BOOLEAN) -- Draw line segments between subsequent points in -- `points'. If `is_closed' draw line segment between first -- and last point in `points'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (points, is_closed) update_display end draw_pie_slice ( x, y: INTEGER; a_vertical_radius, a_horizontal_radius: INTEGER; a_start_angle, an_aperture: REAL ) -- Draw a part of an ellipse centered on (`x', `y') with -- size `a_vertical_radius' and `a_horizontal_radius'. -- Start at `a_start_angle' and stop at `a_start_angle' + -- `an_aperture'. -- The arc is then closed by two segments through (`x', `y'). -- Angles are measured in radians. do Precursor {EV_PIXMAP_IMP_DRAWABLE} ( x, y, a_vertical_radius, a_horizontal_radius, a_start_angle, an_aperture ) update_display end feature -- Filling operations fill_rectangle (x, y, a_width, a_height: INTEGER) -- Draw rectangle with upper-left corner on (`x', `y') -- with size `a_width' and `a_height'. Fill with `foreground_color'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (x, y, a_width, a_height) update_display end fill_ellipse (x, y, a_vertical_radius, a_horizontal_radius: INTEGER) -- Draw an ellipse centered on (`x', `y') with -- size `a_vertical_radius' and `a_horizontal_radius'. -- Fill with `background_color'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} ( x, y, a_vertical_radius, a_horizontal_radius ) update_display end fill_polygon (points: ARRAY [EV_COORDINATE]) -- Draw line segments between subsequent points in `points'. -- Fill all enclosed area's with `foreground_color'. do Precursor {EV_PIXMAP_IMP_DRAWABLE} (points) end fill_pie_slice ( x, y :INTEGER; a_vertical_radius, a_horizontal_radius: INTEGER; a_start_angle, an_aperture: REAL ) -- Draw a part of an ellipse centered on (`x', `y') with -- size `a_vertical_radius' and `a_horizontal_radius'. -- Start at `a_start_angle' and stop at `a_start_angle' + -- `an_aperture'. -- The arc is then closed by two segments through (`x', `y'). -- Angles are measured in radians. do Precursor {EV_PIXMAP_IMP_DRAWABLE} ( x, y, a_vertical_radius, a_horizontal_radius, a_start_angle, an_aperture ) update_display end feature {NONE} -- Implementation copy_pixmap (other_interface: EV_PIXMAP) -- Update `Current' to have same appearence as `other_interface'. -- (So as to satisfy `is_equal'.) do Precursor {EV_PIXMAP_IMP_DRAWABLE} (other_interface) -- As `Current' may be parented, invalidate -- so it is updated on screen. invalidate_without_background end destroy -- Destroy the widget and the internal pixmaps do Precursor {EV_PIXMAP_IMP_DRAWABLE} Precursor {EV_PRIMITIVE_IMP} end class_background: WEL_BRUSH -- Set the class background to NULL in order -- to have full control on the WM_ERASEBKG event -- (on_erase_background) once create Result.make_by_pointer (Default_pointer) end on_erase_background (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT) -- Process Wm_erasebkgnd message. do -- Disable the default windows processing. disable_default_processing -- return a correct value to Windows, i.e. nonzero value -- to tell windows no to erase the background. set_message_return_value (to_lresult (1)) end on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT) -- Wm_paint message. -- May be redefined to paint something on -- the `paint_dc'. `invalid_rect' defines -- the invalid rectangle of the client area that -- needs to be repainted. local l_bitmap_dc: WEL_MEMORY_DC l_bitmap: detachable WEL_BITMAP -- l_mask_bitmap: WEL_BITMAP l_mask_dc: detachable WEL_MEMORY_DC bitmap_top, bitmap_left: INTEGER -- Coordinates of the top-left corner of the -- bitmap inside the drawn area bitmap_right, bitmap_bottom: INTEGER -- Coordinates of the bottom-right corner of the --- bitmap inside the drawn area bitmap_width, bitmap_height: INTEGER window_width, window_height: INTEGER l_background_brush: WEL_BRUSH l_rect: WEL_RECT theme_drawer: EV_THEME_DRAWER_IMP l_back_buffer: WEL_BITMAP l_back_buffer_dc: WEL_MEMORY_DC l_blend_function: WEL_BLEND_FUNCTION l_result: BOOLEAN l_background_region, l_image_region, l_combined_region: WEL_REGION l_bitmap_info: WEL_BITMAP_INFO do if parent /= Void then -- Call expose actions first, any pending invalidations called from 'expose_actions' -- will be expunged at the end of this WM_PAINT message. if expose_actions_internal /= Void then expose_actions.call ([ invalid_rect.x, invalid_rect.y, invalid_rect.width, invalid_rect.height ]) end theme_drawer := application_imp.theme_drawer if attached parent_imp as l_parent_imp and then attached l_parent_imp.background_color_imp as l_background_color_imp then create l_background_brush.make_solid (l_background_color_imp) else create l_background_brush.make_solid (wel_background_color) end l_bitmap := internal_bitmap l_bitmap_dc := dc bitmap_height := height bitmap_width := width window_width := ev_width window_height := ev_height bitmap_left := (window_width - bitmap_width) // 2 bitmap_top := (window_height - bitmap_height) // 2 bitmap_right := bitmap_left + bitmap_width bitmap_bottom := bitmap_top + bitmap_height l_rect := wel_rect l_rect.set_rect (0, 0, window_width, window_height) if internal_mask_bitmap = Void then check l_bitmap /= Void then end create l_bitmap_info.make_by_dc (l_bitmap_dc, l_bitmap, {WEL_DIB_COLORS_CONSTANTS}.dib_rgb_colors) if l_bitmap_info /= Void and then l_bitmap_info.header.bit_count = 32 and then (l_bitmap.ppv_bits /= default_pointer or l_bitmap.is_made_by_dib) then -- Only 32bits DIB bitmap use alpha blend function instead of bit_blt -- Fixed bug#14800 theme_drawer.draw_widget_background (Current, paint_dc, l_rect, l_background_brush) create l_blend_function.make l_result := paint_dc.alpha_blend (bitmap_left, bitmap_top, bitmap_width, bitmap_height, l_bitmap_dc, 0, 0, bitmap_width, bitmap_height, l_blend_function) check successed: l_result = True end l_blend_function.dispose else create l_background_region.make_rect (0, 0, window_width, window_height) create l_image_region.make_rect (bitmap_left, bitmap_top, bitmap_right, bitmap_bottom) l_combined_region := l_background_region.combine (l_image_region, {WEL_RGN_CONSTANTS}.rgn_diff) paint_dc.select_clip_region (l_combined_region) theme_drawer.draw_widget_background (Current, paint_dc, l_rect, l_background_brush) paint_dc.remove_clip_region l_background_region.delete l_image_region.delete l_combined_region.delete paint_dc.bit_blt (bitmap_left, bitmap_top, bitmap_width, bitmap_height, l_bitmap_dc, 0, 0, {WEL_RASTER_OPERATIONS_CONSTANTS}.srccopy) end elseif attached internal_mask_bitmap as l_mask_bitmap then l_mask_dc := mask_dc -- Need to blit to a back buffer to avoid blitting the same pixel twice, which causes flicker. create l_back_buffer.make_compatible (l_bitmap_dc, window_width, window_height) create l_back_buffer_dc.make_by_dc (l_bitmap_dc) l_back_buffer_dc.select_bitmap (l_back_buffer) theme_drawer.draw_widget_background (Current, l_back_buffer_dc, l_rect, l_background_brush) l_back_buffer_dc.mask_blt (bitmap_left, bitmap_top, bitmap_width, bitmap_height, l_bitmap_dc, 0, 0, l_mask_bitmap, 0, 0, {WEL_RASTER_OPERATIONS_CONSTANTS}.maskcopy) paint_dc.bit_blt (0, 0, window_width, window_height, l_back_buffer_dc, 0, 0, {WEL_RASTER_OPERATIONS_CONSTANTS}.srccopy) l_back_buffer_dc.unselect_bitmap l_back_buffer_dc.delete l_back_buffer.delete else check False end end l_background_brush.delete end end on_size (size_type, a_width, a_height: INTEGER_32) -- Wm_size message do -- We want the widget to fully redraw on resize. update_display Precursor (size_type, a_width, a_height) end feature {NONE} -- Implementation update_display -- Update the screen. do -- If the bitmap is exposed, then ask for -- redrawing it (`invalidate' causes -- `paint_bitmap' to be called) if parent /= Void then invalidate_without_background end end feature {NONE} -- Windows events translate_coordinates (a_x, a_y: INTEGER): TUPLE [x, y, screen_x, screen_y: INTEGER] -- For `a_x', `a_y', give actual x and y and screen x and y. local pt: WEL_POINT do pt := client_to_screen (a_x, a_y) Result := [ a_x - (ev_width - width) // 2, a_y - (ev_height - height) // 2, pt.x, pt.y ] end on_left_button_down (keys, x_pos, y_pos: INTEGER) -- Executed when the left button is pressed. -- Redefined as the button press does not set the -- focus automatically. do set_focus Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos) end on_middle_button_down (keys, x_pos, y_pos: INTEGER) -- Executed when the left button is pressed. -- Redefined as the button press does not set the -- focus automatically. do set_focus Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos) end on_right_button_down (keys, x_pos, y_pos: INTEGER) -- Executed when the left button is pressed. -- Redefined as the button press does not set the -- focus automatically. do set_focus Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos) end feature {NONE} -- Private Implementation parented: BOOLEAN -- Is the pixmap in a container? on_parented -- `Current' has just been added to a container -- This has been redefined, as the Precursor updates -- the implementation and we no longer need to perform this. do parented := True end on_orphaned -- `Current' has just been removed from a container -- This has been redefined, as the Precursor updates -- the implementation and we no longer need to perform this. do parented := False end default_style: INTEGER -- Default style that memories the drawings. do Result := Ws_child + Ws_visible + Ws_clipchildren + Ws_clipsiblings end class_style: INTEGER -- Standard style used to create the window class. -- Can be redefined to return a user-defined style. once Result := cs_dblclks | Cs_owndc end feature {EV_ANY, EV_ANY_I} -- Implementation interface: detachable EV_PIXMAP note option: stable attribute end; -- Interface for the bridge pattern. note copyright: "Copyright (c) 1984-2021, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end