note description: "Tab stubs on SD_AUTO_HIDE_PANEL." legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" class SD_TAB_STUB inherit SD_HOR_VER_BOX SD_ACCESS undefine default_create, is_equal, copy end create make feature {NONE} -- Initlization make (a_content: SD_CONTENT; a_direction: INTEGER) -- Creation method. -- If a_vertical True then vertical style otherwise horizontal style require a_content_not_void: a_content /= Void a_direction_valid: a_direction = {SD_ENUMERATION}.top or a_direction = {SD_ENUMERATION}.bottom or a_direction = {SD_ENUMERATION}.left or a_direction = {SD_ENUMERATION}.right do create internal_shared create internal_drawing_area create pointer_press_actions create delay_timer content := a_content internal_docking_manager := a_content.docking_manager create internal_text.make_empty if a_direction = {SD_ENUMERATION}.left or a_direction = {SD_ENUMERATION}.right then create internal_box.init (True) init (True) else create internal_box.init (False) init (False) end extend (internal_box) internal_box.extend (internal_drawing_area) internal_box.disable_item_expand (internal_drawing_area) internal_drawing_area.expose_actions.extend (agent on_expose) internal_drawing_area.pointer_enter_actions.extend (agent on_pointer_enter) internal_drawing_area.pointer_button_press_actions.extend (agent on_pointer_press) set_padding_width (internal_shared.padding_width) is_show_text := True init_separator (a_direction) set_text (a_content.short_title) on_expose (0, 0, internal_drawing_area.width, internal_drawing_area.height) ensure set: content = a_content drawing_area_added: internal_box.has (internal_drawing_area) set: internal_docking_manager = a_content.docking_manager end init_separator (a_direction: INTEGER) -- Initialization base on `a_direction' require a_direction_valid: a_direction = {SD_ENUMERATION}.top or a_direction = {SD_ENUMERATION}.bottom or a_direction = {SD_ENUMERATION}.left or a_direction = {SD_ENUMERATION}.right do inspect a_direction when {SD_ENUMERATION}.top then set_draw_separator_left (True) set_draw_separator_bottom (True) set_draw_separator_right (True) when {SD_ENUMERATION}.bottom then set_draw_separator_left (True) set_draw_separator_top (True) set_draw_separator_right (True) when {SD_ENUMERATION}.left then set_draw_separator_top (True) set_draw_separator_right (True) set_draw_separator_bottom (True) when {SD_ENUMERATION}.right then set_draw_separator_top (True) set_draw_separator_left (True) set_draw_separator_bottom (True) end end on_theme_changed -- Handle theme changed actions local l_colors: SD_SYSTEM_COLOR do create {SD_SYSTEM_COLOR_IMP} l_colors.make internal_drawing_area.set_background_color (l_colors.default_background_color) end feature -- Query text: STRING_32 -- Title do Result := internal_text end text_width: INTEGER -- Width of title -- Used for calculate max size in tab group do Result := internal_drawing_area.font.string_width (internal_text) end text_size: INTEGER -- Width/Height `internal_text' should extend to. It's max size in tab group content: SD_CONTENT -- Which content current is represent pointer_press_actions: EV_NOTIFY_ACTION_SEQUENCE -- Pointer press actions is_group_auto_hide_zone_showing: BOOLEAN -- If auto hide zone belong to our group showing? do if attached tab_group as l_group then from l_group.start until l_group.after or Result loop if l_group.item /= Current and then attached l_group.item.content.state.zone as z then if attached {EV_WIDGET} z as lt_widget then Result := not lt_widget.is_destroyed else check not_possible: False end end end l_group.forth end end end feature -- Command set_text (a_text: READABLE_STRING_GENERAL) -- Set `title' do internal_text := a_text.as_string_32 set_text_size (internal_shared.tool_bar_font.string_width (a_text)) update_size_internal on_expose (0, 0, internal_drawing_area.width, internal_drawing_area.height) ensure set: a_text /= Void implies internal_text.same_string_general (a_text) end set_text_size (a_size: INTEGER) -- Set text width with `a_size' require a_size_valid: a_size >= 0 do text_size := a_size ensure set: text_size = a_size end set_auto_hide_panel (a_panel: SD_AUTO_HIDE_PANEL) -- Set `auto_hide_panel' with `a_panel' require a_panel_not_void: a_panel /= Void do auto_hide_panel := a_panel ensure set: auto_hide_panel = a_panel end feature -- Properties set_draw_separator_top (a_draw: BOOLEAN) -- Set `is_draw_separator_top' do is_draw_separator_top := a_draw ensure set: is_draw_separator_top = a_draw end set_draw_separator_bottom (a_draw: BOOLEAN) -- Set `is_draw_separator_bottom' do is_draw_separator_bottom := a_draw ensure set: is_draw_separator_bottom = a_draw end set_draw_separator_left (a_draw: BOOLEAN) -- Set `is_draw_separator_left' do is_draw_separator_left := a_draw ensure set: is_draw_separator_left = a_draw end set_draw_separator_right (a_draw: BOOLEAN) -- Set `is_draw_separator_right' do is_draw_separator_right := a_draw ensure set: is_draw_separator_right = a_draw end is_draw_separator_top, is_draw_separator_bottom, is_draw_separator_left, is_draw_separator_right: BOOLEAN -- Draw separator at top/botoom/left/right? set_show_text (a_show: BOOLEAN) -- If `a_show' True, show title -- Vice visa do if not internal_shared.show_all_tab_stub_text then is_show_text := a_show end update_size_internal on_expose (0, 0, internal_drawing_area.width, internal_drawing_area.height) ensure set: not internal_shared.show_all_tab_stub_text implies is_show_text = a_show end is_show_text: BOOLEAN -- Draw text on `internal_drawing_area'? feature {SD_DOCKING_MANAGER_AGENTS} -- Agents on_pointer_enter -- Handle pointer enter do if attached tab_group as l_tab_group then internal_docking_manager.command.lock_update (Void, True) from l_tab_group.start until l_tab_group.after loop if l_tab_group.item = Current then l_tab_group.item.set_show_text (True) else l_tab_group.item.set_show_text (False) end l_tab_group.forth end internal_docking_manager.command.unlock_update if is_group_auto_hide_zone_showing then -- We must show immediately pointer_enter_actions.call (Void) else delay_timer.actions.extend_kamikaze (agent on_delay_timer) delay_timer.set_interval ({SD_SHARED}.auto_hide_tab_stub_show_delay) end end end on_pointer_press (a_x: INTEGER_32; a_y: INTEGER_32; a_button: INTEGER_32; a_x_tilt: REAL_64; a_y_tilt: REAL_64; a_pressure: REAL_64; a_screen_x: INTEGER_32; a_screen_y: INTEGER_32) -- Handle pointer press actions do pointer_press_actions.call (Void) end on_delay_timer -- Handle `delay_timer' actions. local l_rect: EV_RECTANGLE l_point: EV_COORDINATE do l_point := (create {EV_SCREEN}).pointer_position create l_rect.make (screen_x, screen_y, width, height) if l_rect.has_x_y (l_point.x, l_point.y) then -- If pointer still in current area pointer_enter_actions.call (Void) end delay_timer.set_interval (0) end feature {SD_AUTO_HIDE_STATE} -- Expose handling on_expose (a_x: INTEGER; a_y: INTEGER; a_width: INTEGER; a_height: INTEGER) -- Handle redraw. do internal_drawing_area.set_background_color (internal_shared.default_background_color) internal_shared.setter.clear_background_for_theme (internal_drawing_area, create {EV_RECTANGLE}.make (0, 0, internal_drawing_area.width, internal_drawing_area.height)) internal_drawing_area.draw_pixmap (start_x_pixmap_internal, start_y_pixmap_internal, content.pixmap) if is_show_text then internal_drawing_area.set_foreground_color ((create {EV_STOCK_COLORS}).black) internal_drawing_area.set_font (internal_shared.tool_bar_font) if not is_vertical then internal_drawing_area.draw_text_top_left (start_x_text_internal, start_y_text_internal, internal_text) else if attached {EV_DRAWING_AREA_IMP} internal_drawing_area.implementation as l_imp then l_imp.draw_rotated_text (start_x_text_internal, start_y_text_internal, {MATH_CONST}.pi.truncated_to_real * {REAL_32} 1.5, internal_text) end end end internal_drawing_area.set_foreground_color (internal_shared.border_color) if is_draw_separator_top then internal_drawing_area.draw_segment (0, 0, internal_drawing_area.width - 1, 0) end if is_draw_separator_bottom then internal_drawing_area.draw_segment (0, internal_drawing_area.height - 1, internal_drawing_area.width - 1, internal_drawing_area.height - 1) end if is_draw_separator_left then internal_drawing_area.draw_segment (0, 0, 0, internal_drawing_area.height - 1) end if is_draw_separator_right then internal_drawing_area.draw_segment (internal_drawing_area.width - 1, 0, internal_drawing_area.width - 1, internal_drawing_area.height - 1) end end feature {NONE} -- Implementation update_size_internal -- Update minmum size base on direction and `is_show_text' local l_size: INTEGER do if is_vertical then l_size := content.pixmap.height + 2 * padding_width if is_show_text then l_size := l_size + text_size + padding_width end internal_drawing_area.set_minimum_height (l_size) else l_size := padding_width + content.pixmap.width + padding_width if is_show_text then l_size := l_size + text_size + padding_width end internal_drawing_area.set_minimum_width (l_size) end end start_x_pixmap_internal: INTEGER -- Start x position when `on_draw' draw pixmap do if is_draw_separator_left then Result := Result + 1 end if not is_vertical then Result := Result + padding_width else Result := Result + (width / 2 - content.pixmap.width / 2).floor end end start_y_pixmap_internal: INTEGER -- Start y position when `on_draw' draw pixmap do if is_draw_separator_top then Result := Result + 3 end if is_vertical then Result := Result + padding_width // 2 else Result := (height / 2 - content.pixmap.height / 2).floor end end start_x_text_internal: INTEGER -- Start x position when `on_draw' draw text local l_platform: PLATFORM do if not is_vertical then Result := start_x_pixmap_internal + content.pixmap.width + padding_width else create l_platform if l_platform.is_windows then Result := (width / 2 - internal_shared.tool_bar_font.height / 2).floor + 3 else Result := (width / 2 + internal_shared.tool_bar_font.height / 2).floor - 8 end end end start_y_text_internal: INTEGER -- Start y position when `on_draw' draw text local l_platform: PLATFORM do if not is_vertical then create l_platform Result := (height / 2 - internal_shared.tool_bar_font.height / 2).floor - 1 if l_platform.is_windows then Result := Result - 1 end else Result := start_y_pixmap_internal + content.pixmap.height + padding_width // 2 end end internal_box: SD_HOR_VER_BOX -- Box contain `internal_drawing_area' and `internal_label' tab_group: detachable ARRAYED_LIST [SD_TAB_STUB] -- Tab group `Current' belongs to (if any). do if attached auto_hide_panel as l_panel then Result := l_panel.tab_group (Current) end end delay_timer: EV_TIMEOUT -- Delay timer to call `pointer_enter_actions' auto_hide_panel: detachable SD_AUTO_HIDE_PANEL -- Panel current is in internal_drawing_area: EV_DRAWING_AREA -- Drawing area draw `internal_pixmap' internal_text: STRING_32 -- Text on `internal_drawing_area' internal_shared: SD_SHARED -- All singletons internal_docking_manager: SD_DOCKING_MANAGER -- Docking manager manage Current invariant internal_shared_not_void: internal_shared /= Void internal_drawing_area_not_void: internal_drawing_area /= Void pointer_press_actions_not_void: pointer_press_actions /= Void note library: "SmartDocking: Library of reusable components for Eiffel." copyright: "Copyright (c) 1984-2017, 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