[JUCE][MacOS]JUCEのNSViewComponentをフロントに持ってくる方法 改善版


前回[この記事](https://qiita.com/Talokay/items/a1a7b49f6253520b9bdf)で紹介した、NSViewComponentのZ-Orderを変えるやりかた。

もっと簡単でシンプルな方法がありましたので、そちらを書きます。

前回の記事では、JUCEライブラリの奥にアクセスして、該当箇所に直接コードを書き足していましたが、必要なメンバを呼び出して変更するやり方です。
よって、JUCEライブラリ自体を書き換える必要はありません。

前回に引き続きお断りですが、このやり方はNSViewを直接呼び出して処理を行うので、macOSでしか有効ではありません。

#実装

クラス、NSViewManager を作成します。

```NSViewManager.hpp

class NSViewManager
{
public:
    IRNSViewManager(){}
    ~IRNSViewManager(){}
    
    // works only on macOS
    void bringOpenGLContextFront(juce::Component* owner, NSViewComponent* view);
}

```

```NSViewManager.cpp

#include "NSViewManager.hpp"

// Empty

```

まず、NSViewManagerクラスのhpp, cpp ファイルを作成。
cppファイルは空で構いません。
次に、Objective-C++ファイルを作成し、NSViewManager.cpp ファイルをインクルードします。

```NSViewManager_mac.mm

#import <AppKit/AppKit.h>
#include "IRNSViewManager.cpp"

void IRNSViewManager::bringOpenGLContextFront(juce::Component* owner, NSViewComponent* view)
{
    
    auto* peer = owner->getPeer();
    auto v = (NSView*) view->getView();

    if(peer != nullptr)
    {
       
        auto peerView = (NSView*) peer->getNativeHandle();
       
        
        [v retain];
        [v removeFromSuperview];
        [peerView addSubview: v];
        [v release];
       
    }
   
    [v setHidden: ! owner->isShowing()];
}

```

# 使い方

例えば、VideoComponentを持つクラスに対して、

```AnyComponent.cpp

void bringViewToFront()
    {
        
#if JUCE_MAC
        NSViewComponent* view = static_cast<NSViewComponent*>(this->player_with_controller->getPimpl());
        if(view == nullptr) return;
        
        IRNSViewManager manager;
        manager.bringOpenGLContextFront(this, view);
        
#endif
        
    }

```

と、ここですみません。前言撤回。JuceのVideoComponentヘッダーファイルに一行足して、Pimpl型の変数ポインタを取得する必要がありました。

```juce_VideoComponent.h

    void*  getPimpl() { return pimpl.get(); }

```

# OpenGLContext

上では、より一般的にNSViewのコントロール方法、次は、OpenGLContextです。
今回は、Z-Orderだけではなく、OpenGLContextのアルファ値を変更するメソッドも追加で紹介します。
OpenGLContextを使用した際、背景を透過させたい時に使用してください。

**ただし、setOpenGLContextAlphaメソッドは、該当ComponentをaddAndMakeVisibleにてバインドした後に実行する必要があります。**


```OpenGLManager.hpp

class OpenGLManager
{
public:
    OpenGLManager(OpenGLContext* context) : context(context)
    {
        
    }
    ~OpenGLManager()
    {
        
    }
    
    void setOpenGLContextAlpha(GLint aValue = 0);
    void bringOpenGLContextFront(juce::Component* owner);
    
private:
    OpenGLContext* context;
};

```

```OpenGLManager.cpp

#include "OpenGLManager.hpp"

```

```OpenGLManager_mac.mm
#import <AppKit/AppKit.h>
#include "OpenGLManager.cpp"


void IROpenGLManager::setOpenGLContextAlpha(GLint aValue)
{
    NSOpenGLContext* context = (NSOpenGLContext*)this->context->getRawContext();
    
    if(context != nullptr)
        [context setValues:&aValue forParameter:NSOpenGLCPSurfaceOpacity];
    else
        std::cout << "Error : IROpenGLManager::setOpenGLContextAlpha() : could not get NSOpenGLContext : nullptr\n";
    
}

void IROpenGLManager::bringOpenGLContextFront(juce::Component* owner)
{
    
    NSOpenGLContext* context = (NSOpenGLContext*)this->context->getRawContext();
    if(context == nullptr)
    {
        std::cout << "Error : IROpenGLManager::bringOpenGLContextFront() : could not get NSOpenGLContext : nullptr\n";
        return;
    }
        
    
    auto* peer = owner->getPeer();
    if(peer != nullptr)
    {
        
        auto peerView = (NSView*) peer->getNativeHandle();
        [context.view retain];
        [context.view removeFromSuperview];
        [peerView addSubview: context.view];
        [context.view release];
        
    }
    
    [context.view setHidden: ! owner->isShowing()];
}

```

#使い方

```AnyComponent.hpp

void bringViewToFront() { //this->openGLContext.bringViewToFront();
        IROpenGLManager manager(&this->openGLContext);
        manager.bringOpenGLContextFront(this);
        
    }

```

背景を透過する時は、OpenGLRendererを継承し、

```AnyComponent.hpp
// inherit
public OpenGLRenderer

    void newOpenGLContextCreated()override
    {
    }
       
        virtual void renderOpenGL()override
    {
        // make the background transparent
        OpenGLHelpers::clear(Colours::transparentBlack);
    }
    
    virtual void openGLContextClosing() override
    {
        
    }

```

背景色を透明にする必要があります。
OpenGLManagerを使用する際は、JUCEライブラリをいじる必要はありません。