UI: make display notification/query use sciter
This commit is contained in:
parent
d41b232322
commit
6e819f283f
|
|
@ -1 +1 @@
|
|||
Subproject commit 7b5a7e6deb92648ac05548a815f96ca17baea7b2
|
||||
Subproject commit 10c9708a7554d0e3fbe7d5dc995f1a58ae4cb953
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
:root {
|
||||
--color-notification-background: #181818;
|
||||
}
|
||||
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0 7px 14px 7px;
|
||||
border: 0;
|
||||
overflow: visible;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.notification-panel {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
background-color: var(--color-notification-background);
|
||||
box-shadow:
|
||||
0 2px 8px rgba(0, 0, 0, 1),
|
||||
0 12px 12px rgba(0, 0, 0, 0.55);
|
||||
overflow: hidden;
|
||||
color: #eff0f1;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.notification-panel > header {
|
||||
width: *;
|
||||
flow: horizontal;
|
||||
background-color: var(--color-titlebar-background);
|
||||
height: window-caption-height;
|
||||
margin: 0;
|
||||
color: var(--color-titlebar-text);
|
||||
}
|
||||
|
||||
html[data-active="false"] .notification-panel > header {
|
||||
background-color: var(--color-titlebar-background-inactive);
|
||||
}
|
||||
|
||||
.notification-panel > header > window-caption {
|
||||
display: block;
|
||||
line-height: window-caption-height;
|
||||
width: *;
|
||||
height: *;
|
||||
padding: 0 0.75em 0 1.1em;
|
||||
font-family: var(--font-ui);
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.notification-panel > header > window-caption span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.notification-panel > header > window-caption img {
|
||||
vertical-align: middle;
|
||||
margin-right: 0.5em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.notification-panel > header > window-buttons {
|
||||
display: block;
|
||||
flow: horizontal;
|
||||
width: max-content;
|
||||
height: *;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.notification-panel > header > window-buttons > window-button {
|
||||
behavior: clickable;
|
||||
display: block;
|
||||
height: *;
|
||||
width: window-button-width;
|
||||
foreground-size: 2em 1.5em;
|
||||
foreground-repeat: no-repeat;
|
||||
foreground-position: 50% 50%;
|
||||
stroke-width: 0;
|
||||
fill: var(--color-titlebar-icon);
|
||||
transition: background-color linear 100ms;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
html[data-active="false"] .notification-panel > header > window-buttons > window-button {
|
||||
fill: var(--color-titlebar-icon-inactive);
|
||||
}
|
||||
|
||||
.notification-panel > header > window-buttons > window-button:hover {
|
||||
background: var(--color-titlebar-icon-hover);
|
||||
}
|
||||
|
||||
.notification-panel > header > window-buttons > window-button[role="window-close"] {
|
||||
foreground-image: url(icon:window-close);
|
||||
}
|
||||
|
||||
.notification-panel > header > window-buttons > window-button[role="window-close"]:hover {
|
||||
background: rgb(232, 17, 35);
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.notification-body {
|
||||
min-width: 22em;
|
||||
max-width: 32em;
|
||||
margin: 0;
|
||||
padding: 1.35em 1.2em 0.75em 1.2em;
|
||||
}
|
||||
|
||||
#NotificationMessage {
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 0.25em 1.2em 1.1em 1.2em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.notification-panel button {
|
||||
color: #eff0f1;
|
||||
background: #232728;
|
||||
border: 1px solid #55575a;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.notification-panel button:hover {
|
||||
border: 1px solid #3cafe9;
|
||||
}
|
||||
|
||||
.notification-panel button:active {
|
||||
background: #3cafe9;
|
||||
}
|
||||
|
||||
.footer button {
|
||||
margin-left: 0.5em;
|
||||
min-width: 5.5rem;
|
||||
height: 2rem;
|
||||
padding: 0.4em 1.4em;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<html window-frame="transparent" window-icon="window-icon.png">
|
||||
<head>
|
||||
<link href="base.css" rel="stylesheet" type="text/css" />
|
||||
<link href="notification_dialog.css" rel="stylesheet" type="text/css" />
|
||||
<title>Notification</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="notification-panel">
|
||||
<header>
|
||||
<window-caption role="window-caption"><img src="window-icon-32.png" /><span id="NotificationTitle">Notification</span></window-caption>
|
||||
<window-buttons>
|
||||
<window-button role="window-close"></window-button>
|
||||
</window-buttons>
|
||||
</header>
|
||||
<div class="notification-body">
|
||||
<div id="NotificationMessage"></div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<button id="NotificationYes">Yes</button>
|
||||
<button id="NotificationNo" role="window-close">No</button>
|
||||
<button id="NotificationOk" role="window-ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,23 +1,191 @@
|
|||
#include "notification.h"
|
||||
#include "settings/ui_settings.h"
|
||||
#include <Windows.h>
|
||||
#include <sciter_element.h>
|
||||
#include <sciter_handler.h>
|
||||
#include <sciter_ui.h>
|
||||
#include <common/std_string.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class NotificationDialogMode
|
||||
{
|
||||
Alert,
|
||||
Query,
|
||||
};
|
||||
|
||||
class NotificationWindow :
|
||||
public IClickSink,
|
||||
public IWindowDestroySink
|
||||
{
|
||||
public:
|
||||
NotificationWindow(ISciterUI & sciterUI) :
|
||||
m_sciterUI(sciterUI),
|
||||
m_window(nullptr),
|
||||
m_mode(NotificationDialogMode::Alert),
|
||||
m_response(NotificationResponse::No)
|
||||
{
|
||||
}
|
||||
|
||||
NotificationResponse Show(void * parentWindow, NotificationDialogMode mode, const char * title, const char * message)
|
||||
{
|
||||
m_mode = mode;
|
||||
m_response = mode == NotificationDialogMode::Query ? NotificationResponse::No : NotificationResponse::Yes;
|
||||
m_window = nullptr;
|
||||
|
||||
if (!m_sciterUI.WindowCreate(parentWindow, "notification_dialog.html", 0, 0, 0, 0, SUIW_CHILD, m_window))
|
||||
{
|
||||
return m_response;
|
||||
}
|
||||
|
||||
SciterElement root(m_window->GetRootElement());
|
||||
if (root.IsValid())
|
||||
{
|
||||
SciterElement titleEl(root.GetElementByID("NotificationTitle"));
|
||||
if (titleEl.IsValid() && title != nullptr)
|
||||
{
|
||||
titleEl.SetText(title);
|
||||
}
|
||||
|
||||
SciterElement messageEl(root.GetElementByID("NotificationMessage"));
|
||||
if (messageEl.IsValid() && message != nullptr)
|
||||
{
|
||||
messageEl.SetText(message);
|
||||
}
|
||||
|
||||
ConfigureButtons();
|
||||
|
||||
m_sciterUI.AttachHandler(root.FindFirst("button[role=\"window-ok\"]"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(root.FindFirst("button[role=\"window-close\"]"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(root.GetElementByID("NotificationYes"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(root.GetElementByID("NotificationNo"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(root.GetElementByID("NotificationOk"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
}
|
||||
|
||||
m_window->OnDestroySinkAdd(this);
|
||||
m_window->FixMinSize();
|
||||
m_window->CenterWindow();
|
||||
m_window->RunModal();
|
||||
|
||||
return m_response;
|
||||
}
|
||||
|
||||
private:
|
||||
NotificationWindow(const NotificationWindow &) = delete;
|
||||
NotificationWindow & operator=(const NotificationWindow &) = delete;
|
||||
|
||||
void ConfigureButtons()
|
||||
{
|
||||
SciterElement root(m_window->GetRootElement());
|
||||
if (!root.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const bool query = m_mode == NotificationDialogMode::Query;
|
||||
SciterElement yesBtn(root.GetElementByID("NotificationYes"));
|
||||
SciterElement noBtn(root.GetElementByID("NotificationNo"));
|
||||
SciterElement okBtn(root.GetElementByID("NotificationOk"));
|
||||
|
||||
if (yesBtn.IsValid())
|
||||
{
|
||||
yesBtn.SetStyleAttribute("display", query ? "inline-block" : "none");
|
||||
}
|
||||
if (noBtn.IsValid())
|
||||
{
|
||||
noBtn.SetStyleAttribute("display", query ? "inline-block" : "none");
|
||||
}
|
||||
if (okBtn.IsValid())
|
||||
{
|
||||
okBtn.SetStyleAttribute("display", query ? "none" : "inline-block");
|
||||
}
|
||||
}
|
||||
|
||||
void Close(NotificationResponse response)
|
||||
{
|
||||
if (m_window == nullptr || m_window->IsClosed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_response = response;
|
||||
m_window->Destroy();
|
||||
}
|
||||
|
||||
bool OnClick(SCITER_ELEMENT element, SCITER_ELEMENT /*source*/, uint32_t /*reason*/) override
|
||||
{
|
||||
SciterElement clickElem(element);
|
||||
const std::string role = clickElem.GetAttribute("role");
|
||||
const std::string id = clickElem.GetAttribute("id");
|
||||
|
||||
if (id == "NotificationYes" || role == "window-ok")
|
||||
{
|
||||
Close(NotificationResponse::Yes);
|
||||
return true;
|
||||
}
|
||||
if (id == "NotificationNo" || role == "window-close")
|
||||
{
|
||||
Close(NotificationResponse::No);
|
||||
return true;
|
||||
}
|
||||
if (id == "NotificationOk")
|
||||
{
|
||||
Close(NotificationResponse::Yes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnWindowDestroy(HWINDOW /*hWnd*/) override
|
||||
{
|
||||
m_window = nullptr;
|
||||
}
|
||||
|
||||
ISciterUI & m_sciterUI;
|
||||
ISciterWindow * m_window;
|
||||
NotificationDialogMode m_mode;
|
||||
NotificationResponse m_response;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Notification> Notification::s_instance;
|
||||
|
||||
Notification::Notification()
|
||||
Notification::Notification() :
|
||||
m_sciterUI(nullptr),
|
||||
m_parentWindow(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void Notification::SetSciterContext(ISciterUI * sciterUI, void * parentWindow)
|
||||
{
|
||||
m_sciterUI = sciterUI;
|
||||
m_parentWindow = parentWindow;
|
||||
}
|
||||
|
||||
void Notification::ClearSciterContext()
|
||||
{
|
||||
m_sciterUI = nullptr;
|
||||
m_parentWindow = nullptr;
|
||||
}
|
||||
|
||||
void Notification::DisplayError(const char * message, const char * title) const
|
||||
{
|
||||
MessageBoxW(nullptr, stdstr(message).ToUTF16().c_str(), stdstr(title).ToUTF16().c_str(), MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
||||
if (m_sciterUI == nullptr || m_parentWindow == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
NotificationWindow dialog(*m_sciterUI);
|
||||
dialog.Show(m_parentWindow, NotificationDialogMode::Alert, title, message);
|
||||
}
|
||||
|
||||
NotificationResponse Notification::Query(const char * message, const char * title) const
|
||||
{
|
||||
const int result = MessageBoxW(nullptr, stdstr(message).ToUTF16().c_str(), stdstr(title).ToUTF16().c_str(), MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND);
|
||||
return result == IDYES ? NotificationResponse::Yes : NotificationResponse::No;
|
||||
if (m_sciterUI == nullptr || m_parentWindow == nullptr)
|
||||
{
|
||||
return NotificationResponse::No;
|
||||
}
|
||||
NotificationWindow dialog(*m_sciterUI);
|
||||
return dialog.Show(m_parentWindow, NotificationDialogMode::Query, title, message);
|
||||
}
|
||||
|
||||
void Notification::BreakPoint(const char * fileName, uint32_t lineNumber)
|
||||
|
|
@ -46,4 +214,4 @@ Notification & Notification::GetInstance()
|
|||
void Notification::CleanUp()
|
||||
{
|
||||
s_instance.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include <memory>
|
||||
#include <nxemu-core/notification.h>
|
||||
|
||||
__interface ISciterUI;
|
||||
|
||||
class Notification :
|
||||
public INotification
|
||||
{
|
||||
|
|
@ -14,6 +16,9 @@ public:
|
|||
void BreakPoint(const char * fileName, uint32_t lineNumber) override;
|
||||
void AppInitDone(void) override;
|
||||
|
||||
void SetSciterContext(ISciterUI * sciterUI, void * parentWindow);
|
||||
void ClearSciterContext();
|
||||
|
||||
static Notification & GetInstance();
|
||||
static void CleanUp();
|
||||
|
||||
|
|
@ -22,4 +27,7 @@ private:
|
|||
Notification & operator=(const Notification &) = delete;
|
||||
|
||||
static std::unique_ptr<Notification> s_instance;
|
||||
|
||||
ISciterUI * m_sciterUI;
|
||||
void * m_parentWindow;
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "sciter_main_window.h"
|
||||
#include "user_interface/notification.h"
|
||||
#include "settings/input_config.h"
|
||||
#include "settings/system_config.h"
|
||||
#include "settings/ui_settings.h"
|
||||
|
|
@ -298,6 +299,7 @@ const std::string * SciterMainWindow::MenuIconSvg(GuiAction action)
|
|||
|
||||
SciterMainWindow::~SciterMainWindow()
|
||||
{
|
||||
Notification::GetInstance().ClearSciterContext();
|
||||
m_WebBrowser.DetachWindow();
|
||||
|
||||
SettingsStore & settings = SettingsStore::GetInstance();
|
||||
|
|
@ -491,6 +493,7 @@ bool SciterMainWindow::Show()
|
|||
{
|
||||
PopulateVulkanRecords(m_vkDeviceRecords, RenderSurface());
|
||||
}
|
||||
Notification::GetInstance().SetSciterContext(&m_sciterUI, (void *)m_window->GetHandle());
|
||||
m_window->Show();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue