mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	mouse-active/inactive ui modes + focus handling
This commit is contained in:
		
							parent
							
								
									c370f9011e
								
							
						
					
					
						commit
						03af2919e9
					
				
					 7 changed files with 87 additions and 45 deletions
				
			
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
    color: $color-text-dim;
 | 
					    color: $color-text-dim;
 | 
				
			||||||
    border-color: rgba($base-col, 0.8);
 | 
					    border-color: rgba($base-col, 0.8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &:focus {
 | 
					    &:focus, &:hover {
 | 
				
			||||||
        color: $color-text;
 | 
					        color: $color-text;
 | 
				
			||||||
        border-color: $base-col;
 | 
					        border-color: $base-col;
 | 
				
			||||||
        background-color: rgba($base-col, 0.3);
 | 
					        background-color: rgba($base-col, 0.3);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,7 +115,8 @@
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        &:focus + .config-option__tab-label {
 | 
					        &:focus + .config-option__tab-label,
 | 
				
			||||||
 | 
					        &:hover + .config-option__tab-label {
 | 
				
			||||||
            color: $color-text;
 | 
					            color: $color-text;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,12 +37,8 @@
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &:hover {
 | 
					    &:focus, &:hover {
 | 
				
			||||||
        cursor: pointer;
 | 
					        cursor: pointer;
 | 
				
			||||||
        opacity: 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &:focus {
 | 
					 | 
				
			||||||
        color: $color-text;
 | 
					        color: $color-text;
 | 
				
			||||||
        opacity: 1;
 | 
					        opacity: 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,10 +12,6 @@ body
 | 
				
			||||||
    box-sizing: border-box;
 | 
					    box-sizing: border-box;
 | 
				
			||||||
	color: $color-text;
 | 
						color: $color-text;
 | 
				
			||||||
	font-family: $font-stack;
 | 
						font-family: $font-stack;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    &[disable-mouse] {
 | 
					 | 
				
			||||||
        pointer-events: none;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.rmlui-window {
 | 
					.rmlui-window {
 | 
				
			||||||
| 
						 | 
					@ -26,6 +22,10 @@ body
 | 
				
			||||||
        opacity: 0;
 | 
					        opacity: 0;
 | 
				
			||||||
        transition: none;
 | 
					        transition: none;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:not([mouse-active]) {
 | 
				
			||||||
 | 
					        pointer-events: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*, *:before, *:after {
 | 
					*, *:before, *:after {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@
 | 
				
			||||||
    padding: space(12) space(4);
 | 
					    padding: space(12) space(4);
 | 
				
			||||||
    background-color: rgba(0, 0, 0, 0);
 | 
					    background-color: rgba(0, 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:focus:not(:disabled, [disabled]),
 | 
				
			||||||
    &:focus-visible:not(:disabled, [disabled]),
 | 
					    &:focus-visible:not(:disabled, [disabled]),
 | 
				
			||||||
    &:hover:not(:disabled, [disabled]) {
 | 
					    &:hover:not(:disabled, [disabled]) {
 | 
				
			||||||
        @include set-color($color-text);
 | 
					        @include set-color($color-text);
 | 
				
			||||||
| 
						 | 
					@ -116,11 +117,7 @@
 | 
				
			||||||
        background-color: $color-white-a5;
 | 
					        background-color: $color-white-a5;
 | 
				
			||||||
        cursor: pointer;
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        &:hover:not(:focus) {
 | 
					        &:hover, &:focus {
 | 
				
			||||||
            @include border($color-white-a80);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        &:hover:focus, &:focus {
 | 
					 | 
				
			||||||
            @include border($color-white-a80);
 | 
					            @include border($color-white-a80);
 | 
				
			||||||
            background-color: $color-white-a20;
 | 
					            background-color: $color-white-a20;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -770,6 +770,8 @@ struct UIContext {
 | 
				
			||||||
        std::unordered_map<recomp::Menu, Rml::ElementDocument*> documents;
 | 
					        std::unordered_map<recomp::Menu, Rml::ElementDocument*> documents;
 | 
				
			||||||
        Rml::ElementDocument* current_document;
 | 
					        Rml::ElementDocument* current_document;
 | 
				
			||||||
        Rml::Element* prev_focused;
 | 
					        Rml::Element* prev_focused;
 | 
				
			||||||
 | 
					        bool mouse_is_active = true;
 | 
				
			||||||
 | 
					        bool mouse_is_active_changed = false;
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        std::unique_ptr<SystemInterface_SDL> system_interface;
 | 
					        std::unique_ptr<SystemInterface_SDL> system_interface;
 | 
				
			||||||
        std::unique_ptr<RmlRenderInterface_RT64> render_interface;
 | 
					        std::unique_ptr<RmlRenderInterface_RT64> render_interface;
 | 
				
			||||||
| 
						 | 
					@ -862,43 +864,73 @@ struct UIContext {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void update_primary_input(bool mouse_moved, bool non_mouse_interacted) {
 | 
				
			||||||
 | 
					            if (current_document == nullptr) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            mouse_is_active_changed = false;
 | 
				
			||||||
 | 
					            if (non_mouse_interacted) {
 | 
				
			||||||
 | 
					                // controller newly interacted with
 | 
				
			||||||
 | 
					                if (mouse_is_active) {
 | 
				
			||||||
 | 
					                    mouse_is_active = false;
 | 
				
			||||||
 | 
					                    mouse_is_active_changed = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (mouse_moved) {
 | 
				
			||||||
 | 
					                // mouse newly interacted with
 | 
				
			||||||
 | 
					                if (!mouse_is_active) {
 | 
				
			||||||
 | 
					                    mouse_is_active = true;
 | 
				
			||||||
 | 
					                    mouse_is_active_changed = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO: Figure out why this only works if the mouse is moving
 | 
				
			||||||
 | 
					            SDL_ShowCursor(mouse_is_active ? SDL_ENABLE : SDL_DISABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Rml::Element* window_el = current_document->GetElementById("window");
 | 
				
			||||||
 | 
					            if (window_el != nullptr) {
 | 
				
			||||||
 | 
					                if (mouse_is_active) {
 | 
				
			||||||
 | 
					                    if (!window_el->HasAttribute("mouse-active")) {
 | 
				
			||||||
 | 
					                        window_el->SetAttribute("mouse-active", true);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (window_el->HasAttribute("mouse-active")) {
 | 
				
			||||||
 | 
					                    window_el->RemoveAttribute("mouse-active");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void update_focus(bool mouse_moved) {
 | 
					        void update_focus(bool mouse_moved) {
 | 
				
			||||||
            if (current_document == nullptr) {
 | 
					            if (current_document == nullptr) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Rml::Element* focused = current_document->GetFocusLeafNode();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // If there was mouse motion, get the current hovered element (or its target if it points to one) and focus that if applicable.
 | 
					            // If there was mouse motion, get the current hovered element (or its target if it points to one) and focus that if applicable.
 | 
				
			||||||
            if (mouse_moved) {
 | 
					            if (mouse_is_active) {
 | 
				
			||||||
                Rml::Element* hovered = context->GetHoverElement();
 | 
					                if (mouse_is_active_changed) {
 | 
				
			||||||
                if (hovered) {
 | 
					                    Rml::Element* focused = current_document->GetFocusLeafNode();
 | 
				
			||||||
                    Rml::Element* hover_target = get_target(current_document, hovered);
 | 
					                    if (focused) focused->Blur();
 | 
				
			||||||
                    if (hover_target && can_focus(hover_target)) {
 | 
					                } else if (mouse_moved) {
 | 
				
			||||||
                        hover_target->Focus();
 | 
					                    Rml::Element* hovered = context->GetHoverElement();
 | 
				
			||||||
                    }
 | 
					                    if (hovered) {
 | 
				
			||||||
                }
 | 
					                        Rml::Element* hover_target = get_target(current_document, hovered);
 | 
				
			||||||
            }
 | 
					                        if (hover_target && can_focus(hover_target)) {
 | 
				
			||||||
 | 
					                            // hover_target->Focus();
 | 
				
			||||||
            // Revert focus to the previous element if focused on anything without a tab index.
 | 
					                            prev_focused = hover_target;
 | 
				
			||||||
            // This should prevent the user from losing focus on something that has no navigation.
 | 
					 | 
				
			||||||
            if (focused && !can_focus(focused)) {
 | 
					 | 
				
			||||||
                // If the previously focused element is still accepting focus, return focus to it.
 | 
					 | 
				
			||||||
                if (prev_focused && can_focus(prev_focused)) {
 | 
					 | 
				
			||||||
                    prev_focused->Focus();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                // Otherwise, check if the currently focused element has a "nav-return" attribute and focus that attribute's value if so.
 | 
					 | 
				
			||||||
                else {
 | 
					 | 
				
			||||||
                    Rml::Variant* nav_return = focused->GetAttribute("nav-return");
 | 
					 | 
				
			||||||
                    if (nav_return && nav_return->GetType() == Rml::Variant::STRING) {
 | 
					 | 
				
			||||||
                        Rml::Element* return_element = current_document->GetElementById(nav_return->Get<std::string>());
 | 
					 | 
				
			||||||
                        if (return_element) {
 | 
					 | 
				
			||||||
                            return_element->Focus();
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					
 | 
				
			||||||
                prev_focused = current_document->GetFocusLeafNode();
 | 
					            if (!mouse_is_active) {
 | 
				
			||||||
 | 
					                if (!prev_focused) {
 | 
				
			||||||
 | 
					                    // get current focus and set to prev
 | 
				
			||||||
 | 
					                    prev_focused = current_document->GetFocusLeafNode();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (mouse_is_active_changed && prev_focused && can_focus(prev_focused)) {
 | 
				
			||||||
 | 
					                    prev_focused->Focus();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1037,6 +1069,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
 | 
				
			||||||
    SDL_Event cur_event{};
 | 
					    SDL_Event cur_event{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool mouse_moved = false;
 | 
					    bool mouse_moved = false;
 | 
				
			||||||
 | 
					    bool non_mouse_interacted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (recomp::try_deque_event(cur_event)) {
 | 
					    while (recomp::try_deque_event(cur_event)) {
 | 
				
			||||||
        // Scale coordinates for mouse and window events based on the UI scale
 | 
					        // Scale coordinates for mouse and window events based on the UI scale
 | 
				
			||||||
| 
						 | 
					@ -1066,14 +1099,28 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Send events to RmlUi if a menu is open.
 | 
					        // Send events to RmlUi if a menu is open.
 | 
				
			||||||
        if (cur_menu != recomp::Menu::None) {
 | 
					        if (cur_menu != recomp::Menu::None) {
 | 
				
			||||||
            RmlSDL::InputEventHandler(ui_context->rml.context, cur_event);
 | 
					 | 
				
			||||||
            // Implement some additional behavior for specific events on top of what RmlUi normally does with them.
 | 
					            // Implement some additional behavior for specific events on top of what RmlUi normally does with them.
 | 
				
			||||||
            switch (cur_event.type) {
 | 
					            switch (cur_event.type) {
 | 
				
			||||||
            case SDL_EventType::SDL_MOUSEMOTION:
 | 
					            case SDL_EventType::SDL_MOUSEMOTION:
 | 
				
			||||||
                mouse_moved = true;
 | 
					                mouse_moved = true;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            case SDL_EventType::SDL_CONTROLLERBUTTONDOWN:
 | 
				
			||||||
 | 
					            case SDL_EventType::SDL_KEYDOWN:
 | 
				
			||||||
 | 
					                non_mouse_interacted = true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL_EventType::SDL_CONTROLLERAXISMOTION:
 | 
				
			||||||
 | 
					                SDL_ControllerAxisEvent* axis_event = &cur_event.caxis;
 | 
				
			||||||
 | 
					                float axis_value = axis_event->value * (1 / 32768.0f);
 | 
				
			||||||
 | 
					                if (fabsf(axis_value) > 0.2f) {
 | 
				
			||||||
 | 
					                    non_mouse_interacted = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            RmlSDL::InputEventHandler(ui_context->rml.context, cur_event);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If no menu is open and the game has been started and either the escape key or select button are pressed, open the config menu.
 | 
					        // If no menu is open and the game has been started and either the escape key or select button are pressed, open the config menu.
 | 
				
			||||||
        if (cur_menu == recomp::Menu::None && ultramodern::is_game_started()) {
 | 
					        if (cur_menu == recomp::Menu::None && ultramodern::is_game_started()) {
 | 
				
			||||||
            bool open_config = false;
 | 
					            bool open_config = false;
 | 
				
			||||||
| 
						 | 
					@ -1104,6 +1151,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
 | 
				
			||||||
        recomp::finish_scanning_input(scanned_field);
 | 
					        recomp::finish_scanning_input(scanned_field);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui_context->rml.update_primary_input(mouse_moved, non_mouse_interacted);
 | 
				
			||||||
    ui_context->rml.update_focus(mouse_moved);
 | 
					    ui_context->rml.update_focus(mouse_moved);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (cur_menu != recomp::Menu::None) {
 | 
					    if (cur_menu != recomp::Menu::None) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue