More work on graphics config menu, improved focus handling in UI, fixed scissor bug in UI rendering
This commit is contained in:
parent
525092fd60
commit
ac131c7835
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue