extends MarginContainer export( bool ) var is_movable = true export( bool ) var is_resizable = true export( bool ) var is_borderless = false export( bool ) var has_footer = true export( bool ) var has_scrollbar = true export( bool ) var is_dragged_by_header_only = true export( String ) var title = "Window" export( Color ) var content_color = Color( 1.0, 1.0, 1.0, 1.0 )# test export( Color ) var background_color = Color( 1.0, 1.0, 1.0, 1.0 ) export( Texture ) var background_texture = null export( Vector2 ) var min_size = Vector2( 128, 128 ) export( Rect2 ) var content_margin = Rect2( 8, 8, 8, 8 ) signal window_clicked( window ) onready var header_box = $parts/header_box onready var content_box = $parts/content_box onready var footer_box = $parts/footer_box var current_rect_size = Vector2( 0, 0 ) var current_rect_position = Vector2( -1, -1 ) var is_resizing = false var is_moving = false var size_changed = true func add_child_to_content( node): if self.get_content(): self.get_content().add_child(node) func add_window_part( node ): add_child( node ) func set_mouse_pass_to_children( node ): for child in node.get_children(): set_mouse_pass_to_children( child ) if node is Control: node.mouse_filter = MOUSE_FILTER_PASS #func _ready(): func _enter_tree(): ######## #### Window's part création. # The internal elements structure is: # self - MarginContainer # background - NinePatchRect # parts - VBoxContainer # header_box - MarginContainer # header - HBoxContainer # quit - TextureButton # close - TextureButton # open - TextureButton # label - Label # content_box - MarginContainer # scroll_container - Scrollcontainer # content - VBoxContainer # footer_box - MarginContainer # footer - HBoxContainer # contextual_help - Label # resize - TextureButton ### # self self.size_flags_horizontal = SIZE_EXPAND self.size_flags_vertical = SIZE_EXPAND self.set( "custom_constants/margin_right", 0) self.set( "custom_constants/margin_top", 0) self.set( "custom_constants/margin_left", 0) self.set( "custom_constants/margin_bottom", 0) self.connect ( "gui_input", self, "_on_window_gui_input" ) if is_movable and not self.is_dragged_by_header_only: self.mouse_default_cursor_shape = CURSOR_MOVE ### ### # background var background if not self.has_node( "background" ): background = NinePatchRect.new() background.name = "background" if not background_texture: # var background_image = Image.new() # var stream_texture = load('res://addons/ui_window/background_default.jpg') # if not stream_texture : # print("Erreur lors du chargement de l'image: "+str("res://addons/ui_window/background_default.jpg") ) # else: # background_image = stream_texture.get_data() # background.texture = ImageTexture.new() # background.texture.create_from_image( background_image ) # background.texture.flags = Texture.FLAG_FILTER | Texture.FLAG_REPEAT pass else: background.texture = background_texture background.texture.flags = Texture.FLAG_FILTER | Texture.FLAG_REPEAT background.axis_stretch_horizontal = NinePatchRect.AXIS_STRETCH_MODE_TILE background.axis_stretch_vertical = NinePatchRect.AXIS_STRETCH_MODE_TILE background.size_flags_horizontal = SIZE_EXPAND_FILL background.size_flags_vertical = SIZE_EXPAND_FILL background.region_rect = Rect2( 0, 0, 0, 0 ) background.patch_margin_left = 4 background.patch_margin_top = 32 background.patch_margin_right = 4 background.patch_margin_bottom = 4 background.self_modulate = background_color self.add_window_part( background ) # background.set_owner( self ) ### ### # parts var parts if not self.has_node( "parts" ): parts = VBoxContainer.new() parts.name = "parts" parts.size_flags_horizontal = SIZE_EXPAND_FILL parts.size_flags_vertical = SIZE_EXPAND_FILL self.add_window_part( parts ) # parts.set_owner( self ) ### ### # header_box var header_box if not parts.has_node( "header_box" ): header_box = MarginContainer.new() header_box.name = "header_box" header_box.size_flags_horizontal = SIZE_EXPAND_FILL header_box.size_flags_vertical = SIZE_SHRINK_CENTER header_box.set( "custom_constants/margin_right", 4) header_box.set( "custom_constants/margin_top", 4) header_box.set( "custom_constants/margin_left", 4) header_box.set( "custom_constants/margin_bottom", 4) if is_movable: header_box.mouse_default_cursor_shape = CURSOR_MOVE parts.add_child( header_box ) # header_box.set_owner( parts ) header_box.connect ( "gui_input", self, "_on_Header_gui_input" ) ### ### # header var header if not header_box.has_node( "header" ): header = HBoxContainer.new() header.name = "header" header.size_flags_horizontal = SIZE_EXPAND_FILL header.size_flags_vertical = SIZE_EXPAND | SIZE_SHRINK_CENTER if is_movable: header.mouse_default_cursor_shape = CURSOR_MOVE header_box.add_child( header ) # header.set_owner( header_box ) ### ### # quit var quit_button if not header.has_node( "quit" ): quit_button = TextureButton.new() quit_button.name = "quit" quit_button.size_flags_horizontal = SIZE_SHRINK_END quit_button.size_flags_vertical = SIZE_SHRINK_CENTER var tex_quit = ImageTexture.new() var img_quit = Image.new() var stream_texture = load( "res://addons/kh_window/button_quit.png") img_quit = stream_texture.get_data() tex_quit.create_from_image( img_quit ) quit_button.texture_normal = tex_quit header.add_child( quit_button ) # quit_button.set_owner( header ) quit_button.connect ( "pressed", self, "_on_Quit_pressed" ) ### # close var close_button = TextureButton.new() if not header.has_node( "close" ): close_button = TextureButton.new() close_button.name = "close" close_button.size_flags_horizontal = SIZE_SHRINK_END close_button.size_flags_vertical = SIZE_SHRINK_CENTER var tex_close = ImageTexture.new() var img_close = Image.new() var stream_texture = load("res://addons/kh_window/button_close.png") img_close = stream_texture.get_data() tex_close.create_from_image( img_close ) close_button.texture_normal = tex_close header.add_child( close_button ) # close_button.set_owner( header ) close_button.connect ( "pressed", self, "_on_Close_pressed" ) ### # open var open_button if not header.has_node( "open" ): open_button = TextureButton.new() open_button.name = "open" open_button.size_flags_horizontal = SIZE_SHRINK_END open_button.size_flags_vertical = SIZE_SHRINK_CENTER var tex_open = ImageTexture.new() var img_open = Image.new() var stream_texture = load("res://addons/kh_window/button_open.png") img_open = stream_texture.get_data() tex_open.create_from_image( img_open ) open_button.texture_normal = tex_open open_button.visible = false header.add_child( open_button ) # open_button.set_owner( header ) open_button.connect ( "pressed", self, "_on_Open_pressed" ) ### ### # Title Label var title_label if not header.has_node( "label" ): title_label = Label.new() title_label.name = "label" title_label.text = title title_label.size_flags_horizontal = SIZE_EXPAND_FILL title_label.size_flags_vertical = SIZE_SHRINK_CENTER if is_movable: title_label.mouse_default_cursor_shape = CURSOR_MOVE header.add_child( title_label ) # title_label.set_owner( header ) ### ### # Content var content_box if not parts.has_node( "content_box" ): content_box = MarginContainer.new() content_box.name = "content_box" content_box.size_flags_horizontal = SIZE_EXPAND_FILL content_box.size_flags_vertical = SIZE_EXPAND_FILL content_box.set( "custom_constants/margin_right", 8) content_box.set( "custom_constants/margin_top", 8) content_box.set( "custom_constants/margin_left", 8) content_box.set( "custom_constants/margin_bottom", 8) parts.add_child( content_box ) # content_box.set_owner( parts ) ### ### if self.has_scrollbar: # content_box/scroll_container var content_scroll_container if not content_box.has_node( "scroll_container" ): content_scroll_container = ScrollContainer.new() content_scroll_container.name = "scroll_container" content_scroll_container.size_flags_horizontal = SIZE_FILL content_scroll_container.size_flags_vertical = SIZE_FILL content_scroll_container.scroll_deadzone = 0 content_box.add_child( content_scroll_container ) # content_scroll_container.set_owner( content_box ) ### ### # content var content if not content_scroll_container.has_node( "content" ): content = MarginContainer.new() content.name = "content" content.size_flags_horizontal = SIZE_EXPAND_FILL content.size_flags_vertical = SIZE_EXPAND_FILL content_scroll_container.add_child( content ) # content.set_owner( content_scroll_container ) ### else: var content if not content_box.has_node( "content" ): content = MarginContainer.new() content.name = "content" content.size_flags_horizontal = SIZE_EXPAND_FILL content.size_flags_vertical = SIZE_EXPAND_FILL content_box.add_child( content ) ### # Footer var footer_box if not parts.has_node( "footer_box" ): footer_box = MarginContainer.new() footer_box.name = "footer_box" footer_box.size_flags_horizontal = SIZE_FILL footer_box.size_flags_vertical = SIZE_FILL footer_box.set( "custom_constants/margin_right", content_margin.position.y) footer_box.set( "custom_constants/margin_top", content_margin.size.x) footer_box.set( "custom_constants/margin_left", content_margin.position.x) footer_box.set( "custom_constants/margin_bottom", content_margin.size.y) parts.add_child( footer_box ) # footer_box.set_owner( parts ) ### ### # footer_box/footer var footer if not footer_box.has_node( "footer" ): footer = HBoxContainer.new() footer.name = "footer" footer.size_flags_horizontal = SIZE_EXPAND_FILL footer.size_flags_vertical = SIZE_EXPAND_FILL footer_box.add_child( footer ) # footer.set_owner( footer_box ) ### ### # footer_label var footer_label if not footer.has_node( "footer_label" ): footer_label = Label.new() footer_label.name = "footer_label" footer_label.size_flags_horizontal = SIZE_EXPAND footer_label.size_flags_vertical = SIZE_EXPAND footer.add_child( footer_label ) ### # resize var resize_button if not footer.has_node( "resize" ): resize_button = TextureButton.new() resize_button.name = "resize" resize_button.size_flags_horizontal = SIZE_FILL | SIZE_SHRINK_END resize_button.size_flags_vertical = SIZE_SHRINK_END var tex_resize = ImageTexture.new() var img_resize = Image.new() var stream_texture = load("res://addons/kh_window/button_resize.png") img_resize = stream_texture.get_data() tex_resize.create_from_image( img_resize ) resize_button.texture_normal = tex_resize resize_button.mouse_default_cursor_shape = CURSOR_FDIAGSIZE resize_button.action_mode = Button.ACTION_MODE_BUTTON_PRESS # resize_button.mouse_filter = MOUSE_FILTER_STOP footer.add_child( resize_button ) # resize_button.set_owner( footer ) resize_button.connect ( "button_down", self, "_on_Resize_pressed" ) ###er_label.set_owner( footer ) ### current_rect_size = self.rect_min_size if is_borderless: $background.region_rect = Rect2( $background.patch_margin_left-1 , $background.patch_margin_top-1 , 256-($background.patch_margin_left+$background.patch_margin_right)+2 , 256-($background.patch_margin_top+$background.patch_margin_bottom)+2 ) $background.patch_margin_left = 1 $background.patch_margin_top = 1 $background.patch_margin_right = 1 $background.patch_margin_bottom = 1 header_box.rect_min_size.y = 1 close_button.visible = false open_button.visible = false quit_button.visible = false title_label.visible = false if not is_resizable: if not has_footer: footer_box.visible = false else: footer_box.get_node( "footer/resize" ).visible = false func _ready(): # On déplace les enfants ajouter via l'editeur sous content. for child in self.get_children(): if not child.name =="parts" and not child.name =="background": if child.name.begins_with( "footer_" ): if footer_box.get_node("footer").has_node("footer_label"): footer_box.get_node("footer").remove_child( footer_box.get_node("footer").get_node("footer_label") ) self.remove_child( child ) get_footer().add_child( child ) get_footer().move_child( child, 0 ) else: self.remove_child( child ) get_content().add_child( child ) set_mouse_pass_to_children( self ) func _process(delta): if size_changed: self.rect_size = Vector2( clamp( self.rect_size.x, min_size.x, self.rect_size.x ), clamp( self.rect_size.y, min_size.y, self.rect_size.y ) ) size_changed = false func _on_Window_mouse_entered(): print("mouse_entered") func _on_Window_focus_entered(): print("focus_entered") func _on_Quit_pressed(): self.visible = false func get_content_child( p_node ): return get_content().get_node( p_node ) func get_content(): if self.has_scrollbar: return content_box.get_node( "scroll_container/content" ) else: return content_box.get_node( "content" ) func get_footer(): return footer_box.get_node( "footer" ) func close(): if not self.is_borderless: self.header_box.get_node( "header/close" ).visible = false self.header_box.get_node( "header/open" ).visible = true self.content_box.visible = false self.footer_box.visible = false self.current_rect_size = self.rect_size self.rect_size = Vector2( 0, 0 ) $background.rect_size = Vector2( 0, 0 ) $background.rect_min_size = Vector2( 0, 0 ) else: self.header_box.get_node( "header/close" ).visible = false self.header_box.get_node( "header/open" ).visible = false self.content_box.visible = false self.footer_box.visible = false self.current_rect_size = self.rect_size self.rect_size = Vector2( 0, 0 ) $background.rect_size = Vector2( 0, 0 ) $background.rect_min_size = Vector2( 0, 0 ) func _on_Close_pressed(): close() func open(): if not is_borderless: header_box.get_node( "header/close" ).visible = true header_box.get_node( "header/open" ).visible = false content_box.visible = true footer_box.visible = true self.rect_size = current_rect_size else: header_box.get_node( "header/close" ).visible = false header_box.get_node( "header/open" ).visible = false content_box.visible = true footer_box.visible = true self.rect_size = current_rect_size func _on_Open_pressed(): open() func _on_Resize_pressed(): is_resizing = true func _input( event ): if is_resizable: if is_resizing and event is InputEventMouseButton and not event.pressed: is_resizing = false if event is InputEventMouseMotion and is_resizing: var delta = event.relative self.rect_size += delta size_changed = true func check_if_clicked( event ): if not is_moving and event is InputEventMouseButton and event.is_pressed() and not event.is_echo() and event.button_index == 1 : emit_signal( "window_clicked", self ) func _on_Header_gui_input( event ): check_if_clicked( event ) if self.is_dragged_by_header_only: if is_movable: if is_moving and event is InputEventMouseButton and not event.pressed: is_moving = false elif not is_moving and event is InputEventMouseButton and event.pressed: is_moving = true if event is InputEventMouseMotion and is_moving: var delta = event.relative self.rect_position += delta func _on_window_gui_input( event ): check_if_clicked( event ) if not self.is_dragged_by_header_only: if is_movable: if is_moving and event is InputEventMouseButton and not event.pressed: is_moving = false elif not is_moving and event is InputEventMouseButton and event.pressed: is_moving = true if event is InputEventMouseMotion and is_moving: var delta = event.relative self.rect_position += delta func load_from_file( config_file ): print("[res://addons/kh_window/kh_window.gd] load_from_file") if config_file.has_section( self.name ): self.rect_position = config_file.get_value( self.name, "position" ) self.rect_size = config_file.get_value( self.name, "size" ) self.is_borderless = config_file.get_value( self.name, "borderless" ) current_rect_position = self.rect_position current_rect_size = self.rect_size if config_file.get_value( self.name, "opened" ): open() else: close() func save_to_file( config_file ): var is_open = content_box.visible config_file.set_value(self.name, "position", self.rect_position) if not is_open: config_file.set_value(self.name, "size", current_rect_size) else: config_file.set_value(self.name, "size", self.rect_size) if is_open: config_file.set_value(self.name, "opened", true) else: config_file.set_value(self.name, "opened", false) config_file.set_value(self.name, "borderless", is_borderless)