Browse Source

Add back modal windows related functionality

Signed-off-by: falkTX <falktx@falktx.com>
pull/272/head
falkTX 4 years ago
parent
commit
635e5cede4
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 190 additions and 153 deletions
  1. +15
    -4
      dgl/Window.hpp
  2. +9
    -14
      dgl/src/Window.cpp
  3. +130
    -33
      dgl/src/WindowPrivateData.cpp
  4. +36
    -102
      dgl/src/WindowPrivateData.hpp

+ 15
- 4
dgl/Window.hpp View File

@@ -55,6 +55,12 @@ public:
*/
explicit Window(Application& app);

/**
Constructor for a modal window, by having another window as its parent.
The Application instance must be the same between the 2 windows.
*/
explicit Window(Application& app, Window& parent);

/**
Constructor for an embed Window without known size,
typically used in modules or plugins that run inside another host.
@@ -224,6 +230,13 @@ public:
*/
void repaint(const Rectangle<uint>& rect) noexcept;

/**
Run this window as a modal, blocking input events from the parent.
Only valid for windows that have been created with another window as parent (as passed in the constructor).
Can optionally block-wait, but such option is only available if the application is running as standalone.
*/
void runAsModal(bool blockWait = false);

/**
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
*/
@@ -239,6 +252,7 @@ public:
// TODO deprecated
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
inline double getScaling() const noexcept { return getScaling(); }
inline void exec(bool blockWait = false) { runAsModal(blockWait); }

protected:
/**
@@ -257,6 +271,7 @@ protected:
/**
A function called when the window is resized.
If there is a top-level widget associated with this window, its size will be set right after this function.
TODO this seems wrong, top-level widget should be resized here
*/
virtual void onReshape(uint width, uint height);

@@ -318,10 +333,6 @@ END_NAMESPACE_DGL
};
#endif // DGL_FILE_BROWSER_DISABLED

static Window& withTransientParentWindow(Window& transientParentWindow);

void exec(bool lockWait = false);

void addIdleCallback(IdleCallback* const callback);
void removeIdleCallback(IdleCallback* const callback);



+ 9
- 14
dgl/src/Window.cpp View File

@@ -23,12 +23,12 @@ START_NAMESPACE_DGL
// -----------------------------------------------------------------------
// Window

// Window::Window(Window& transientParentWindow)
// : pData(new PrivateData(transientParentWindow.pData->fAppData, this, transientParentWindow)) {}

Window::Window(Application& app)
: pData(new PrivateData(app, this)) {}

Window::Window(Application& app, Window& parent)
: pData(new PrivateData(app, this, parent.pData)) {}

Window::Window(Application& app,
const uintptr_t parentWindowHandle,
const double scaleFactor,
@@ -170,10 +170,7 @@ double Window::getScaleFactor() const noexcept

void Window::focus()
{
if (! pData->isEmbed)
puglRaiseWindow(pData->view);

puglGrabFocus(pData->view);
pData->focus();
}

void Window::repaint() noexcept
@@ -192,6 +189,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
puglPostRedisplayRect(pData->view, prect);
}

void Window::runAsModal(bool blockWait)
{
pData->runAsModal(blockWait);
}

void Window::setGeometryConstraints(const uint minimumWidth,
const uint minimumHeight,
const bool keepAspectRatio,
@@ -242,13 +244,6 @@ void Window::onReshape(uint, uint)
}

#if 0
#if 0
void Window::exec(bool lockWait)
{
pData->exec(lockWait);
}
#endif

void Window::setTransientWinId(const uintptr_t winId)
{
puglSetTransientFor(pData->fView, winId);


+ 130
- 33
dgl/src/WindowPrivateData.cpp View File

@@ -63,12 +63,13 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
}

Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transientWindow)
Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* const ppData)
: app(a),
appData(a.pData),
self(s),
@@ -77,15 +78,16 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transi
isClosed(true),
isVisible(false),
isEmbed(false),
scaleFactor(getDesktopScaleFactor()),
scaleFactor(ppData->scaleFactor),
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0)
minHeight(0),
modal(this, ppData)
{
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);

puglSetTransientFor(view, transientWindow.getNativeWindowHandle());
puglSetTransientFor(view, puglGetNativeWindow(ppData->view));
}

