1
2use {
3 crate::{
4 app::{AppData},
5 file_system::file_system::SnapshotImageData,
6 makepad_widgets::*,
7 },
8 makepad_platform::studio::{StudioToApp,StudioScreenshotRequest},
9 std::{
10 env,
11 },
12};
13
14live_design!{
15 use link::shaders::*;
16 use link::widgets::*;
17 use link::theme::*;
18 use makepad_widgets::designer_theme::*;
19
20 SnapshotItem = <RoundedView> {
21 height: Fit, width: Fill
22 draw_bg:{color:#2}
23 flow:Down
24 align:{x:0.5},
25
26 message = <Label>{text:"test", width:Fill, height:Fit}
27 run_button = <ButtonFlat> {
28 width: Fit,
29 height: Fit,
30 padding: <THEME_MSPACE_2> {}
31 margin: 0.
32 icon_walk: {
33 width: 12, height: Fit,
34 margin: { left: 10 }
35 }
36
37 draw_icon: {
38 color: (THEME_COLOR_U_4),
39 svg_file: dep("crate://self/resources/icons/icon_run.svg"),
40 }
41 icon_walk: { width: 9. }
42 }
43 image = <Image> {
44 width: 200,
45 height: 100
46 margin:{top:10,bottom:10}
47 fit: Horizontal,
50 draw_bg: {
51 instance hover: 0.0
52 instance down: 0.0
53 fn pixel(self) -> vec4 {
54 let sdf = Sdf2d::viewport(self.pos * self.rect_size)
55 sdf.box(1, 1, self.rect_size.x - 2, self.rect_size.y - 2, 4.0)
56 let max_scale = vec2(0.92);
57 let scale = mix(vec2(1.0), max_scale, self.hover);
58 let pan = mix(vec2(0.0), (vec2(1.0) - max_scale) * 0.5, self.hover)* self.image_scale;
59 let color = self.get_color_scale_pan(scale * self.image_scale, pan + self.image_pan) + mix(vec4(0.0), vec4(0.1), self.down);
60 if color.a<0.0001{
61 color = #3
62 }
63 sdf.fill_keep(color);
64 sdf.stroke(
65 mix(mix(#x0000, #x0006, self.hover), #xfff2, self.down),
66 1.0
67 )
68
69 return sdf.result
70 }
71 }
72 }
73 }
74
75 pub Snapshot = {{Snapshot}} <RectView> {
76 height: Fill, width: Fill,
77 flow: Down,
79 <DockToolbar> {
80 height: Fit
81 content = {
82 height: Fit
83 padding:{top:1}
84 spacing: (THEME_SPACE_2)
85 flow: Down
86 <View>{
87 height: Fit
88 spacing: 5
89 roots_dropdown = <DropDownFlat>{ width: Fit, popup_menu_position: BelowInput }
90 snapshot_button = <ButtonFlat>{text:"Snapshot"}
91 <Filler> {}
92 <ToggleFlat>{text:"Auto"}
93 }
94 message_input = <TextInputFlat>{empty_text:"Description"}
95 }
96 }
97 list = <PortalList> {
98 capture_overload: false,
99 grab_key_focus: false
100 auto_tail: true
101 drag_scrolling: false
102 max_pull_down: 0,
103 height: Fill, width: Fill,
104 flow: Down
105 SnapshotItem = <SnapshotItem> {}
106 Empty = <SolidView> {
107 cursor: Default
108 draw_bg:{color:#44}
109 width: Fill
110 height: 80,
111 }
112 }
113 }
114}
115
116#[derive(Clone, Debug, DefaultNone)]
117pub enum SnapshotAction {
118 Load(String),
119 None
120}
121
122#[derive(Live, LiveHook, Widget)]
123pub struct Snapshot{
124 #[deref] view:View,
125 #[rust] request_id: u64,
126}
127
128impl Snapshot{
129 fn draw_snapshots(&mut self, cx: &mut Cx2d, list:&mut PortalList, scope:&mut Scope, root_id:usize){
130 let data = scope.data.get_mut::<AppData>().unwrap();
131 let file_system = &mut data.file_system;
132 let git_log = file_system.git_logs.get(root_id as usize).unwrap();
133 list.set_item_range(cx, 0, git_log.commits.len());
134 while let Some(item_id) = list.next_visible_item(cx) {
135 let item = if let Some(commit) = git_log.commits.get(item_id){
136 let item = list.item(cx, item_id, live_id!(SnapshotItem)).as_view();
137 item.label(id!(message)).set_text(cx, &commit.message);
138 let image = item.image(id!(image));
141
142 let load = match file_system.snapshot_image_data.borrow().get(&commit.hash){
143 Some(SnapshotImageData::Loading)=>{
144 image.set_visible(cx, true);
145 false
146 }
147 Some(SnapshotImageData::Error)=>{
148 image.set_visible(cx, false);
149 false
150 }
151 Some(SnapshotImageData::Loaded{data, path})=>{
152 image.set_visible(cx, true);
153 image.load_image_from_data_async(cx, &path, data.clone()).ok();
154 false
155 }
156 None=>true
157 };
158 if load{
159 file_system.file_client.load_snapshot_image(&git_log.root, &commit.hash);
160 }
161 item
162 }
163 else{
164 list.item(cx, item_id, live_id!(Empty)).as_view()
165 };
166 item.draw_all(cx, &mut Scope::empty());
167 }
168 }
169
170 fn load_snapshot(&mut self, _cx:&mut Cx, data:&mut AppData, item_id:usize){
171 let root_id = self.drop_down(id!(roots_dropdown)).selected_item();
172 let git_log = data.file_system.git_logs.get(root_id).unwrap();
173 if let Some(commit) = git_log.commits.get(item_id){
174 data.file_system.load_snapshot(git_log.root.clone(), commit.hash.clone());
175 }
176 }
177
178 fn make_snapshot(&mut self, _cx:&mut Cx, data:&mut AppData){
179 let root_id = self.drop_down(id!(roots_dropdown)).selected_item();
180 let git_log = data.file_system.git_logs.get(root_id).unwrap();
181 let mut iter = data.build_manager.active.builds_with_root(git_log.root.clone());
184 if let Some(item) = iter.next(){
185 let message = self.view(id!(message_input)).text();
187 if message.len() == 0{
188 return
189 }
190 data.file_system.create_snapshot(git_log.root.clone(), message);
191 data.build_manager.active_build_websockets.lock().unwrap().borrow_mut().send_studio_to_app(*item.0, StudioToApp::Screenshot(StudioScreenshotRequest{
192 kind_id: 0,
193 request_id:self.request_id
194 }));
195 self.request_id += 1;
196 }
197 }
198}
199
200impl Widget for Snapshot {
201 fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk:Walk)->DrawStep{
202 let data = scope.data.get_mut::<AppData>().unwrap();
203
204 let dd = self.drop_down(id!(roots_dropdown));
205 let mut i = data.file_system.git_logs.iter();
206 dd.set_labels_with(cx, |label|{
207 i.next().map(|m| label.push_str(&m.root));
208 });
209 let root_id = dd.selected_item();
210 while let Some(step) = self.view.draw_walk(cx, scope, walk).step(){
211 if let Some(mut list) = step.as_portal_list().borrow_mut(){
212 self.draw_snapshots(cx, &mut *list, scope, root_id)
213 }
214 }
215 DrawStep::done()
216 }
217
218 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope){
219 let snapshots = self.view.portal_list(id!(list));
220 self.view.handle_event(cx, event, scope);
221 let data = scope.data.get_mut::<AppData>().unwrap();
222 if let Event::Actions(actions) = event{
223 if self.view.button(id!(snapshot_button)).clicked(actions){
224 self.make_snapshot(cx, data);
225 }
226 if let Some(_search) = self.view.text_input(id!(search_input)).changed(&actions){
227 }
228 for (item_id, _item) in snapshots.items_with_actions(&actions) {
229 if let Some(wa) = actions.widget_action(id!(run_button)){
230 if wa.widget().as_button().pressed(actions){
231 self.load_snapshot(cx, data, item_id);
232 }
233 }
234 }
235 }
236 }
237}
238
239impl SnapshotRef{
240 pub fn set_message(&self, cx:&mut Cx, message:String){
241 if let Some(inner) = self.borrow_mut(){
242 inner.view(id!(message_input)).set_text(cx, &message);
243 }
244 }
245}