Coverage for tatlin/lib/ui/basescene.py: 72%

68 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-03-20 05:56 +0000

1# -*- coding: utf-8 -*- 

2# Copyright (C) 2011 Denis Kobozev 

3# 

4# This program is free software; you can redistribute it and/or modify 

5# it under the terms of the GNU General Public License as published by 

6# the Free Software Foundation; either version 2 of the License, or 

7# (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU General Public License for more details. 

13# 

14# You should have received a copy of the GNU General Public License 

15# along with this program; if not, write to the Free Software Foundation, 

16# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

17 

18import wx 

19from wx import glcanvas 

20 

21 

22class BaseScene(glcanvas.GLCanvas): 

23 def __init__(self, parent): 

24 try: # the new way 

25 super(BaseScene, self).__init__(parent, self._get_display_attributes()) 

26 except AttributeError: # the old way 

27 super(BaseScene, self).__init__(parent, attribList=self._get_attrib_list()) 

28 

29 self.Hide() 

30 

31 self.initialized = False 

32 self.context = glcanvas.GLContext(self) 

33 

34 self.Bind(wx.EVT_ERASE_BACKGROUND, self._on_erase_background) 

35 self.Bind(wx.EVT_SIZE, self._on_size) 

36 self.Bind(wx.EVT_PAINT, self._on_paint) 

37 self.Bind(wx.EVT_LEFT_DOWN, self._on_mouse_down) 

38 self.Bind(wx.EVT_MOTION, self._on_mouse_motion) 

39 

40 # make it unnecessary for the scene to be in focus to respond to the 

41 # mouse wheel by binding the mouse wheel event to the parent; if we 

42 # bound the event to the scene itself, the user would have to click on 

43 # the scene before scrolling each time the scene loses focus (users who 

44 # have the fortune of being able to use a window manager that has a 

45 # setting for focus-follows-mouse wouldn't care either way, since their 

46 # wm would handle it for them) 

47 parent.Bind(wx.EVT_MOUSEWHEEL, self._on_mouse_wheel) 

48 

49 methods = [ 

50 "init", 

51 "display", 

52 "reshape", 

53 "button_press", 

54 "button_motion", 

55 "wheel_scroll", 

56 ] 

57 for method in methods: 

58 if not hasattr(self, method): 

59 raise Exception("Method %s() is not implemented" % method) 

60 

61 @staticmethod 

62 def _get_display_attributes(): 

63 """Get the display attributes when using wxPython 4.1 or later.""" 

64 for depth in [32, 24, 16, 8]: 

65 dispAttrs = glcanvas.GLAttributes() 

66 dispAttrs.PlatformDefaults().DoubleBuffer().Depth(depth).EndList() 

67 

68 if glcanvas.GLCanvas.IsDisplaySupported(dispAttrs): 

69 return dispAttrs 

70 else: 

71 raise Exception("No suitable depth buffer value found") 

72 

73 @staticmethod 

74 def _get_attrib_list(): 

75 """Get the display attributes when using wxPython 4.0 or earlier.""" 

76 for depth in [32, 24, 16, 8]: 

77 attrib_list = [ 

78 glcanvas.WX_GL_RGBA, 

79 glcanvas.WX_GL_DOUBLEBUFFER, 

80 glcanvas.WX_GL_DEPTH_SIZE, 

81 depth, 

82 0, 

83 ] 

84 

85 if glcanvas.GLCanvas.IsDisplaySupported(attrib_list): 

86 return attrib_list 

87 else: 

88 raise Exception("No suitable depth buffer value found") 

89 

90 def invalidate(self): 

91 self.Refresh(False) 

92 

93 def _on_erase_background(self, event): 

94 pass # Do nothing, to avoid flashing on MSW. Doesn't seem to be working, though :( 

95 

96 def _on_size(self, event): 

97 wx.CallAfter(self._set_viewport) 

98 event.Skip() 

99 

100 def _set_viewport(self): 

101 self.SetCurrent(self.context) 

102 size = self.GetClientSize() 

103 self.reshape(size.width, size.height) 

104 

105 def _on_paint(self, event): 

106 dc = wx.PaintDC(self) 

107 self.SetCurrent(self.context) 

108 if not self.initialized: 

109 self.init() 

110 self.initialized = True 

111 size = self.GetClientSize() 

112 self.display(size.width, size.height) 

113 self.SwapBuffers() 

114 

115 def _on_mouse_down(self, event): 

116 self.SetFocus() 

117 x, y = event.GetPosition() 

118 self.button_press(x, y) 

119 

120 def _on_mouse_motion(self, event): 

121 x, y = event.GetPosition() 

122 left = event.LeftIsDown() 

123 middle = event.MiddleIsDown() 

124 right = event.RightIsDown() 

125 self.button_motion(x, y, left, middle, right) 

126 

127 def _on_mouse_wheel(self, event): 

128 self.wheel_scroll(event.GetWheelRotation())