Browse Source

Merge branch 'release/1.10.x'

rdb 5 years ago
parent
commit
2156e6deb2

+ 76 - 1
direct/src/dist/FreezeTool.py

@@ -638,7 +638,9 @@ okMissing = [
     'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios', 'vms_lib',
     'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios', 'vms_lib',
     'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
     'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
     'email.Iterators', '_subprocess', 'gestalt', 'java.lang',
     'email.Iterators', '_subprocess', 'gestalt', 'java.lang',
-    'direct.extensions_native.extensions_darwin',
+    'direct.extensions_native.extensions_darwin', '_manylinux',
+    'collections.Iterable', 'collections.Mapping', 'collections.MutableMapping',
+    'collections.Sequence', 'numpy_distutils',
     ]
     ]
 
 
 # Since around macOS 10.15, Apple's codesigning process has become more strict.
 # Since around macOS 10.15, Apple's codesigning process has become more strict.
@@ -2500,6 +2502,9 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
         except ImportError as msg:
         except ImportError as msg:
             self.msg(2, "ImportError:", str(msg))
             self.msg(2, "ImportError:", str(msg))
             self._add_badmodule(name, caller)
             self._add_badmodule(name, caller)
+        except SyntaxError as msg:
+            self.msg(2, "SyntaxError:", str(msg))
+            self._add_badmodule(name, caller)
         else:
         else:
             if fromlist:
             if fromlist:
                 for sub in fromlist:
                 for sub in fromlist:
@@ -2513,6 +2518,76 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
                         self.msg(2, "ImportError:", str(msg))
                         self.msg(2, "ImportError:", str(msg))
                         self._add_badmodule(fullname, caller)
                         self._add_badmodule(fullname, caller)
 
 
+    def scan_code(self, co, m):
+        code = co.co_code
+        # This was renamed to scan_opcodes in Python 3.6
+        if hasattr(self, 'scan_opcodes_25'):
+            scanner = self.scan_opcodes_25
+        else:
+            scanner = self.scan_opcodes
+
+        for what, args in scanner(co):
+            if what == "store":
+                name, = args
+                m.globalnames[name] = 1
+            elif what in ("import", "absolute_import"):
+                fromlist, name = args
+                have_star = 0
+                if fromlist is not None:
+                    if "*" in fromlist:
+                        have_star = 1
+                    fromlist = [f for f in fromlist if f != "*"]
+                if what == "absolute_import": level = 0
+                else: level = -1
+                self._safe_import_hook(name, m, fromlist, level=level)
+                if have_star:
+                    # We've encountered an "import *". If it is a Python module,
+                    # the code has already been parsed and we can suck out the
+                    # global names.
+                    mm = None
+                    if m.__path__:
+                        # At this point we don't know whether 'name' is a
+                        # submodule of 'm' or a global module. Let's just try
+                        # the full name first.
+                        mm = self.modules.get(m.__name__ + "." + name)
+                    if mm is None:
+                        mm = self.modules.get(name)
+                    if mm is not None:
+                        m.globalnames.update(mm.globalnames)
+                        m.starimports.update(mm.starimports)
+                        if mm.__code__ is None:
+                            m.starimports[name] = 1
+                    else:
+                        m.starimports[name] = 1
+            elif what == "relative_import":
+                level, fromlist, name = args
+                parent = self.determine_parent(m, level=level)
+                if name:
+                    self._safe_import_hook(name, m, fromlist, level=level)
+                else:
+                    self._safe_import_hook(parent.__name__, None, fromlist, level=0)
+
+                if fromlist and "*" in fromlist:
+                    if name:
+                        mm = self.modules.get(parent.__name__ + "." + name)
+                    else:
+                        mm = self.modules.get(parent.__name__)
+
+                    if mm is not None:
+                        m.globalnames.update(mm.globalnames)
+                        m.starimports.update(mm.starimports)
+                        if mm.__code__ is None:
+                            m.starimports[name] = 1
+                    else:
+                        m.starimports[name] = 1
+            else:
+                # We don't expect anything else from the generator.
+                raise RuntimeError(what)
+
+        for c in co.co_consts:
+            if isinstance(c, type(co)):
+                self.scan_code(c, m)
+
     def find_module(self, name, path=None, parent=None):
     def find_module(self, name, path=None, parent=None):
         """ Finds a module with the indicated name on the given search path
         """ Finds a module with the indicated name on the given search path
         (or self.path if None).  Returns a tuple like (fp, path, stuff), where
         (or self.path if None).  Returns a tuple like (fp, path, stuff), where

