void PopupMenu::_submenu_timeout() { if (mouse_over==submenu_over) { _activate_submenu(mouse_over); submenu_over=-1; } }
void PopupMenu::_input_event(const InputEvent &p_event) { switch( p_event.type) { case InputEvent::KEY: { if (!p_event.key.pressed) break; switch(p_event.key.scancode) { case KEY_DOWN: { for(int i=mouse_over+1;i<items.size();i++) { if (i<0 || i>=items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over=i; update(); break; } } } break; case KEY_UP: { for(int i=mouse_over-1;i>=0;i--) { if (i<0 || i>=items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over=i; update(); break; } } } break; case KEY_RETURN: case KEY_ENTER: { if (mouse_over>=0 && mouse_over<items.size() && !items[mouse_over].separator) { activate_item(mouse_over); } } break; } } break; case InputEvent::MOUSE_BUTTON: { const InputEventMouseButton &b=p_event.mouse_button; if (b.pressed) break; switch(b.button_index) { case BUTTON_WHEEL_DOWN: { if (get_global_pos().y + get_size().y > get_viewport_rect().size.y) { int vseparation = get_constant("vseparation"); Ref<Font> font = get_font("font"); Point2 pos = get_pos(); int s = (vseparation+font->get_height())*3; pos.y-=s; set_pos(pos); //update hover InputEvent ie; ie.type=InputEvent::MOUSE_MOTION; ie.mouse_motion.x=b.x; ie.mouse_motion.y=b.y+s; _input_event(ie); } } break; case BUTTON_WHEEL_UP: { if (get_global_pos().y < 0) { int vseparation = get_constant("vseparation"); Ref<Font> font = get_font("font"); Point2 pos = get_pos(); int s = (vseparation+font->get_height())*3; pos.y+=s; set_pos(pos); //update hover InputEvent ie; ie.type=InputEvent::MOUSE_MOTION; ie.mouse_motion.x=b.x; ie.mouse_motion.y=b.y-s; _input_event(ie); } } break; case BUTTON_LEFT: { int over=_get_mouse_over(Point2(b.x,b.y)); if (invalidated_click) { invalidated_click=false; break; } if (over<0) { hide(); break; //non-activable } if (items[over].separator || items[over].disabled) break; if (items[over].submenu!="") { _activate_submenu(over); return; } activate_item(over); } break; } //update(); } break; case InputEvent::MOUSE_MOTION: { if (invalidated_click) { moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y); if (moved.length()>4) invalidated_click=false; } const InputEventMouseMotion &m=p_event.mouse_motion; for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) { if (!Rect2(Point2(),get_size()).has_point(Point2(m.x,m.y)) && E->get().has_point(Point2(m.x,m.y))) { call_deferred("hide"); return; } } int over=_get_mouse_over(Point2(m.x,m.y)); int id = (over<0 || items[over].separator || items[over].disabled)?-1:items[over].ID; if (id<0) { mouse_over=-1; update(); break; } if (items[over].submenu!="" && submenu_over!=over) { submenu_over=over; submenu_timer->start(); } if (over!=mouse_over) { mouse_over=over; update(); } } break; } }
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { if (!k->is_pressed()) return; switch (k->get_scancode()) { case KEY_DOWN: { for (int i = mouse_over + 1; i < items.size(); i++) { if (i < 0 || i >= items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over = i; update(); break; } } } break; case KEY_UP: { for (int i = mouse_over - 1; i >= 0; i--) { if (i < 0 || i >= items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over = i; update(); break; } } } break; case KEY_ENTER: case KEY_KP_ENTER: { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { activate_item(mouse_over); } } break; } } Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { if (b->is_pressed()) return; switch (b->get_button_index()) { case BUTTON_WHEEL_DOWN: { if (get_global_position().y + get_size().y > get_viewport_rect().size.y) { int vseparation = get_constant("vseparation"); Ref<Font> font = get_font("font"); Point2 pos = get_position(); int s = (vseparation + font->get_height()) * 3; pos.y -= (s * b->get_factor()); set_position(pos); //update hover Ref<InputEventMouseMotion> ie; ie.instance(); ie->set_position(b->get_position() + Vector2(0, s)); _gui_input(ie); } } break; case BUTTON_WHEEL_UP: { if (get_global_position().y < 0) { int vseparation = get_constant("vseparation"); Ref<Font> font = get_font("font"); Point2 pos = get_position(); int s = (vseparation + font->get_height()) * 3; pos.y += (s * b->get_factor()); set_position(pos); //update hover Ref<InputEventMouseMotion> ie; ie.instance(); ie->set_position(b->get_position() - Vector2(0, s)); _gui_input(ie); } } break; case BUTTON_LEFT: { int over = _get_mouse_over(b->get_position()); if (invalidated_click) { invalidated_click = false; break; } if (over < 0) { hide(); break; //non-activable } if (items[over].separator || items[over].disabled) break; if (items[over].submenu != "") { _activate_submenu(over); return; } activate_item(over); } break; } //update(); } Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { if (invalidated_click) { moved += m->get_relative(); if (moved.length() > 4) invalidated_click = false; } for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E->get().has_point(m->get_position())) { call_deferred("hide"); return; } } int over = _get_mouse_over(m->get_position()); int id = (over < 0 || items[over].separator || items[over].disabled) ? -1 : (items[over].ID >= 0 ? items[over].ID : over); if (id < 0) { mouse_over = -1; update(); return; } if (items[over].submenu != "" && submenu_over != over) { submenu_over = over; submenu_timer->start(); } if (over != mouse_over) { mouse_over = over; update(); } } }
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { if (p_event->is_action("ui_down") && p_event->is_pressed()) { int search_from = mouse_over + 1; if (search_from >= items.size()) search_from = 0; for (int i = search_from; i < items.size(); i++) { if (i < 0 || i >= items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); update(); accept_event(); break; } } } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { int search_from = mouse_over - 1; if (search_from < 0) search_from = items.size() - 1; for (int i = search_from; i >= 0; i--) { if (i < 0 || i >= items.size()) continue; if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); update(); accept_event(); break; } } } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { Node *n = get_parent(); if (n && Object::cast_to<PopupMenu>(n)) { hide(); accept_event(); } } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) { _activate_submenu(mouse_over); accept_event(); } } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { if (items[mouse_over].submenu != "" && submenu_over != mouse_over) { _activate_submenu(mouse_over); } else { activate_item(mouse_over); } accept_event(); } } Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { if (b->is_pressed()) return; int button_idx = b->get_button_index(); switch (button_idx) { case BUTTON_WHEEL_DOWN: { if (get_global_position().y + get_size().y > get_viewport_rect().size.y) { _scroll(-b->get_factor(), b->get_position()); } } break; case BUTTON_WHEEL_UP: { if (get_global_position().y < 0) { _scroll(b->get_factor(), b->get_position()); } } break; default: { // Allow activating item by releasing the LMB or any that was down when the popup appeared if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) { bool was_during_grabbed_click = during_grabbed_click; during_grabbed_click = false; int over = _get_mouse_over(b->get_position()); if (invalidated_click) { invalidated_click = false; break; } if (over < 0) { if (!was_during_grabbed_click) { hide(); } break; //non-activable } if (items[over].separator || items[over].disabled) break; if (items[over].submenu != "") { _activate_submenu(over); return; } activate_item(over); } } } //update(); } Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { if (invalidated_click) { moved += m->get_relative(); if (moved.length() > 4) invalidated_click = false; } for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) { if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E->get().has_point(m->get_position())) { call_deferred("hide"); return; } } int over = _get_mouse_over(m->get_position()); int id = (over < 0 || items[over].separator || items[over].disabled) ? -1 : (items[over].ID >= 0 ? items[over].ID : over); if (id < 0) { mouse_over = -1; update(); return; } if (items[over].submenu != "" && submenu_over != over) { submenu_over = over; submenu_timer->start(); } if (over != mouse_over) { mouse_over = over; update(); } } Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { if (get_global_position().y + get_size().y > get_viewport_rect().size.y || get_global_position().y < 0) { _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position()); } } }