extends Control # A scene displaying the poll results as linear merit profiles. # This scene is updated dynamically as the poll receives new judgments. const MeritProfileScene = preload("res://addons/majority_judgment/nodes/MajorityJudgmentMeritProfileControl.tscn") export(Resource) var poll setget set_poll, get_poll export(int) var vertical_gap := 4 # pixels export(int) var candidates_labels_width := 200 # pixels export(bool) var align_with_bottom := false # pixels export(int) var padding_with_window_top := 20 # pixels export(int) var padding_with_window_bottom := 95 # pixels onready var ClosePollButton = find_node("ClosePollButton", true) onready var ClosePollDialog = find_node("ClosePollConfirmationDialog", true) onready var ProfilesContainer = find_node("ProfilesContainer", true) var providers:Array # of MajorityJudgmentAbstractJudgmentsProvider #var provider:MajorityJudgmentAbstractJudgmentsProvider func _ready(): ClosePollDialog.connect("confirmed", self, "close_and_exit") func _input(_event): if Input.is_action_just_pressed("ui_cancel"): prompt_close_and_exit() if Input.is_action_just_pressed("ui_toggle_elements"): ClosePollButton.visible = not ClosePollButton.visible func prompt_close_and_exit(): ClosePollDialog.popup_centered() func close_and_exit(): close_poll() exit_scene() func exit_scene(): # Close things up # stop_providers() App.go_to_main_menu() func get_poll() -> MajorityJudgmentPoll: return poll func set_poll(__poll:MajorityJudgmentPoll): poll = __poll craft_nodes() update_scene() App.save_ongoing_poll() self.providers = App.get_providers() for provider in self.providers: start_provider(provider) func close_poll(): App.close_ongoing_poll() var candidates_lines_nodes := Array() var profiles_nodes := Array() func craft_nodes(): var tally : MajorityJudgmentPollTally = get_poll().tally() var candidate_index = 0 # as they were initially written, before the sort for candidate in get_poll().get_candidates(): var profile = create_merit_profile_scene(6) if tally: profile.refresh(tally.get_tally_of_candidate(candidate).merit_profile) var height = profile.compute_height() profile.rect_min_size = Vector2(400, height) var container = self.ProfilesContainer var wrapper = HBoxContainer.new() wrapper.name = "Candidate%sLine" % char(candidate_index+65) wrapper.anchor_right = 1.0 # wrapper.rect_min_size = Vector2(400, height) var position = candidate_index if tally: position = tally.get_position_of_candidate(candidate, true) wrapper.margin_top = position * (height + vertical_gap) wrapper.margin_bottom = wrapper.margin_top + height self.candidates_lines_nodes.append(wrapper) var candidate_label = Label.new() candidate_label.name = "CandidateLabel" candidate_label.text = candidate.get_name() candidate_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL # candidate_label.size_flags_vertical = Control.SIZE_EXPAND_FILL candidate_label.rect_min_size = Vector2(candidates_labels_width, height) candidate_label.rect_size = Vector2(candidates_labels_width, height) candidate_label.clip_text = true candidate_label.autowrap = true candidate_label.valign = Label.VALIGN_CENTER candidate_label.align = Label.ALIGN_RIGHT var candidate_font = preload("res://addons/majority_judgment/fonts/KenneyMini.tres") candidate_font.set_size(int(height*0.62)) candidate_label.set("custom_fonts/font", candidate_font) var candidate_letter := Label.new() candidate_letter.name = "CandidateLetterLabel" candidate_letter.text = char(candidate_index+65) # candidate_letter.size_flags_horizontal = Control.SIZE_EXPAND_FILL # candidate_letter.size_flags_vertical = Control.SIZE_EXPAND_FILL candidate_letter.rect_min_size = Vector2(height, height) # candidate_letter.rect_size = Vector2(candidates_labels_width, height) candidate_letter.valign = Label.VALIGN_CENTER candidate_letter.align = Label.ALIGN_CENTER var letter_font = preload("res://addons/majority_judgment/fonts/KenneyMiniSquare.tres") letter_font.set_size(height*0.75) candidate_letter.set("custom_fonts/font", letter_font) wrapper.add_child(candidate_label) wrapper.add_child(candidate_letter) wrapper.add_child(profile) container.add_child(wrapper) # wrapper.margin_top = position * height # wrapper.margin_bottom = wrapper.margin_top + height candidate_label.owner = self profile.owner = self wrapper.owner = self self.profiles_nodes.append(profile) candidate_index += 1 func update_scene(): $Tween.remove_all() var tally : MajorityJudgmentPollTally = get_poll().tally() var candidate_index = 0 # as they were initially written, before the sort var candidates_amount = get_poll().count_candidates() var container_height = $ProfilesContainer.rect_size.y for candidate in get_poll().get_candidates(): var profile = profiles_nodes[candidate_index] var candidate_line_node = self.candidates_lines_nodes[candidate_index] var position = candidate_index var height = profile.compute_height() if tally: position = tally.get_position_of_candidate(candidate, true) var tween_transition = Tween.TRANS_SINE var tween_ease = Tween.EASE_IN_OUT var tween_duration = 0.818 var tween_delay = 0 var cln_margin_top = position * (height + vertical_gap) if align_with_bottom: cln_margin_top += ( container_height - candidates_amount * (height + vertical_gap) - padding_with_window_bottom ) else: cln_margin_top += padding_with_window_top $Tween.interpolate_property( candidate_line_node, "margin_top", candidate_line_node.margin_top, cln_margin_top, tween_duration, tween_transition, tween_ease, tween_delay ) $Tween.interpolate_property( candidate_line_node, "margin_bottom", candidate_line_node.margin_bottom, cln_margin_top + height, tween_duration, tween_transition, tween_ease, tween_delay ) $Tween.start() # candidate_line_node.margin_top = position * (height + vertical_gap) # candidate_line_node.margin_bottom = wrapper.margin_top + height if tally: var merit = tally.get_tally_of_candidate(candidate).merit_profile profile.refresh(merit) else: var merit = poll.get_dummy_merit_profile(candidate) profile.refresh(merit) candidate_index += 1 func create_merit_profile_scene(gradation_size:int): var mps = MeritProfileScene.instance() mps.set_poll(get_poll()) mps.craft_nodes(gradation_size) return mps func start_provider(__provider): # self.provider = __provider var connected = __provider.connect( "judgment_emitted", self, "__on_judgment_emitted" ) __provider.start_providing() var known_participants := Dictionary() # id => Participant func get_or_create_participant(identifier:String) -> MajorityJudgmentParticipant: if not known_participants.has(identifier): known_participants[identifier] = MajorityJudgmentParticipant.make(identifier) return known_participants[identifier] var __save_mutex := Mutex.new() # perhaps overzealous func __on_judgment_emitted(author_identifier, grade_index, candidate_index): # Data comes from userland, best be careful here if ( grade_index < 0 or grade_index >= poll.grading.grades.size() ): # printerr("Ignoring grade #%d since it's out of range.") return if ( candidate_index < 0 or candidate_index >= poll.candidates.size() ): # printerr("Ignoring candidate %s since it's out of range." % [char(candidate_index)]) return __save_mutex.lock() var j = MajorityJudgmentJudgment.new() j.set_participant(get_or_create_participant(author_identifier)) j.set_grade(poll.grading.grades[grade_index]) j.set_candidate(poll.candidates[candidate_index]) poll.add_judgment(j) App.save_ongoing_poll() __save_mutex.unlock() update_scene() func _on_ClosePollButton_pressed(): prompt_close_and_exit()