From bfd6649ce91680d8e2a8ead2342e0f0a2d6d8a67 Mon Sep 17 00:00:00 2001 From: Adrian Schmid Date: Sun, 2 Jul 2023 15:10:33 +0200 Subject: [PATCH] keyboard controls for the card board --- src/logic-scenes/board/card-board.gd | 208 ++++++++++++++++++++++----- src/logic-scenes/board/card.gd | 1 - src/logic-scenes/board/post-it.gd | 5 + 3 files changed, 180 insertions(+), 34 deletions(-) diff --git a/src/logic-scenes/board/card-board.gd b/src/logic-scenes/board/card-board.gd index d6b7a24..3130171 100644 --- a/src/logic-scenes/board/card-board.gd +++ b/src/logic-scenes/board/card-board.gd @@ -1,33 +1,43 @@ extends PanelContainer var area_dict = {} +enum ui_context {DROPZONE, POST_IT_LIST, ASSIGN_POST_IT} + @onready var dropzone = $HBoxContainer/dropzone +@onready var active_context = ui_context.DROPZONE # 0 = dropzone, 1 = post it list var currently_selected_node: Area2D = null +var currently_selected_card_for_assigning: Area2D = null var is_area_dragged: bool = false var currently_dragged_area: Area2D +var selected_dropzone_element: int = -1 +var selected_postit_list_element: int = 0 +var selected_card_for_assignment + # Called when the node enters the scene tree for the first time. func _ready(): - populate_board() reorder_areas("dropzone_content") - - + + active_context = ui_context.DROPZONE + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): - # Reset information about Areas being dragged, if the mouse is not longer pressed. # Needed because otherwise it can happen that the areas don't register it if you stop clicking on them. if !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and is_area_dragged: currently_dragged_area.is_dragged = false is_area_dragged = false currently_dragged_area = null + + #if active_context == ui_context.ASSIGN_POST_IT: + + # Will be used later to spawn Cards and Post-Its and remember them in the dictionary func populate_board(): - # TODO: Currently populating the dictionary with the Nodes currently in the scene # When opening the scene we need to pass some kind of collection to the Board # Then it can display the Card/PostIts and populate its dictionary at the same time @@ -43,19 +53,19 @@ func populate_board(): area_dict["post_its_in_list"] = post_its # will be selected on the right side currently_selected_node = area_dict["dropzone_content"][0] # set first Card as currently selected node by default - + # Checks if a Node is currently inside the dropzone func is_in_dropzone(to_check: Node) -> bool: - if (dropzone.size.x < to_check.position.x or dropzone.size.y < to_check.position.y): + if (dropzone.size.x < to_check.global_position.x or dropzone.size.y < to_check.global_position.y): return false - elif (to_check.position.x < 0 or to_check.position.y < 0): + elif (to_check.global_position.x < 0 or to_check.global_position.y < 0): return false else: return true + func handle_mouse_button(to_handle: Area2D, input: InputEvent): - # No two areas can be dragged at the same time. # Make sure that only the same area is dragged. # Otherwise overlapping areas are dragged at the same time. @@ -72,6 +82,7 @@ func handle_mouse_button(to_handle: Area2D, input: InputEvent): # Alternative might be to check for specific values within the script ("is_card" f.e)) match to_handle.get_meta("type"): "card": # 1 = Card + active_context = ui_context.DROPZONE if input.is_pressed(): reorder_areas("dropzone_content") else: @@ -85,34 +96,46 @@ func handle_mouse_button(to_handle: Area2D, input: InputEvent): # TODO (if needed): Add function to rearrange the array based on positions in the dropzone else: if is_in_dropzone(to_handle): - if to_handle.has_overlapping_areas(): - var overlaps = to_handle.get_overlapping_areas() - for area in overlaps: - if area.get_meta("type") == "card": - if !area.has_postit_attached(): - to_handle.reparent(area) - to_handle.set_owner(self) - to_handle.position = area.get_child(3).position - else: - to_handle.rotation = to_handle.base_rotation - to_handle.scale = to_handle.base_scale - else: - for panel in area_dict["post_it_panels"]: - if panel.get_child_count() == 1: - to_handle.reparent(panel) - to_handle.set_owner(self) - area_dict["dropzone_content"].erase(to_handle) - area_dict["post_its_in_list"].push_back(to_handle) - to_handle.position = panel.get_child(0).position + if to_handle.has_overlapping_areas(): + for area in to_handle.get_overlapping_areas(): + if area.get_meta("type") == "card": + if !area.has_postit_attached(): + attach_postit_to_card(to_handle, area) + else: to_handle.rotation = to_handle.base_rotation to_handle.scale = to_handle.base_scale - reorder_areas("post_its_in_list") - break + else: + active_context = ui_context.POST_IT_LIST + _return_postit_to_panels(to_handle) currently_dragged_area = null + +# Logic for attaching a postit to a card. Also reset postit positions if the card cannot be attached +func attach_postit_to_card(postit: Area2D, card: Area2D, update_dict = false): + postit.reparent(card) + postit.set_owner(self) + postit.position = card.get_child(3).position + + if update_dict: + area_dict["post_its_in_list"].erase(postit) + area_dict["dropzone_content"].push_back(postit) + + reorder_areas("dropzone_content") + reorder_areas("post_its_in_list") + + +# Mark area that was hovered over as currently selected func handle_hover(to_handle: Area2D): + currently_selected_node.highlighted = false currently_selected_node = to_handle - pass + + if is_in_dropzone(to_handle): + selected_dropzone_element = area_dict["dropzone_content"].find(to_handle) + active_context = ui_context.DROPZONE + else: + selected_postit_list_element = area_dict["post_its_in_list"].find(to_handle) + active_context = ui_context.POST_IT_LIST + # Reorders the areas in any of the dictionaries entries # Pass the entries key in order to reorder it @@ -127,6 +150,125 @@ func reorder_areas(reorder: String): if obj_2.position.y < obj.position.y: i += 1 new_order.insert(i, obj) - - #print_debug(new_order) + + +# Takes the inputs for control inputs +func _input(event): + # Return, if the input is a mouse event (mouse events are handled separately) + if event is InputEventMouse: return + + if event.is_action_pressed("ui_up"): # up to select an element above + match active_context: + ui_context.DROPZONE: + selected_dropzone_element -= 1 + ui_context.POST_IT_LIST: + selected_postit_list_element -= 1 + ui_context.ASSIGN_POST_IT: + selected_card_for_assignment -= 1 + + elif event.is_action_pressed("ui_down"): # down to select an element beneath + match active_context: + ui_context.DROPZONE: + selected_dropzone_element += 1 + ui_context.POST_IT_LIST: + selected_postit_list_element += 1 + ui_context.ASSIGN_POST_IT: + selected_card_for_assignment += 1 + + elif event.is_action_pressed("ui_left"): # left to switch context to the left + active_context -= 1 + if active_context < 0: + active_context = ui_context.POST_IT_LIST + + elif event.is_action_pressed("ui_right"): # right to switch context to the right + active_context += 1 + if active_context > 2: + active_context = ui_context.DROPZONE + + elif event.is_action_pressed("ui_select"): # select the selected post it + if active_context == ui_context.ASSIGN_POST_IT: # to assign it to a card + attach_postit_to_card(currently_selected_node, + currently_selected_card_for_assigning, true) + _leave_assignment_context() + else: + _enter_assignment_context() + + + # do some adjustments to loop elements (after last element, select first one etc.) + if selected_dropzone_element < 0: + selected_dropzone_element = area_dict["dropzone_content"].size()-1 + elif selected_dropzone_element > area_dict["dropzone_content"].size()-1: + selected_dropzone_element = 0 + + if selected_postit_list_element < 0: + selected_postit_list_element = area_dict["post_its_in_list"].size()-1 + elif selected_postit_list_element > area_dict["post_its_in_list"].size()-1: + selected_postit_list_element = 0 + + if active_context == ui_context.ASSIGN_POST_IT: # skip this if we're not in assign post it context + if selected_card_for_assignment < 0: + selected_card_for_assignment = area_dict["dropzone_content"].size()-1 + elif selected_card_for_assignment > area_dict["dropzone_content"].size()-1: + selected_card_for_assignment = 0 + + # highlight the selected element + match active_context: + ui_context.DROPZONE: + currently_selected_node.highlighted = false + currently_selected_node = area_dict["dropzone_content"][selected_dropzone_element] + currently_selected_node.highlighted = true + ui_context.POST_IT_LIST: + currently_selected_node.highlighted = false + currently_selected_node = area_dict["post_its_in_list"][selected_postit_list_element] + currently_selected_node.highlighted = true + ui_context.ASSIGN_POST_IT: + currently_selected_card_for_assigning.highlighted = false + currently_selected_card_for_assigning = area_dict["dropzone_content"][selected_card_for_assignment] + currently_selected_card_for_assigning.highlighted = true + + # update dictiornary orders + reorder_areas("dropzone_content") + reorder_areas("post_its_in_list") + + +# Sets everything up to enter the context where postits can be assigned via button controls +func _enter_assignment_context(): + # cards are currently not moved, only post its. Exit function if a card should be moved. + if currently_selected_node == null or currently_selected_node.get_meta("type") != "post-it" : return + + # if the postit is already attached, remove it and return it to the post it panels + if currently_selected_node.is_postit_attached(): + _return_postit_to_panels(currently_selected_node) + active_context = ui_context.POST_IT_LIST + return + + # adjust everything for the post it to select its attach-target + active_context = ui_context.ASSIGN_POST_IT + selected_card_for_assignment = 0 + currently_selected_card_for_assigning = area_dict["dropzone_content"][0] + currently_selected_card_for_assigning.highlighted = true + + +# leaves the context for assigning postit via button controls +func _leave_assignment_context(): + currently_selected_node.highlighted = false + active_context = ui_context.DROPZONE + currently_selected_node = currently_selected_card_for_assigning + + +# handles everything to return a post it to the panels +func _return_postit_to_panels(postit: Area2D): + for panel in area_dict["post_it_panels"]: + if panel.get_child_count() == 1: + postit.reparent(panel) + postit.set_owner(self) + area_dict["dropzone_content"].erase(postit) + area_dict["post_its_in_list"].push_back(postit) + postit.position = panel.get_child(0).position + postit.rotation = postit.base_rotation + postit.scale = postit.base_scale + reorder_areas("dropzone_content") + reorder_areas("post_its_in_list") + break + diff --git a/src/logic-scenes/board/card.gd b/src/logic-scenes/board/card.gd index ee4e6ca..34c5338 100644 --- a/src/logic-scenes/board/card.gd +++ b/src/logic-scenes/board/card.gd @@ -121,7 +121,6 @@ func _move_card(): func has_postit_attached() -> bool: var all_children = get_children() - print_debug(all_children) for child in all_children: if child.get_meta("type") == "post-it": return true diff --git a/src/logic-scenes/board/post-it.gd b/src/logic-scenes/board/post-it.gd index cd37efd..246cf8c 100644 --- a/src/logic-scenes/board/post-it.gd +++ b/src/logic-scenes/board/post-it.gd @@ -97,3 +97,8 @@ func _move_post_it(): if is_dragged: position += get_viewport().get_mouse_position() - position +func is_postit_attached() -> bool: + if self.get_parent().get_meta("type") == "card": + return true + return false +