|
| 1 | +from kivy.core.window import Window |
| 2 | +from kivy.lang import Builder |
| 3 | +from kivy.properties import ObjectProperty, StringProperty |
| 4 | +from kivy.uix.relativelayout import RelativeLayout |
| 5 | +from kivy.uix.boxlayout import BoxLayout |
| 6 | +from kivy.utils import platform |
| 7 | +from camera4kivy import Preview, CameraProviderInfo |
| 8 | +from applayout.swipescreen import SwipeScreen |
| 9 | +from applayout.toast import Toast |
| 10 | + |
| 11 | +VS5 = """ |
| 12 | +<VideoScreen5>: |
| 13 | + video_preview: video_layout.ids.preview |
| 14 | + video_button: video_layout.video_button |
| 15 | + VideoLayout5: |
| 16 | + id:video_layout |
| 17 | +""" |
| 18 | + |
| 19 | +class VideoScreen5(SwipeScreen): |
| 20 | + video_preview = ObjectProperty(None) |
| 21 | + video_button = ObjectProperty(None) |
| 22 | + |
| 23 | + def __init__(self, **args): |
| 24 | + Builder.load_string(VS5) |
| 25 | + super().__init__(**args) |
| 26 | + |
| 27 | + def on_enter(self): |
| 28 | + self.video_preview.connect_camera(filepath_callback= self.capture_path, |
| 29 | + sensor_rotation = 90) |
| 30 | + |
| 31 | + def on_pre_leave(self): |
| 32 | + self.video_preview.disconnect_camera() |
| 33 | + |
| 34 | + def capture_path(self,file_path): |
| 35 | + # Reset button in cases where camera terminates video recording. |
| 36 | + self.video_button.state = 'normal' |
| 37 | + Toast().show(file_path) |
| 38 | + |
| 39 | +VL5 = """ |
| 40 | +<VideoLayout5>: |
| 41 | + video_button: buttons.ids.video |
| 42 | + Background5: |
| 43 | + id: pad_end |
| 44 | + Preview: |
| 45 | + id: preview |
| 46 | + orientation: 'portrait' |
| 47 | + letterbox_color: 'darkgrey' |
| 48 | + ButtonsLayout5: |
| 49 | + id: buttons |
| 50 | +
|
| 51 | +<Background5@Label>: |
| 52 | + color: 'darkgrey' |
| 53 | + canvas: |
| 54 | + Color: |
| 55 | + rgba: self.color |
| 56 | + Rectangle: |
| 57 | + pos: self.pos |
| 58 | + size: self.size |
| 59 | +""" |
| 60 | + |
| 61 | +class VideoLayout5(BoxLayout): |
| 62 | + |
| 63 | + def __init__(self, **args): |
| 64 | + Builder.load_string(VL5) |
| 65 | + super().__init__(**args) |
| 66 | + |
| 67 | + def on_size(self, layout, size): |
| 68 | + if Window.width < Window.height: |
| 69 | + self.orientation = 'vertical' |
| 70 | + self.ids.preview.size_hint = (1, .3) |
| 71 | + self.ids.buttons.size_hint = (1, .2) |
| 72 | + self.ids.pad_end.size_hint = (1, .1) |
| 73 | + else: |
| 74 | + self.orientation = 'horizontal' |
| 75 | + self.ids.preview.size_hint = (.3, 1) |
| 76 | + self.ids.buttons.size_hint = (.2, 1) |
| 77 | + self.ids.pad_end.size_hint = (.1, 1) |
| 78 | + |
| 79 | +BL5 = """ |
| 80 | +<ButtonsLayout5>: |
| 81 | + normal: |
| 82 | + down: |
| 83 | + txt: |
| 84 | + Background5: |
| 85 | + Label: |
| 86 | + text: root.txt |
| 87 | + Button: |
| 88 | + id:other |
| 89 | + on_press: root.photo() |
| 90 | + height: self.width |
| 91 | + width: self.height |
| 92 | + background_normal: 'icons/camera_white.png' |
| 93 | + background_down: 'icons/camera_red.png' |
| 94 | + ToggleButton: |
| 95 | + id:video |
| 96 | + on_press: root.video_action(self.state) |
| 97 | + height: self.width |
| 98 | + width: self.height |
| 99 | + background_normal: root.normal |
| 100 | + background_down: root.down |
| 101 | +""" |
| 102 | + |
| 103 | +class ButtonsLayout5(RelativeLayout): |
| 104 | + |
| 105 | + normal = StringProperty() |
| 106 | + down = StringProperty() |
| 107 | + txt = StringProperty() |
| 108 | + |
| 109 | + def __init__(self, **kwargs): |
| 110 | + Builder.load_string(BL5) |
| 111 | + super().__init__(**kwargs) |
| 112 | + self.provider = CameraProviderInfo().get_name() |
| 113 | + if self.provider in ['picamera2','opencv']: |
| 114 | + self.normal = 'icons/video_white.png' |
| 115 | + self.down = 'icons/video_red.png' |
| 116 | + else: |
| 117 | + self.normal = 'icons/video-off.png' |
| 118 | + self.down = 'icons/video-off.png' |
| 119 | + if self.provider in ['picamera2']: |
| 120 | + self.txt = 'Physically rotate the\ncamera by 90 deg to\na portrait orientation.' |
| 121 | + |
| 122 | + |
| 123 | + def on_size(self, layout, size): |
| 124 | + if Window.width < Window.height: |
| 125 | + self.ids.other.pos_hint = {'center_x':.3,'center_y':.5} |
| 126 | + self.ids.other.size_hint = (.2, None) |
| 127 | + self.ids.video.pos_hint = {'center_x':.7,'center_y':.5} |
| 128 | + self.ids.video.size_hint = (.24, None) |
| 129 | + else: |
| 130 | + self.ids.other.pos_hint = {'center_x':.5,'center_y':.7} |
| 131 | + self.ids.other.size_hint = (None, .2) |
| 132 | + self.ids.video.pos_hint = {'center_x':.5,'center_y':.3} |
| 133 | + self.ids.video.size_hint = (None, .24) |
| 134 | + |
| 135 | + def photo(self): |
| 136 | + self.parent.ids.preview.capture_photo() |
| 137 | + |
| 138 | + def video_action(self, state): |
| 139 | + if self.provider in ['picamera2', 'opencv']: |
| 140 | + if state == 'down': |
| 141 | + self.parent.ids.preview.capture_video() |
| 142 | + else: |
| 143 | + self.parent.ids.preview.stop_capture_video() |
| 144 | + |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | + |
| 150 | + |
0 commit comments