+ 3 - 1
direct/src/dist/commands.py

@@ -408,7 +408,8 @@ class build_apps(setuptools.Command):
             abi_tag += 'm'
             abi_tag += 'm'
 
 
         whldir = os.path.join(whlcache, '_'.join((platform, abi_tag)))
         whldir = os.path.join(whlcache, '_'.join((platform, abi_tag)))
-        os.makedirs(whldir, exist_ok=True)
+        if not os.path.isdir(whldir):
+            os.makedirs(whldir)
 
 
         # Remove any .zip files. These are built from a VCS and block for an
         # Remove any .zip files. These are built from a VCS and block for an
         # interactive prompt on subsequent downloads.
         # interactive prompt on subsequent downloads.
@@ -946,6 +947,7 @@ class build_apps(setuptools.Command):
                    not pattern.pattern.endswith('/**'):
                    not pattern.pattern.endswith('/**'):
                     continue
                     continue
 
 
+                pattern_dir = p3d.Filename(pattern.pattern).get_dirname()
                 if abspath.startswith(pattern_dir + '/'):
                 if abspath.startswith(pattern_dir + '/'):
                     return True
                     return True
 
 

+ 92 - 10
direct/src/gui/OnscreenText.py

@@ -293,43 +293,121 @@ class OnscreenText(NodePath):
 
 
     text = property(getText, setText)
     text = property(getText, setText)
 
 
+    def setTextX(self, x):
+        self.setTextPos(x, self.__pos[1])
+
     def setX(self, x):
     def setX(self, x):
-        self.setPos(x, self.__pos[1])
+        """
+        .. deprecated:: 1.11.0
+           Use `.setTextX()` method instead.
+        """
+        self.setTextPos(x, self.__pos[1])
+
+    def setTextY(self, y):
+        self.setTextPos(self.__pos[0], y)
 
 
     def setY(self, y):
     def setY(self, y):
-        self.setPos(self.__pos[0], y)
+        """
+        .. deprecated:: 1.11.0
+           Use `.setTextY()` method instead.
+        """
+        self.setTextPos(self.__pos[0], y)
+
+    def setTextPos(self, x, y=None):
+        """
+        Position the onscreen text in 2d screen space
+        """
+        if y is None:
+            self.__pos = tuple(x)
+        else:
+            self.__pos = (x, y)
+        self.updateTransformMat()
+
+    def getTextPos(self):
+        return self.__pos
+
+    text_pos = property(getTextPos, setTextPos)
 
 
     def setPos(self, x, y):
     def setPos(self, x, y):
         """setPos(self, float, float)
         """setPos(self, float, float)
         Position the onscreen text in 2d screen space
         Position the onscreen text in 2d screen space
+
+        .. deprecated:: 1.11.0
+           Use `.setTextPos()` method or `.text_pos` property instead.
         """
         """
         self.__pos = (x, y)
         self.__pos = (x, y)
         self.updateTransformMat()
         self.updateTransformMat()
 
 
     def getPos(self):
     def getPos(self):
+        """
+        .. deprecated:: 1.11.0
+           Use `.getTextPos()` method or `.text_pos` property instead.
+        """
         return self.__pos
         return self.__pos
 
 
-    pos = property(getPos, setPos)
+    pos = property(getPos)
+
+    def setTextR(self, r):
+        """setTextR(self, float)
+        Rotates the text around the screen's normal.
+        """
+        self.__roll = -r
+        self.updateTransformMat()
+
+    def getTextR(self):
+        return -self.__roll
+
+    text_r = property(getTextR, setTextR)
 
 
     def setRoll(self, roll):
     def setRoll(self, roll):
         """setRoll(self, float)
         """setRoll(self, float)
