More work on graphics config menu, improved focus handling in UI, fixed scissor bug in UI rendering

This commit is contained in:
Mr-Wiseguy 2023-12-30 19:03:57 -05:00
parent 525092fd60
commit ac131c7835
3 changed files with 171 additions and 44 deletions

View File

@ -23,7 +23,7 @@
text-align: center;
}
#tab_graphics:selected {
nav-down:#ar_original;
nav-down:#res_auto;
}
</style>
</head>
@ -35,29 +35,74 @@
<tab id="tab_graphics" autofocus>Graphics</tab>
<panel>
<form>
<div style="width:700dp; border-radius:0dp; height:auto; padding:16dp; text-align:left; margin-left:auto; margin-right:auto; font-effect: outline(2dp black); font-size:24dp; background:rgba(50,50,50,200);">
<label style="padding:4dp;">Aspect Ratio</label><br/>
<hr/>
<div style="padding:2dp;">
<input type="radio" name="aspectratio" id="ar_original"/>
<label for="ar_original">Original</label>
<input type="radio" name="aspectratio" id="ar_expand" checked="checked" style="nav-right:none"/>
<label for="ar_expand">Expand</label>
<div class="option_container">
<div class="option_row">
<div class="option">
<label style="padding:4dp;">Resolution</label><br/>
<hr/>
<div class="option_list">
<input type="radio" name="resolution" id="res_original"/>
<label for="res_original">Original</label>
<input type="radio" name="resolution" id="res_2x" style="nav-down:#ar_expand"/>
<label for="res_2x">Original 2x</label>
<input type="radio" name="resolution" id="res_auto" style="nav-down:#ar_expand" checked="checked"/>
<label for="res_auto">Auto</label>
</div>
</div>
<div class="option">
<label style="padding:4dp;">Window Mode</label><br/>
<hr/>
<div class="option_list">
<input type="radio" name="windowmode" id="wm_windowed" style="nav-down:#msaa_none" checked="checked"/>
<label for="wm_windowed">Windowed</label>
<input type="radio" name="windowmode" id="wm_fullscreen" style="nav-right:none"/>
<label for="wm_fullscreen">Fullscreen</label>
</div>
</div>
</div>
<div class="option_row">
<div class="option">
<label style="padding:4dp;">Aspect Ratio</label><br/>
<hr/>
<div class="option_list">
<input type="radio" name="aspectratio" id="ar_original" style="nav-left:none"/>
<label for="ar_original">Original</label>
<input type="radio" name="aspectratio" id="ar_expand" style="nav-up:#res_2x" checked="checked"/>
<label for="ar_expand">Expand</label>
</div>
</div>
<div class="option">
<label style="padding:4dp;">MS Anti-Aliasing</label><br/>
<hr/>
<div class="option_list">
<input type="radio" name="antialiasing" id="msaa_none" checked="checked" style="nav-up:#wm_windowed;nav-left:none"/>
<label for="msaa_none">None</label>
<input type="radio" name="antialiasing" id="msaa_2x"/>
<label for="msaa_2x">2x</label>
<input type="radio" name="antialiasing" id="msaa_4x"/>
<label for="msaa_4x">4x</label>
<input type="radio" name="antialiasing" id="msaa_8x" style="nav-right:none"/>
<label for="msaa_8x">8x</label>
</div>
</div>
</div>
<div class="option_row">
<div class="option">
<label style="padding:4dp;">Refresh Rate</label><br/>
<hr/>
<div class="option_list" style="flex-wrap: wrap;">
<input type="radio" name="refreshrate" id="rr_original" style="nav-up:#ar_expand"/>
<label for="rr_original">Original</label>
<input type="radio" name="refreshrate" id="rr_display" style="nav-up:#ar_expand"/>
<label for="rr_display">Display</label>
<input type="radio" name="refreshrate" id="rr_manual" checked="checked" style="nav-up:#msaa_none;nav-right:none"/>
<label for="rr_manual">Manual</label>
<div style="flex-basis:100%;height:0"/>
<input id="rr_manual_input" type="range" min="60" max="1000" style="font:normal;flex:1;nav-up:auto;nav-down:auto;width:100%" value="60"/>
</div>
</div>
</div>
<br/>
<label style="padding:4dp;">Refresh Rate</label><br/>
<hr/>
<p style="padding:2dp;">
<input type="radio" name="refreshrate" id="rr_original"/>
<label for="rr_original">Original</label>
<input type="radio" name="refreshrate" id="rr_display"/>
<label for="rr_display">Display</label>
<input type="radio" name="refreshrate" id="rr_manual" checked="checked" style="nav-up:#ar_expand;nav-right:none"/>
<label for="rr_manual">Manual</label>
<br/>
<input id="rr_manual_input" type="range" min="60" max="1000" style="font:normal;flex:1;nav-up:auto;nav-down:auto;" value="60"/>
</p>
</div>
</form>
</panel>

View File

