| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE 6 technical preview.
 -    Copyright (c) 2020 - Raw Material Software Limited
 - 
 -    You may use this code under the terms of the GPL v3
 -    (see www.gnu.org/licenses).
 - 
 -    For this technical preview, this file is not subject to commercial licensing.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - 
 - /**
 -     This component runs in a slave process, draws the part of the canvas that this
 -     particular client covers, and updates itself when messages arrive from the master
 -     containing new canvas states.
 - */
 - class SlaveCanvasComponent  : public Component,
 -                               private OSCSender,
 -                               private OSCReceiver,
 -                               private OSCReceiver::Listener<OSCReceiver::RealtimeCallback>,
 -                               private AsyncUpdater,
 -                               private Timer
 - {
 - public:
 -     SlaveCanvasComponent (PropertiesFile& p, int windowIndex)  : properties (p)
 -     {
 -         {
 -             String uuidPropName ("UUID" + String (windowIndex));
 -             clientName = properties.getValue (uuidPropName);
 - 
 -             if (clientName.isEmpty())
 -             {
 -                 clientName = "CLIENT_" + String (Random().nextInt (10000)).toUpperCase();
 -                 properties.setValue (uuidPropName, clientName);
 -             }
 -         }
 - 
 -         setOpaque (true);
 -         setSize (1500, 900);
 - 
 -         if (! OSCSender::connect (getBroadcastIPAddress(), clientPortNumber))
 -             error = "Client app OSC sender: network connection error.";
 - 
 -         if (! OSCReceiver::connect (masterPortNumber))
 -             error = "Client app OSC receiver: network connection error.";
 - 
 -         OSCReceiver::addListener (this);
 - 
 -         timerCallback();
 -         startTimer (2000);
 -     }
 - 
 -     ~SlaveCanvasComponent() override
 -     {
 -         OSCReceiver::removeListener (this);
 -     }
 - 
 - private:
 -     void mouseDrag (const MouseEvent& e) override
 -     {
 -         auto clientArea = getAreaInGlobalSpace();
 - 
 -         if (! clientArea.isEmpty())
 -         {
 -             OSCMessage message (userInputOSCAddress);
 - 
 -             message.addString (clientName);
 -             message.addFloat32 (e.position.x * clientArea.getWidth()  / getWidth()  + clientArea.getX());
 -             message.addFloat32 (e.position.y * clientArea.getHeight() / getHeight() + clientArea.getY());
 - 
 -             send (message);
 -         }
 -     }
 - 
 -     //==============================================================================
 -     void oscMessageReceived (const OSCMessage& message) override
 -     {
 -         auto address = message.getAddressPattern();
 - 
 -         if (address.matches (canvasStateOSCAddress))
 -             canvasStateOSCMessageReceived (message);
 -     }
 - 
 -     struct NewStateMessage  : public Message
 -     {
 -         NewStateMessage (const MemoryBlock& d) : data (d) {}
 -         MemoryBlock data;
 -     };
 - 
 -     void canvasStateOSCMessageReceived (const OSCMessage& message)
 -     {
 -         if (message.isEmpty() || ! message[0].isBlob())
 -             return;
 - 
 -         if (packetiser.appendIncomingBlock (message[0].getBlob()))
 -         {
 -             const ScopedLock sl (canvasLock);
 - 
 -             MemoryBlock newCanvasData;
 - 
 -             if (packetiser.reassemble (newCanvasData))
 -             {
 -                 MemoryInputStream i (newCanvasData.getData(), newCanvasData.getSize(), false);
 -                 canvas2.load (i);
 -                 triggerAsyncUpdate();
 -             }
 -         }
 -     }
 - 
 -     //==============================================================================
 -     String getMachineInfoToDisplay() const
 -     {
 -         auto display = Desktop::getInstance().getDisplays().findDisplayForPoint (getScreenBounds().getCentre());
 -         return getOSName() + "   " + String (display.dpi) + "   "  + String (display.scale);
 -     }
 - 
 -     static String getOSName()
 -     {
 -        #if JUCE_MAC
 -         return "Mac OSX";
 -        #elif JUCE_ANDROID
 -         return "Android";
 -        #elif JUCE_IOS
 -         return "iOS";
 -        #elif JUCE_WINDOWS
 -         return "Windows";
 -        #elif JUCE_LINUX
 -         return "Linux";
 -        #endif
 -     }
 - 
 -     void paint (Graphics& g) override
 -     {
 -         g.fillAll (canvas.backgroundColour);
 - 
 -         auto clientArea = getAreaInGlobalSpace();
 - 
 -         if (clientArea.isEmpty())
 -         {
 -             g.setColour (Colours::red.withAlpha (0.5f));
 -             g.setFont (20.0f);
 -             g.drawText ("Not Connected", getLocalBounds(), Justification::centred, false);
 -             return;
 -         }
 - 
 -         canvas.draw (g, getLocalBounds().toFloat(), clientArea);
 - 
 -         g.setFont (Font (34.0f));
 -         g.setColour (Colours::white.withAlpha (0.6f));
 - 
 -         g.drawText (getMachineInfoToDisplay(),
 -                     getLocalBounds().reduced (10).removeFromBottom (20),
 -                     Justification::centredRight, true);
 - 
 -         if (error.isNotEmpty())
 -         {
 -             g.setColour (Colours::red);
 -             g.drawText (error, getLocalBounds().reduced (10).removeFromBottom (80),
 -                         Justification::centredRight, true);
 -         }
 -     }
 - 
 -     Rectangle<float> getAreaInGlobalSpace() const
 -     {
 -         if (auto client = canvas.findClient (clientName))
 -         {
 -             auto screenBounds = getScreenBounds();
 -             auto display = Desktop::getInstance().getDisplays().findDisplayForPoint (screenBounds.getCentre());
 -             return ((screenBounds - display.userArea.getCentre()).toFloat() / (client->scaleFactor * display.dpi / display.scale)) + client->centre;
 -         }
 - 
 -         return {};
 -     }
 - 
 -     Rectangle<float> getScreenAreaInGlobalSpace() const
 -     {
 -         if (auto client = canvas.findClient (clientName))
 -         {
 -             auto display = Desktop::getInstance().getDisplays().findDisplayForPoint (getScreenBounds().getCentre());
 -             return (display.userArea.toFloat() / (client->scaleFactor * display.dpi / display.scale)).withCentre (client->centre);
 -         }
 - 
 -         return {};
 -     }
 - 
 -     void timerCallback() override
 -     {
 -         send (newClientOSCAddress, clientName + ":" + IPAddress::getLocalAddress().toString()
 -                                               + ":" + getScreenAreaInGlobalSpace().toString());
 -     }
 - 
 -     void handleAsyncUpdate() override
 -     {
 -         const ScopedLock sl (canvasLock);
 -         canvas.swapWith (canvas2);
 -         repaint();
 -     }
 - 
 -     SharedCanvasDescription canvas, canvas2;
 -     PropertiesFile& properties;
 -     String clientName, error;
 - 
 -     CriticalSection canvasLock;
 -     BlockPacketiser packetiser;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SlaveCanvasComponent)
 - };
 
 
  |