-        Rotate the onscreen text around the screen's normal
+        Rotate the onscreen text around the screen's normal.
+
+        .. deprecated:: 1.11.0
+           Use ``setTextR(-roll)`` instead (note the negated sign).
         """
         """
         self.__roll = roll
         self.__roll = roll
         self.updateTransformMat()
         self.updateTransformMat()
 
 
     def getRoll(self):
     def getRoll(self):
+        """
+        .. deprecated:: 1.11.0
+           Use ``-getTextR()`` instead (note the negated sign).
+        """
         return self.__roll
         return self.__roll
 
 
     roll = property(getRoll, setRoll)
     roll = property(getRoll, setRoll)
 
 
+    def setTextScale(self, sx, sy = None):
+        """setTextScale(self, float, float)
+        Scale the text in 2d space.  You may specify either a single
+        uniform scale, or two scales, or a tuple of two scales.
+        """
+
+        if sy is None:
+            if isinstance(sx, tuple):
+                self.__scale = sx
+            else:
+                self.__scale = (sx, sx)
+        else:
+            self.__scale = (sx, sy)
+        self.updateTransformMat()
+
+    def getTextScale(self):
+        return self.__scale
+
+    text_scale = property(getTextScale, setTextScale)
+
     def setScale(self, sx, sy = None):
     def setScale(self, sx, sy = None):
         """setScale(self, float, float)
         """setScale(self, float, float)
         Scale the text in 2d space.  You may specify either a single
         Scale the text in 2d space.  You may specify either a single
         uniform scale, or two scales, or a tuple of two scales.
         uniform scale, or two scales, or a tuple of two scales.
+
+        .. deprecated:: 1.11.0
+           Use `.setTextScale()` method or `.text_scale` property instead.
         """
         """
 
 
-        if sy == None:
+        if sy is None:
             if isinstance(sx, tuple):
             if isinstance(sx, tuple):
                 self.__scale = sx
                 self.__scale = sx
             else:
             else:
@@ -338,6 +416,15 @@ class OnscreenText(NodePath):
             self.__scale = (sx, sy)
             self.__scale = (sx, sy)
         self.updateTransformMat()
         self.updateTransformMat()
 
 
+    def getScale(self):
+        """
+        .. deprecated:: 1.11.0
+           Use `.getTextScale()` method or `.text_scale` property instead.
+        """
+        return self.__scale
+
+    scale = property(getScale, setScale)
+
     def updateTransformMat(self):
     def updateTransformMat(self):
         assert(isinstance(self.textNode, TextNode))
         assert(isinstance(self.textNode, TextNode))
         mat = (
         mat = (
@@ -347,11 +434,6 @@ class OnscreenText(NodePath):
             )
             )
         self.textNode.setTransform(mat)
         self.textNode.setTransform(mat)
 
 
-    def getScale(self):
-        return self.__scale
-
-    scale = property(getScale, setScale)
-
     def setWordwrap(self, wordwrap):
     def setWordwrap(self, wordwrap):
         self.__wordwrap = wordwrap
         self.__wordwrap = wordwrap
 
 

+ 3 - 1
doc/ReleaseNotes