@ -22,6 +22,39 @@ body {
tab-index:none;
} */
div.option_container {
display:flex;
flex-direction: column;
width:850dp;
border-radius:0dp;
height:auto;
padding:16dp;
text-align:left;
margin-left:auto;
margin-right:auto;
font-effect: outline(2dp black);
font-size:24dp;
background:rgba(50,50,50,200);
}
div.option_row {
display:flex;
flex-direction: row;
}
div.option {
flex:1;
padding:4dp;
text-align:center;
}
div.option_list {
padding:2dp;
text-align:center;
display:flex;
justify-content:center;
}
div#title_bar {
z-index: 1;
position: absolute;
@ -71,7 +104,7 @@ div#content {
p {
text-align: left;
margin-bottom: 4dp;
/* margin-bottom: 4dp; */
}
h1 {
@ -255,17 +288,18 @@ select selectbox option:hover {
input.radio,
input.checkbox {
/* width: 30dp; */
height: 30dp;
/* height: 30dp; */
/* vertical-align: -11dp; */
margin-top: 4dp;
margin-bottom: 4dp;
flex: 1;
/* margin-top: 4dp; */
/* margin-bottom: 4dp; */
flex: 0;
tab-index:auto;
focus:auto;
nav-up:auto;
nav-down:auto;
nav-right:auto;
nav-left:auto;
width:0dp;
}
input.radio + label {
@ -276,6 +310,8 @@ input.radio + label {
text-align:center;
tab-index:none;
focus:auto;
margin-left:10dp;
margin-right:10dp;
/* display:none; */
/* decorator: image(radio) */
}
@ -295,21 +331,11 @@ input.radio:checked + label {
/* decorator: image(radio-checked) */
}
input.radio:hover + label {
color:#329696;
/* background: rgb(150,150,150); */
}
input.radio:focus + label {
color:#329696;
/* background: rgb(150,150,150); */
}
input.radio:checked:hover + label {
border-bottom:1dp;
/* background: rgb(150,150,150); */
}
tabset {
font:bold;
margin:1dp;
@ -332,10 +358,6 @@ tab {
nav-left:auto;
}
tab:hover {
color:#329696;
}
tab:selected {
border-top: 2dp;
border-color: white;

View File

@ -339,7 +339,7 @@ public:
list_->setViewports(RT64::RenderViewport{ 0, 0, float(window_width_), float(window_height_) });
if (scissor_enabled_) {
list_->setScissors(RT64::RenderRect{ scissor_x_, scissor_y_, scissor_width_, scissor_height_ });
list_->setScissors(RT64::RenderRect{ scissor_x_, scissor_y_, scissor_width_ + scissor_x_, scissor_height_ + scissor_y_ });
}
else {
list_->setScissors(RT64::RenderRect{ 0, 0, window_width_, window_height_ });
@ -564,11 +564,34 @@ public:
}
};
bool can_focus(Rml::Element* element) {
return element->GetProperty(Rml::PropertyId::TabIndex)->Get<Rml::Style::TabIndex>() != Rml::Property(Rml::Style::TabIndex::None);
}
Rml::Element* get_target(Rml::ElementDocument* document, Rml::Element* element) {
// Labels can have targets, so check if this element is a label.
if (element->GetTagName() == "label") {
// Check if the label has a "for" property.
Rml::String for_value = element->GetAttribute<Rml::String>("for", "");
// If there is a value for the "for" property, find that element and return it if it exists.
if (!for_value.empty()) {
Rml::Element* target_element = document->GetElementById(for_value);
if (target_element) {
return target_element;
}
}
}
// Return the element directly if no target exists.
return element;
}
struct {
struct UIRenderContext render;
class {
std::unordered_map<recomp::Menu, Rml::ElementDocument*> documents;
Rml::ElementDocument* current_document;
Rml::Element* prev_focused;
public:
SystemInterface_SDL system_interface;
std::unique_ptr<RmlRenderInterface_RT64> render_interface;
@ -619,6 +642,30 @@ struct {
documents.emplace(recomp::Menu::Launcher, context->LoadDocument("assets/launcher.rml"));
documents.emplace(recomp::Menu::Config, context->LoadDocument("assets/config_menu.rml"));
}
void update_focus(bool mouse_moved) {
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 (mouse_moved) {
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.
// This should prevent the user from losing focus on something that has no navigation.
if (focused && !can_focus(focused)) {
prev_focused->Focus();
}
else {
prev_focused = current_document->GetFocusLeafNode();
}
}
} rml;
} UIContext;
@ -693,7 +740,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
bool is_reload_held = key_state[SDL_SCANCODE_F11] != 0;
bool reload_sheets = is_reload_held && !was_reload_held;
was_reload_held = is_reload_held;
static recomp::Menu prev_menu = recomp::Menu::None;
recomp::Menu cur_menu = open_menu.load();
@ -710,10 +757,23 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
SDL_Event cur_event{};
bool mouse_moved = false;
while (recomp::try_deque_event(cur_event)) {
RmlSDL::InputEventHandler(UIContext.rml.context, cur_event);
// If a menu is open then implement some additional behavior for specific events on top of what RmlUi normally does with them.
if (cur_menu != recomp::Menu::None) {
switch (cur_event.type) {
case SDL_EventType::SDL_MOUSEMOTION:
mouse_moved = true;
break;
}
}
}
UIContext.rml.update_focus(mouse_moved);
if (cur_menu != recomp::Menu::None) {
int width, height;
SDL_GetWindowSizeInPixels(window, &width, &height);