Window::PrivateData::PrivateData(Application& a, Window* const s,
@@ -103,7 +105,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{
if (isEmbed)
{
@@ -136,7 +139,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{
if (isEmbed)
{
@@ -279,16 +283,26 @@ void Window::PrivateData::hide()
// }
#endif

puglHide(view);
if (modal.enabled)
stopModal();

// if (fModal.enabled)
// exec_fini();
puglHide(view);

isVisible = false;
}

// -----------------------------------------------------------------------

void Window::PrivateData::focus()
{
if (! isEmbed)
puglRaiseWindow(view);

puglGrabFocus(view);
}

// -----------------------------------------------------------------------

void Window::PrivateData::close()
{
DGL_DBG("Window close\n");
@@ -327,13 +341,91 @@ void Window::PrivateData::idleCallback()
// std::free(buffer);
// }
// #endif
//
// if (fModal.enabled && fModal.parent != nullptr)
// fModal.parent->windowSpecificIdle();
// self->repaint();

// if (modal.enabled && modal.parent != nullptr)
// modal.parent->idleCallback();
}

// -----------------------------------------------------------------------
// modal handling

void Window::PrivateData::startModal()
{
DGL_DBG("Window modal loop starting..."); DGL_DBGF;
DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show());

// activate modal mode for this window
modal.enabled = true;

// make parent give focus to us
modal.parent->modal.child = this;

// make sure both parent and ourselves are visible
modal.parent->show();
show();

DGL_DBG("Ok\n");
}

void Window::PrivateData::stopModal()
{
DGL_DBG("Window modal loop stopping..."); DGL_DBGF;

// deactivate modal mode
modal.enabled = false;

// safety checks, make sure we have a parent and we are currently active as the child to give focus to
if (modal.parent == nullptr)
return;
if (modal.parent->modal.child != this)
return;

// stop parent from giving focus to us, so it behaves like normal
modal.parent->modal.child = nullptr;

// the mouse position probably changed since the modal appeared,
// so send a mouse motion event to the modal's parent window
#if 0
#if defined(DISTRHO_OS_HAIKU)
// TODO
#elif defined(DISTRHO_OS_MAC)
// TODO
#elif defined(DISTRHO_OS_WINDOWS)
// TODO
#else
int i, wx, wy;
uint u;
::Window w;
if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
fModal.parent->onPuglMotion(wx, wy);
#endif
#endif

DGL_DBG("Ok\n");
}

void Window::PrivateData::runAsModal(const bool blockWait)
{
DGL_DBGp("Window::PrivateData::runAsModal %i\n", blockWait);
startModal();

if (blockWait)
{
DISTRHO_SAFE_ASSERT_RETURN(appData->isStandalone,);

while (isVisible && modal.enabled)
appData->idle(10);

stopModal();
}
else
{
appData->idle(0);
}
}

// -----------------------------------------------------------------------
// pugl events

void Window::PrivateData::onPuglConfigure(const int width, const int height)
{
@@ -372,14 +464,19 @@ void Window::PrivateData::onPuglClose()
{
DGL_DBG("PUGL: onClose\n");

// if (fModal.enabled)
// exec_fini();

if (! self->onClose())
return;

// if (fModal.childFocus != nullptr)
// fModal.childFocus->fSelf->onClose();
if (modal.enabled)
stopModal();

if (modal.child != nullptr)
{
if (modal.child->modal.enabled)
modal.child->stopModal();

modal.child->close();
}

close();
}
@@ -388,8 +485,8 @@ void Window::PrivateData::onPuglFocus(const bool focus, const CrossingMode mode)
{
DGL_DBGp("onPuglFocus : %i %i\n", focus, mode);

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
self->onFocus(focus, mode);
@@ -400,8 +497,8 @@ void Window::PrivateData::onPuglKey(const Events::KeyboardEvent& ev)
{
DGL_DBGp("onPuglKey : %i %u %u\n", ev.press, ev.key, ev.keycode);

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -413,8 +510,8 @@ void Window::PrivateData::onPuglSpecial(const Events::SpecialEvent& ev)
{
DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key);

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -426,8 +523,8 @@ void Window::PrivateData::onPuglText(const Events::CharacterInputEvent& ev)
{
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string);

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -439,8 +536,8 @@ void Window::PrivateData::onPuglMouse(const Events::MouseEvent& ev)
{
DGL_DBGp("onPuglMouse : %i %i %f %f\n", ev.button, ev.press, ev.pos.getX(), ev.pos.getY());

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -452,8 +549,8 @@ void Window::PrivateData::onPuglMotion(const Events::MotionEvent& ev)
{
DGL_DBGp("onPuglMotion : %f %f\n", ev.pos.getX(), ev.pos.getY());

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -465,8 +562,8 @@ void Window::PrivateData::onPuglScroll(const Events::ScrollEvent& ev)
{
DGL_DBGp("onPuglScroll : %f %f %f %f\n", ev.pos.getX(), ev.pos.getY(), ev.delta.getX(), ev.delta.getY());

// if (fModal.childFocus != nullptr)
// return fModal.childFocus->focus();
if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)


+ 36
- 102
dgl/src/WindowPrivateData.hpp View File

@@ -68,11 +68,40 @@ struct Window::PrivateData : IdleCallback {
/** Pugl minWidth, minHeight access. */
uint minWidth, minHeight;

/** Modal window setup. */
struct Modal {
// PrivateData* self; // pointer to PrivateData this Modal class belongs to
PrivateData* parent; // parent of this window (so we can become modal)
PrivateData* child; // child window to give focus to when modal mode is enabled
bool enabled; // wherever modal mode is enabled (only possible if parent != null)

/** Constructor for a non-modal window. */
Modal(PrivateData* const s) noexcept
: parent(nullptr),
child(nullptr),
enabled(false) {}

/** Constructor for a modal window (with a parent). */
Modal(PrivateData* const s, PrivateData* const p) noexcept
: parent(p),
child(nullptr),
enabled(false) {}

/** Destructor. */
~Modal() noexcept
{
DISTRHO_SAFE_ASSERT(! enabled);
}
} modal;

/** Constructor for a regular, standalone window. */
explicit PrivateData(Application& app, Window* self);

/** Constructor for a modal window. */
explicit PrivateData(Application& app, Window* self, PrivateData* ppData);

/** Constructor for a regular, standalone window with a transient parent. */
explicit PrivateData(Application& app, Window* self, Window& transientWindow);
// explicit PrivateData(Application& app, Window* self, Window& transientWindow);

/** Constructor for an embed Window, with a few extra hints from the host side. */
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable);
@@ -89,6 +118,7 @@ struct Window::PrivateData : IdleCallback {

void show();
void hide();
void focus();

/** Hide window and notify application of a window close event.
* Does nothing if window is embed (that is, not standalone).
@@ -105,6 +135,11 @@ struct Window::PrivateData : IdleCallback {

void idleCallback() override;

// modal handling
void startModal();
void stopModal();
void runAsModal(bool blockWait);

// pugl events
void onPuglConfigure(int width, int height);
void onPuglExpose();
@@ -128,39 +163,6 @@ struct Window::PrivateData : IdleCallback {
END_NAMESPACE_DGL

#if 0
// this one depends on build type
// GraphicsContext fContext;

bool fFirstInit;
bool fVisible;
bool fUsingEmbed;
double fScaling;
double fAutoScaling;

struct Modal {
bool enabled;
PrivateData* parent;
PrivateData* childFocus;

Modal()
: enabled(false),
parent(nullptr),
childFocus(nullptr) {}

Modal(PrivateData* const p)
: enabled(false),
parent(p),
childFocus(nullptr) {}

~Modal()
{
DISTRHO_SAFE_ASSERT(! enabled);
DISTRHO_SAFE_ASSERT(childFocus == nullptr);
}

DISTRHO_DECLARE_NON_COPY_STRUCT(Modal)
} fModal;

// #if defined(DISTRHO_OS_HAIKU)
// BApplication* bApplication;
// BView* bView;
@@ -189,74 +191,6 @@ END_NAMESPACE_DGL
struct Window::PrivateData {
// -------------------------------------------------------------------

void exec(const bool lockWait)
{
DBG("Window exec\n");
exec_init();

if (lockWait)
{
for (; fVisible && fModal.enabled;)
{
idle();
d_msleep(10);
}

exec_fini();
}
else
{
idle();
}
}

// -------------------------------------------------------------------

void exec_init()
{
DBG("Window modal loop starting..."); DBGF;
DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true));

fModal.enabled = true;
fModal.parent->fModal.childFocus = this;

fModal.parent->setVisible(true);
setVisible(true);

DBG("Ok\n");
}

void exec_fini()
{
DBG("Window modal loop stopping..."); DBGF;
fModal.enabled = false;

if (fModal.parent != nullptr)
{
fModal.parent->fModal.childFocus = nullptr;

// the mouse position probably changed since the modal appeared,
// so send a mouse motion event to the modal's parent window
#if defined(DISTRHO_OS_HAIKU)
// TODO
#elif defined(DISTRHO_OS_MAC)
// TODO
#elif defined(DISTRHO_OS_WINDOWS)
// TODO
#else
int i, wx, wy;
uint u;
::Window w;
if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
fModal.parent->onPuglMotion(wx, wy);
#endif
}

DBG("Ok\n");
}

// -------------------------------------------------------------------

bool handlePluginSpecial(const bool press, const Key key)
{
DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key);


Loading…
Cancel
Save