@@ -4,7 +4,8 @@ Recommended maintenance release.
 
 
 * Support building for macOS 11 "Big Sur" and "Apple Silicon" (arm64)
 * Support building for macOS 11 "Big Sur" and "Apple Silicon" (arm64)
 * Fix a memory leak, particularly noticeable with multithreaded pipeline (#1077)
 * Fix a memory leak, particularly noticeable with multithreaded pipeline (#1077)
-* Fix problem building Windows binaries using deployment system
+* Fix crash on macOS when unplugging device with threading active (#1082)
+* Fix error with build_apps not working with certain versions of Python
 * Fix DirectEntry/PGEntry flickering in the multithreaded pipeline (#1070)
 * Fix DirectEntry/PGEntry flickering in the multithreaded pipeline (#1070)
 * Fix sounds resuming on reactivation if stop() was called while inactive (#559)
 * Fix sounds resuming on reactivation if stop() was called while inactive (#559)
 * Collision traverser now releases GIL during traversal (#1033)
 * Collision traverser now releases GIL during traversal (#1033)
@@ -16,6 +17,7 @@ Recommended maintenance release.
 * Fix compilation error with Bullet 2.90+
 * Fix compilation error with Bullet 2.90+
 * Assimp library was updated in Windows thirdparty packages (#1020)
 * Assimp library was updated in Windows thirdparty packages (#1020)
 * libCg is now shipped as library instead of framework on macOS (#1079)
 * libCg is now shipped as library instead of framework on macOS (#1079)
+* Fix some erroneous warnings about missing modules in build_apps
 * Add warnings to build_apps when forgetting dependencies in requirements.txt
 * Add warnings to build_apps when forgetting dependencies in requirements.txt
 * Add experimental TextureStage::M_emission mode
 * Add experimental TextureStage::M_emission mode
 * Add experimental p3d_TextureNormal, p3d_TextureEmission, etc. GLSL inputs
 * Add experimental p3d_TextureNormal, p3d_TextureEmission, etc. GLSL inputs

+ 2 - 0
panda/src/device/inputDeviceManager.cxx

@@ -111,6 +111,8 @@ add_device(InputDevice *device) {
  */
  */
 void InputDeviceManager::
 void InputDeviceManager::
 remove_device(InputDevice *device) {
 remove_device(InputDevice *device) {
+  // We need to hold a reference, since remove_device decrements the refcount.
+  PT(InputDevice) device_ref = device;
   {
   {
     LightMutexHolder holder(_lock);
     LightMutexHolder holder(_lock);
     _connected_devices.remove_device(device);
     _connected_devices.remove_device(device);

+ 171 - 0
tests/gui/test_OnscreenText.py

@@ -0,0 +1,171 @@
+from direct.gui.OnscreenText import OnscreenText
+
+
+def test_onscreentext_text_pos():
+    text = OnscreenText(pos=(1, 2))
+    assert text['pos'] == (1, 2)
+    assert text.pos == (1, 2)
+    assert text.getPos() == (1, 2)
+    assert text.text_pos == (1, 2)
+    assert text.getTextPos() == (1, 2)
+    assert text.get_pos() == (0, 0, 0)
+
+    text.setTextPos(3, 4)
+    assert text['pos'] == (3, 4)
+    assert text.pos == (3, 4)
+    assert text.getPos() == (3, 4)
+    assert text.text_pos == (3, 4)
+    assert text.getTextPos() == (3, 4)
+    assert text.get_pos() == (0, 0, 0)
+
+    text.text_pos = (7, 8)
+    assert text['pos'] == (7, 8)
+    assert text.pos == (7, 8)
+    assert text.getPos() == (7, 8)
+    assert text.text_pos == (7, 8)
+    assert text.getTextPos() == (7, 8)
+    assert text.get_pos() == (0, 0, 0)
+
+    text.setPos(9, 10)
+    assert text['pos'] == (9, 10)
+    assert text.pos == (9, 10)
+    assert text.getPos() == (9, 10)
+    assert text.text_pos == (9, 10)
+    assert text.getTextPos() == (9, 10)
+    assert text.get_pos() == (0, 0, 0)
+
+    text['pos'] = (11, 12)
+    assert text['pos'] == (11, 12)
+    assert text.pos == (11, 12)
+    assert text.getPos() == (11, 12)
+    assert text.text_pos == (11, 12)
+    assert text.getTextPos() == (11, 12)
+    assert text.get_pos() == (0, 0, 0)
+
+
+def test_onscreentext_node_pos():
+    text = OnscreenText()
+
+    text.set_pos(1, 2, 3)
+    assert text['pos'] == (0, 0)
+    assert text.pos == (0, 0)
+    assert text.getPos() == (0, 0)
+    assert text.text_pos == (0, 0)
+    assert text.getTextPos() == (0, 0)
+    assert text.get_pos() == (1, 2, 3)
+
+
+def test_onscreentext_text_roll():
+    text = OnscreenText(roll=1)
+    assert text['roll'] == 1
+    assert text.roll == 1
+    assert text.getRoll() == 1
+    assert text.text_r == -1
+    assert text.getTextR() == -1
+    assert text.get_r() == 0
+
+    text.setTextR(2)
+    assert text['roll'] == -2
+    assert text.roll == -2
+    assert text.getRoll() == -2
+    assert text.text_r == 2
+    assert text.getTextR() == 2
+    assert text.get_r() == 0
+
+    text.text_r = 3
+    assert text['roll'] == -3
+    assert text.roll == -3
+    assert text.getRoll() == -3
+    assert text.text_r == 3
+    assert text.getTextR() == 3
+    assert text.get_r() == 0
+
+    text.setRoll(4)
+    assert text['roll'] == 4
+    assert text.roll == 4
+    assert text.getRoll() == 4
+    assert text.text_r == -4
+    assert text.getTextR() == -4
+    assert text.get_r() == 0
+
+    text['roll'] = 5
+    assert text['roll'] == 5
+    assert text.roll == 5
+    assert text.getRoll() == 5
+    assert text.text_r == -5
+    assert text.getTextR() == -5
+    assert text.get_r() == 0
+
+
+def test_onscreentext_node_roll():
+    text = OnscreenText()
+
+    text.set_r(45)
+    assert text['roll'] == 0
+    assert text.roll == 0
+    assert text.getRoll() == 0
+    assert text.text_r == 0
+    assert text.getTextR() == 0
+    assert text.get_r() == 45
+
+
+def test_onscreentext_text_scale():
+    text = OnscreenText(scale=(1, 2))
+    assert text['scale'] == (1, 2)
+    assert text.scale == (1, 2)
+    assert text.getScale() == (1, 2)
+    assert text.text_scale == (1, 2)
+    assert text.getTextScale() == (1, 2)
+    assert text.get_scale() == (1, 1, 1)
+
+    text.setTextScale(3, 4)
+    assert text['scale'] == (3, 4)
+    assert text.scale == (3, 4)
+    assert text.getScale() == (3, 4)
+    assert text.text_scale == (3, 4)
+    assert text.getTextScale() == (3, 4)
+    assert text.get_scale() == (1, 1, 1)
+
+    text.text_scale = (7, 8)
+    assert text['scale'] == (7, 8)
+    assert text.scale == (7, 8)
+    assert text.getScale() == (7, 8)
+    assert text.text_scale == (7, 8)
+    assert text.getTextScale() == (7, 8)
+    assert text.get_scale() == (1, 1, 1)
+
+    text.setScale(9, 10)
+    assert text['scale'] == (9, 10)
+    assert text.scale == (9, 10)
+    assert text.getScale() == (9, 10)
+    assert text.text_scale == (9, 10)
+    assert text.getTextScale() == (9, 10)
+    assert text.get_scale() == (1, 1, 1)
+
+    text['scale'] = (11, 12)
+    assert text['scale'] == (11, 12)
+    assert text.scale == (11, 12)
+    assert text.getScale() == (11, 12)
+    assert text.text_scale == (11, 12)
+    assert text.getTextScale() == (11, 12)
+    assert text.get_scale() == (1, 1, 1)
+
+    text.scale = 13
+    assert text['scale'] == (13, 13)
+    assert text.scale == (13, 13)
+    assert text.getScale() == (13, 13)
+    assert text.text_scale == (13, 13)
+    assert text.getTextScale() == (13, 13)
+    assert text.get_scale() == (1, 1, 1)
+
+
+def test_onscreentext_node_scale():
+    text = OnscreenText()
+
+    text.set_scale(1, 2, 3)
+    assert text['scale'] == (0.07, 0.07)
+    assert text.scale == (0.07, 0.07)
+    assert text.getScale() == (0.07, 0.07)
+    assert text.text_scale == (0.07, 0.07)
+    assert text.getTextScale() == (0.07, 0.07)
+    assert text.get_scale() == (1, 2, 3)