added mobile/web ui

This commit is contained in:
aOK 2024-09-26 21:26:02 +03:00
parent a93c31c9e7
commit 6f512eaa61
42 changed files with 1182 additions and 137 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
*.fish
/target
vcf.rs

View file

@ -0,0 +1 @@

10
resources/icons/chat.svg Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path d="M14.347,4.864C14.899,4.865 15.347,5.313 15.347,5.865C15.347,6.416 14.899,6.865 14.347,6.864L4.221,6.864C3.301,6.864 2.555,7.611 2.555,8.531L2.555,22.323C2.555,23.243 3.301,23.989 4.221,23.989L7.128,23.989C7.68,23.989 8.128,24.437 8.128,24.989L8.128,29.433C8.128,29.737 8.501,29.882 8.707,29.659L13.214,24.746C13.656,24.264 14.279,23.989 14.933,23.989L24.293,23.989C25.213,23.989 25.959,23.243 25.959,22.323L25.959,18.621C25.96,18.069 26.408,17.621 26.96,17.621C27.511,17.621 27.96,18.069 27.959,18.621L27.959,22.323C27.959,24.348 26.318,25.989 24.293,25.989L14.933,25.989C14.84,25.989 14.751,26.028 14.688,26.097L10.18,31.011C8.742,32.578 6.128,31.561 6.128,29.433L6.128,25.989L4.221,25.989C2.196,25.989 0.555,24.348 0.555,22.323L0.555,8.531C0.555,6.506 2.196,4.864 4.221,4.864L14.347,4.864Z" style="fill:rgb(52,64,84);"/>
<path d="M21.22,4.459L27.779,4.459C27.779,4.459 31.446,4.459 31.446,8.125L31.446,12.043C31.446,12.043 31.446,15.709 27.779,15.709L21.22,15.709C21.22,15.709 17.554,15.709 17.554,12.043L17.554,8.125C17.554,8.125 17.554,4.459 21.22,4.459ZM21.22,6.459C19.554,6.459 19.554,8.125 19.554,8.125L19.554,12.043C19.554,13.709 21.22,13.709 21.22,13.709L27.779,13.709C29.446,13.709 29.446,12.043 29.446,12.043L29.446,8.125C29.446,6.459 27.779,6.459 27.779,6.459L21.22,6.459Z"/>
<path d="M23.499,1.809C23.499,1.257 23.947,0.809 24.499,0.809C25.051,0.809 25.499,1.257 25.499,1.809L25.499,5.458C25.499,6.01 25.051,6.458 24.499,6.458C23.947,6.458 23.499,6.01 23.499,5.458L23.499,1.809Z"/>
<path d="M21.571,9.566C21.571,9.152 21.907,8.816 22.321,8.816C22.735,8.816 23.071,9.152 23.071,9.566L23.071,10.615C23.071,11.029 22.735,11.365 22.321,11.365C21.907,11.365 21.571,11.029 21.571,10.615L21.571,9.566Z"/>
<path d="M25.926,9.566C25.926,9.152 26.262,8.816 26.676,8.816C27.09,8.816 27.426,9.152 27.426,9.566L27.426,10.615C27.426,11.029 27.09,11.365 26.676,11.365C26.262,11.365 25.926,11.029 25.926,10.615L25.926,9.566Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.654 1.059 C 3.292 1.125,3.120 1.181,2.820 1.331 C 2.137 1.672,1.637 2.181,1.304 2.878 C 0.998 3.516,1.020 2.804,1.020 12.000 C 1.020 19.750,1.024 20.237,1.091 20.524 C 1.361 21.672,2.328 22.639,3.476 22.909 C 3.763 22.976,4.250 22.980,12.000 22.980 C 19.750 22.980,20.237 22.976,20.524 22.909 C 21.672 22.639,22.639 21.672,22.909 20.524 C 22.976 20.237,22.980 19.750,22.980 12.000 C 22.980 4.250,22.976 3.763,22.909 3.476 C 22.646 2.357,21.747 1.433,20.606 1.107 L 20.300 1.020 12.120 1.013 C 5.545 1.008,3.884 1.017,3.654 1.059 M14.320 12.000 L 14.320 21.000 9.162 21.000 C 4.050 21.000,4.001 20.999,3.783 20.918 C 3.528 20.822,3.251 20.572,3.113 20.315 L 3.020 20.140 3.010 12.086 C 3.003 6.680,3.013 3.981,3.040 3.879 C 3.131 3.543,3.524 3.139,3.854 3.044 C 3.927 3.023,6.174 3.006,9.150 3.004 L 14.320 3.000 14.320 12.000 M20.220 3.083 C 20.518 3.195,20.805 3.482,20.917 3.780 L 21.000 4.003 21.000 12.000 L 21.000 19.997 20.917 20.220 C 20.805 20.518,20.518 20.805,20.220 20.917 C 20.006 20.997,19.924 21.000,18.158 21.000 L 16.320 21.000 16.320 12.000 L 16.320 3.000 18.158 3.000 C 19.924 3.000,20.006 3.003,20.220 3.083 M7.137 7.773 C 6.649 8.006,6.428 8.619,6.662 9.088 C 6.698 9.161,7.351 9.845,8.114 10.610 L 9.500 12.000 8.114 13.390 C 7.351 14.155,6.698 14.839,6.662 14.912 C 6.422 15.392,6.662 16.022,7.167 16.239 C 7.413 16.345,7.770 16.337,8.002 16.221 C 8.078 16.183,8.952 15.339,9.945 14.346 C 11.568 12.722,11.756 12.520,11.815 12.343 C 11.897 12.094,11.897 11.906,11.815 11.657 C 11.756 11.480,11.568 11.278,9.945 9.654 C 8.952 8.661,8.077 7.816,8.000 7.778 C 7.923 7.739,7.743 7.701,7.600 7.692 C 7.386 7.679,7.304 7.693,7.137 7.773 " stroke="none" fill-rule="evenodd" fill="black"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path d="M0,16C0,11.757 1.686,7.687 4.686,4.686C7.687,1.686 11.757,0 16,0C20.243,0 24.313,1.686 27.314,4.686C30.314,7.687 32,11.757 32,16C32,20.243 30.314,24.313 27.314,27.314C24.313,30.314 20.243,32 16,32C11.757,32 7.687,30.314 4.686,27.314C1.686,24.313 0,20.243 0,16ZM2,16C2,19.713 3.475,23.274 6.101,25.899C8.726,28.525 12.287,30 16,30C19.713,30 23.274,28.525 25.899,25.899C28.525,23.274 30,19.713 30,16C30,12.287 28.525,8.726 25.899,6.101C23.274,3.475 19.713,2 16,2C12.287,2 8.726,3.475 6.101,6.101C3.475,8.726 2,12.287 2,16Z" style="fill:rgb(34,34,34);"/>
<path d="M24.389,10.338C24.389,10.339 24.387,10.342 24.387,10.343L21.034,20.402C20.925,20.73 20.653,20.979 20.315,21.059C19.978,21.138 19.624,21.038 19.379,20.793L11.208,12.622C10.963,12.377 10.862,12.022 10.942,11.685C11.021,11.348 11.27,11.076 11.598,10.966C11.598,10.966 21.657,7.606 21.652,7.608C22.033,7.478 22.443,7.458 22.835,7.549C23.227,7.641 23.586,7.84 23.871,8.125C24.155,8.409 24.355,8.768 24.446,9.16C24.537,9.55 24.517,9.958 24.389,10.338ZM22.494,9.699C22.503,9.672 22.504,9.642 22.498,9.614C22.491,9.585 22.477,9.559 22.456,9.539C22.436,9.518 22.41,9.504 22.381,9.497C22.353,9.491 22.323,9.492 22.296,9.501L22.291,9.503L13.765,12.351L19.649,18.234L22.492,9.705L22.494,9.699Z" style="fill:rgb(34,34,34);"/>
<path d="M10.966,11.598C11.141,11.075 11.707,10.791 12.231,10.966C12.755,11.141 13.038,11.707 12.863,12.231L9.507,22.295L9.505,22.3C9.496,22.328 9.495,22.358 9.501,22.386C9.508,22.414 9.522,22.441 9.543,22.461C9.563,22.482 9.589,22.496 9.618,22.503C9.646,22.509 9.676,22.508 9.703,22.498L9.709,22.497L19.773,19.142C20.297,18.967 20.863,19.251 21.038,19.774C21.213,20.298 20.929,20.865 20.406,21.039C20.406,21.039 10.342,24.394 10.347,24.392C9.966,24.522 9.556,24.542 9.164,24.451C8.772,24.359 8.413,24.16 8.129,23.875C7.844,23.591 7.645,23.232 7.553,22.84C7.462,22.448 7.482,22.038 7.61,21.662L10.966,11.598Z" style="fill:rgb(34,34,34);"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M30,11L30,25C30,25.796 29.684,26.559 29.121,27.121C28.559,27.684 27.796,28 27,28L5,28C4.204,28 3.441,27.684 2.879,27.121C2.316,26.559 2,25.796 2,25L2,7C2,6.204 2.316,5.441 2.879,4.879C3.441,4.316 4.204,4 5,4L10,4C10.466,4 10.925,4.108 11.342,4.317C11.758,4.525 12.121,4.827 12.4,5.2L14.5,8L27,8C27.796,8 28.559,8.316 29.121,8.879C29.684,9.441 30,10.204 30,11ZM28,11C28,10.735 27.895,10.48 27.707,10.293C27.52,10.105 27.265,10 27,10L14,10C13.685,10 13.389,9.852 13.2,9.6L10.8,6.4C10.707,6.276 10.586,6.175 10.447,6.106C10.308,6.036 10.155,6 10,6L5,6C4.735,6 4.48,6.105 4.293,6.293C4.105,6.48 4,6.735 4,7L4,25C4,25.265 4.105,25.52 4.293,25.707C4.48,25.895 4.735,26 5,26L27,26C27.265,26 27.52,25.895 27.707,25.707C27.895,25.52 28,25.265 28,25L28,11Z" style="fill:rgb(52,64,84);"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M 3.654,1.059 C 3.292,1.125 3.12,1.181 2.82,1.331 2.137,1.672 1.637,2.181 1.304,2.878 0.998,3.516 1.02,2.804 1.02,12 c 0,7.75 0.004,8.237 0.071,8.524 0.27,1.148 1.237,2.115 2.385,2.385 0.287,0.067 0.774,0.071 8.524,0.071 7.75,0 8.237,-0.004 8.524,-0.071 1.148,-0.27 2.115,-1.237 2.385,-2.385 C 22.976,20.237 22.98,19.75 22.98,12 22.98,4.25 22.976,3.763 22.909,3.476 22.646,2.357 21.747,1.433 20.606,1.107 L 20.3,1.02 12.12,1.013 C 5.545,1.008 3.884,1.017 3.654,1.059 M 15.947118,12 v 9 H 9.162 C 4.05,21 4.001,20.999 3.783,20.918 3.528,20.822 3.251,20.572 3.113,20.315 L 3.02,20.14 3.01,12.086 C 3.003,6.68 3.013,3.981 3.04,3.879 3.131,3.543 3.524,3.139 3.854,3.044 3.927,3.023 6.174,3.006 9.15,3.004 L 15.947118,3 v 9 M 20.22,3.083 c 0.298,0.112 0.585,0.399 0.697,0.697 L 21,4.003 V 12 19.997 L 20.917,20.22 C 20.805,20.518 20.518,20.805 20.22,20.917 20.006,20.997 19.72061,21 17.95461,21 h -0.0075 V 12 3 h 0.0075 c 1.766,0 2.05139,0.003 2.26539,0.083 m -9.72,4.69 c -0.294,0.143 -3.781,3.591 -3.878,3.834 -0.091,0.227 -0.086,0.587 0.01,0.803 0.053,0.116 0.613,0.732 1.779,1.954 1.913,2.004 1.889,1.985 2.369,1.946 0.279,-0.022 0.437,-0.093 0.622,-0.278 0.257,-0.257 0.345,-0.635 0.24,-1.025 -0.049,-0.18 -0.178,-0.325 -1.957,-2.187 l -0.764,-0.8 1.396,-1.37 C 11.328,9.658 11.737,9.23 11.801,9.099 11.976,8.736 11.892,8.258 11.602,7.968 11.412,7.778 11.254,7.71 10.96,7.692 c -0.215,-0.014 -0.294,0 -0.46,0.081" stroke="none" fill-rule="evenodd" fill="black"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

72
src/aboutus/about_us.rs Normal file
View file

@ -0,0 +1,72 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
AboutUs = {{AboutUs}} {
flow: Overlay
width: Fill
height: Fill
<View> {
flow: Overlay,
width: Fill
height: Fill
padding: {left: 25, right: 25, bottom: 20},
<View>{
flow: Down,
spacing:10,
align: {
x: 0.5,
y: 0.5
},
label1 = <Label> {
draw_text: {
color: #f
},
text: r#"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent tristique condimentum tristique. Donec sapien arcu, molestie vitae neque pretium, ultrices luctus diam. Aenean a eros ac lectus sollicitudin eleifend non in tellus. Nullam sapien velit, sodales et tincidunt vestibulum, sollicitudin et purus. Praesent elementum risus rhoncus enim consectetur pulvinar. Quisque rutrum leo quis odio mattis blandit. Etiam sit amet nibh felis. Vivamus maximus hendrerit turpis, vitae efficitur risus faucibus in. Vestibulum lorem dui, consectetur consectetur magna nec, hendrerit bibendum magna. Mauris faucibus rhoncus turpis luctus porta. Aenean interdum auctor sapien ac hendrerit.
Aliquam erat volutpat. Praesent velit felis, iaculis at interdum sed, pellentesque nec tortor. Nulla mauris augue, sollicitudin non nisi ac, consequat dapibus lorem. Maecenas mollis, nulla id tincidunt finibus, neque enim ultricies libero, vel accumsan metus libero vel mauris. Vivamus et suscipit nisl, vel lacinia massa. Sed et bibendum lectus, nec pellentesque tortor. Cras non est ut eros venenatis volutpat quis quis risus. Suspendisse convallis vestibulum orci. Etiam sit amet nisl eleifend, semper nibh sit amet, tincidunt leo. Sed ut tristique nunc. Nulla dictum hendrerit augue.
Vivamus ac porttitor sem. In auctor posuere velit ac molestie. Suspendisse ornare ex quis eros porttitor tincidunt. Praesent tincidunt purus tellus, vel malesuada dui condimentum at. Morbi pellentesque, velit euismod tristique rhoncus, metus mi tincidunt lacus, at faucibus tortor nunc ut nibh. Etiam efficitur est diam, ut commodo enim bibendum at. Suspendisse accumsan gravida nisi, sit amet sodales lectus maximus eu."#,
width: 200.0,
}
}
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct AboutUs {
#[deref]
view: View,
}
impl Widget for AboutUs {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope);
self.widget_match_event(cx, event, scope);
// self.match_event(cx, event);
// self.view.handle_event(cx, event, &mut Scope::empty());
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
// DrawStep::done()
self.view.draw_walk(cx, scope, walk)
}
}
impl WidgetMatchEvent for AboutUs {
fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions, _scope: &mut Scope) {
// if self.view.button(id!(button1)).clicked(&actions) {
// log!("Press button {}", self.counter);
// self.counter += 1;
// let label = self.view.label(id!(label1));
// label.set_text_and_redraw(cx, &format!("Counter: {}", self.counter));
// }
}
}

7
src/aboutus/mod.rs Normal file
View file

@ -0,0 +1,7 @@
use makepad_widgets::Cx;
pub mod about_us;
pub fn live_design(cx: &mut Cx) {
about_us::live_design(cx);
}

View file

@ -1,22 +1,14 @@
use crate::editor::fish_doc::*;
use crate::{data::state::State, home::editor::fish_doc::*};
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import crate::editor::fish_patch_editor::*;
import crate::editor::fish_block_editor::*;
import crate::app_web::AppWebUI;
// import crate::homescreen::BigFishHomeScreen;
import crate::editor::fish_theme::*;
// import crate::editor::fish_connection_widget::*;
import crate::editor::fish_selector_widget::*;
// import crate::lua_console::*;
import crate::app_ui::AppUI;
App = {{App}} {
ui: <Window> {
show_bg: true
width: Fill,
height: Fill,
@ -46,7 +38,18 @@ live_design! {
line = Line,
}
body = <AppWebUI>{}
window: {inner_size: vec2(800, 600)},
body = {
flow: Overlay
width: Fill,
height: Fill,
root = <View> {
width: Fill,
height: Fill,
app_ui = <AppUI>{}
}
}
}
}
}
@ -57,25 +60,96 @@ app_main!(App);
pub struct App {
#[live]
ui: WidgetRef,
#[rust]
counter: usize,
#[rust]
state: State,
// #[rust]
// document: FishDoc,
}
impl LiveRegister for App {
fn live_register(cx: &mut Cx) {
crate::makepad_widgets::live_design(cx);
crate::editor::live_design(cx);
// crate::editor::live_design(cx);
crate::app_ui::live_design(cx);
crate::app_mobile::live_design(cx);
crate::app_web::live_design(cx);
crate::home::live_design(cx);
crate::aboutus::live_design(cx);
crate::shared::live_design(cx);
}
}
impl MatchEvent for App {
fn handle_startup(&mut self, _cx: &mut Cx) {}
fn handle_startup(&mut self, cx: &mut Cx) {
let mobile_screen = self.ui.view(id!(mobile));
let web_screen = self.ui.view(id!(web));
if self.state.screen_width < 960_f64 {
log!("SCREEN_WIDTH ===> {}", self.state.screen_width);
web_screen.set_visible(false);
mobile_screen.set_visible_and_redraw(cx, true);
// web_screen.draw_all(cx, &mut Scope::empty());
} else if self.state.screen_width > 960_f64 {
mobile_screen.set_visible(false);
web_screen.set_visible_and_redraw(cx, true);
// web_screen.draw_all(cx, &mut Scope::empty());
} else {
log!("SCREEN_WIDTH ===> {}", self.state.screen_width);
}
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {}
self.state.document = FishDoc::create_test_doc();
}
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
// fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
if self.ui.button(id!(button1)).clicked(&actions) {
self.counter += 1;
let label = self.ui.label(id!(label1));
// label.set_text_and_redraw(cx, &format!("Counter: {}", self.counter));
}
if self.ui.button(id!(undobutton)).clicked(&actions) {
let _ = self.state.document.undo().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
if self.ui.button(id!(redobutton)).clicked(&actions) {
let _ = self.state.document.redo().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
if self.ui.button(id!(addblockbutton)).clicked(&actions) {
let _ = self.state.document.add_block().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
for action in actions {
if let WindowAction::WindowGeomChange(ce) = action.as_widget_action().cast() {
self.state.screen_width = ce.new_geom.inner_size.x * ce.new_geom.dpi_factor;
let mobile_screen = self.ui.view(id!(mobile));
let web_screen = self.ui.view(id!(web));
if self.state.screen_width < 960_f64 {
web_screen.set_visible(false);
mobile_screen.set_visible_and_redraw(cx, true);
} else if self.state.screen_width > 960_f64 {
mobile_screen.set_visible(false);
web_screen.set_visible_and_redraw(cx, true);
} else {
log!("ELSE_SCREEN_WIDTH ===> {}", self.state.screen_width);
}
}
}
}
}
impl AppMain for App {
// fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
// self.match_event(cx, event);
// self.ui.handle_event(cx, event, &mut Scope::empty());
// }
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
self.ui
.handle_event(cx, event, &mut Scope::with_data(&mut self.state.document));
}
}

29
src/app_mobile.rs Normal file
View file

@ -0,0 +1,29 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
import crate::shared::widgets::*;
import crate::home::home_screen::HomeScreen;
import crate::home::app_menu::AppMenu;
// FillerY = <View> {width: Fill}
AppMobileUI = <ScrollXYView>{
width: Fill,
height: Fill,
// padding: {top: 50, bottom: 48 }
show_bg: false,
flow: Down,
spacing:10,
align: {
x: 0.5,
y: 0.5
},
<HomeScreen>{
app_menu = <AppMenu> {}
}
}
}

26
src/app_ui.rs Normal file
View file

@ -0,0 +1,26 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import crate::shared::styles::*;
import crate::app_web::AppWebUI;
import crate::app_mobile::AppMobileUI;
// AppUI = {{AppUI}} {
AppUI = <View> {
width: Fill,
height: Fill,
align: {x: 0.5},
padding: {top: 0, bottom: 0 }
// debug: A
<View> {
width: Fill,
height: Fill,
mobile = <AppMobileUI>{}
web = <AppWebUI>{}
}
}
}

View file

@ -1,87 +1,124 @@
use makepad_widgets::*;
use crate::editor::fish_doc::FishDoc;
// use crate::data::state::State;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import crate::editor::fish_patch_editor::*;
import crate::editor::fish_block_editor::*;
import crate::editor::fish_theme::*;
import crate::editor::fish_connection_widget::*;
import crate::editor::fish_selector_widget::*;
AppWebUI = {{AppWebUI}} {
<View>{
import crate::shared::styles::*;
import crate::home::home_screen::HomeScreen;
import crate::aboutus::about_us::AboutUs;
import crate::shared::widgets::NavbarMenuButton;
ICON_DISCOVER = dep("crate://self/resources/icons/discover.svg")
ICON_CHAT = dep("crate://self/resources/icons/chat.svg")
ICON_MY_MODELS = dep("crate://self/resources/icons/my_models.svg")
AppWebUI = <ScrollXYView>{
width: Fill,
height: Fill,
align: {x: 0.5},
flow: Down,
patcheditorscreen = <View>{
flow: Down
<View>
{
flow: Right
height: Fit;
undobutton = <Button>{text:"Undo"}
redobutton = <Button>{text:"Redo"}
addblockbutton = <Button>{text:"New Block"}
padding: {top: 0, bottom: 0 }
// debug: A
navbar_menu = <RoundedView> {
width: Fill,
height: Fit,
flow: Right, spacing: 20.0,
padding: { top: 0 }
align: {x: 0.5, y: 0.0},
show_bg: true,
draw_bg: {
color: (SIDEBAR_BG_COLOR),
instance radius: 0.0,
border_color: #EAECF0,
border_width: 1.2,
}
home_screen_tab = <NavbarMenuButton> {
animator: {selected = {default: on}}
text: "Home",
draw_icon: {
svg_file: (ICON_DISCOVER),
}
}
aboutus_screen_tab = <NavbarMenuButton> {
text: "About Us",
draw_icon: {
svg_file: (ICON_MY_MODELS),
}
}
}
patchedit = <FishPatchEditor>{}
}
application_pages = <View> {
margin: 0.0,
padding: 0.0,
flow: Overlay,
width: Fill,
height: Fill,
// debug: A
home_screen_frame = <HomeScreen> {align: {x: 0.5, y: 0.5}, visible: true}
aboutus_screen_frame = <AboutUs> {visible: false}
}
}
}
// }
#[derive(Live, Widget)]
pub struct AppWebUI {
#[deref]
ui: Window,
#[rust]
counter: usize,
#[rust]
document: FishDoc,
}
// #[derive(Live, Widget)]
// pub struct AppWebUI {
// #[deref]
// ui: Window,
// #[rust]
// counter: usize,
// #[rust]
// document: FishDoc,
// }
impl LiveHook for AppWebUI {
fn after_new_from_doc(&mut self, _cx: &mut Cx) {
self.document = FishDoc::create_test_doc();
println!("after_new_from_doc(): starting some kind of a loop");
}
}
// impl LiveHook for AppWebUI {
// fn after_new_from_doc(&mut self, _cx: &mut Cx) {
// self.document = FishDoc::create_test_doc();
// println!("after_new_from_doc(): starting some kind of a loop");
// }
// }
impl Widget for AppWebUI {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.ui
.handle_event(cx, event, &mut Scope::with_data(&mut self.document));
self.widget_match_event(cx, event, scope);
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
let editor_screen = self.ui.view(id!(patcheditorscreen));
while let Some(_next) = self.ui.draw(cx, scope).step() {
editor_screen.draw_all(cx, scope);
}
DrawStep::done()
}
}
impl WidgetMatchEvent for AppWebUI {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
if self.ui.button(id!(button1)).clicked(&actions) {
self.counter += 1;
let label = self.ui.label(id!(label1));
label.set_text_and_redraw(cx, &format!("Counter: {}", self.counter));
}
// impl Widget for AppWebUI {
// fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
// self.ui
// .handle_event(cx, event, &mut Scope::with_data(&mut self.document));
// self.widget_match_event(cx, event, scope);
// }
// fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
// let editor_screen = self.ui.view(id!(patcheditorscreen));
// while let Some(_next) = self.ui.draw(cx, scope).step() {
// editor_screen.draw_all(cx, scope);
// }
// DrawStep::done()
// }
// }
// impl WidgetMatchEvent for AppWebUI {
// fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
// if self.ui.button(id!(button1)).clicked(&actions) {
// self.counter += 1;
// let label = self.ui.label(id!(label1));
// label.set_text_and_redraw(cx, &format!("Counter: {}", self.counter));
// }
if self.ui.button(id!(undobutton)).clicked(&actions) {
let _ = self.document.undo().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
// if self.ui.button(id!(undobutton)).clicked(&actions) {
// let _ = self.document.undo().is_ok();
// self.ui.widget(id!(patchedit)).redraw(cx);
// }
if self.ui.button(id!(redobutton)).clicked(&actions) {
let _ = self.document.redo().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
if self.ui.button(id!(addblockbutton)).clicked(&actions) {
let _ = self.document.add_block().is_ok();
self.ui.widget(id!(patchedit)).redraw(cx);
}
}
}
// if self.ui.button(id!(redobutton)).clicked(&actions) {
// let _ = self.document.redo().is_ok();
// self.ui.widget(id!(patchedit)).redraw(cx);
// }
// if self.ui.button(id!(addblockbutton)).clicked(&actions) {
// let _ = self.document.add_block().is_ok();
// self.ui.widget(id!(patchedit)).redraw(cx);
// }
// }
// }

1
src/data/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod state;

32
src/data/state.rs Normal file
View file

@ -0,0 +1,32 @@
use std::{
fs,
path::{Path, PathBuf},
};
// use crate::editor::fish_doc::FishDoc;
use crate::home::editor::fish_doc::FishDoc;
#[derive(Default)]
pub struct State {
pub images: Vec<PathBuf>,
pub screen_width: f64,
pub document: FishDoc,
}
impl State {
pub fn load_images(&mut self, path: &Path) {
self.images = fs::read_dir(path)
.expect("unable to read directory")
.map(|entry| entry.expect("unable to read entry").path())
.filter(|path| {
path.extension()
.map_or(false, |ext| ["png", "jpg"].iter().any(|e| *e == ext))
})
.collect::<Vec<_>>();
}
pub fn root(&self) -> Option<&Path> {
self.images.first().map(|p| p.parent().unwrap())
}
}

View file

@ -1,29 +0,0 @@
pub mod block_connector_button;
pub mod block_delete_button;
pub mod block_header_button;
pub mod fish_block;
pub mod fish_block_editor;
pub mod fish_block_template;
pub mod fish_connection;
pub mod fish_connection_widget;
pub mod fish_doc;
pub mod fish_param_storage;
pub mod fish_patch;
pub mod fish_patch_editor;
pub mod fish_ports;
pub mod fish_preset;
pub mod fish_selector_widget;
pub mod fish_theme;
use makepad_widgets::Cx;
pub fn live_design(cx: &mut Cx) {
crate::editor::fish_patch_editor::live_design(cx);
crate::editor::block_header_button::live_design(cx);
crate::editor::block_delete_button::live_design(cx);
crate::editor::block_connector_button::live_design(cx);
crate::editor::fish_block_editor::live_design(cx);
crate::editor::fish_connection_widget::live_design(cx);
crate::editor::fish_selector_widget::live_design(cx);
crate::editor::fish_theme::live_design(cx);
}

113
src/home/app_menu.rs Normal file
View file

@ -0,0 +1,113 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
import crate::shared::widgets::*;
import makepad_draw::shader::std::*;
ICON_CLOSE_PANEL = dep("crate://self/resources/icons/close_right_panel.svg")
ICON_OPEN_PANEL = dep("crate://self/resources/icons/open_right_panel.svg")
AppMenu = {{AppMenu}} <MoxinTogglePanel> {
open_content = {
<View> {
width: Fill
height: Fill
padding: {top: 70, left: 25.0, right: 25.0}
spacing: 35
flow: Down
show_bg: true
draw_bg: {
color: #F2F4F7
}
label = <Label> {
draw_text: {
text_style: <BOLD_FONT>{font_size: 12}
color: #667085
}
text: "Salamu"
}
}
}
persistent_content = {
default = {
before = {
width: Fill
}
open = {
draw_icon: {
svg_file: (ICON_OPEN_PANEL),
}
}
close = {
draw_icon: {
svg_file: (ICON_CLOSE_PANEL),
}
}
}
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct AppMenu {
#[deref]
deref: TogglePanel,
// #[rust]
// current_chat_id: Option<ChatID>,
}
impl Widget for AppMenu {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.deref.handle_event(cx, event, scope);
self.widget_match_event(cx, event, scope);
// TODO This is a hack to redraw the chat history and reflect the
// name change on the first message sent.
// Maybe we should send and receive an action here?
if let Event::Signal = event {
self.redraw(cx);
}
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
// self.deref.draw_walk(cx, scope, walk)
self.deref.draw_walk(cx, scope, walk)
// DrawStep::done()
}
}
impl WidgetMatchEvent for AppMenu {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
let close = self.button(id!(close_panel_button));
let open = self.button(id!(open_panel_button));
if close.clicked(&actions) {
close.set_visible(false);
open.set_visible(true);
self.set_open(cx, false);
}
if open.clicked(&actions) {
open.set_visible(false);
close.set_visible(true);
self.set_open(cx, true);
}
// if self.button(id!(close_panel_button)).clicked(&actions) {
// self.button(id!(close_panel_button)).set_visible(false);
// self.button(id!(open_panel_button)).set_visible(true);
// self.deref.set_open(cx, false);
// }
// if self.button(id!(open_panel_button)).clicked(&actions) {
// self.button(id!(open_panel_button)).set_visible(false);
// self.button(id!(close_panel_button)).set_visible(true);
// self.deref.set_open(cx, true);
// }
}
}

View file

@ -1,6 +1,6 @@
use crate::editor::fish_block_template::*;
use crate::editor::fish_param_storage::*;
use crate::editor::fish_ports::*;
use crate::home::editor::fish_block_template::*;
use crate::home::editor::fish_param_storage::*;
use crate::home::editor::fish_ports::*;
use crate::makepad_micro_serde::*;
use crate::makepad_platform::*;
use makepad_widgets::DVec2;

View file

@ -4,9 +4,9 @@ live_design! {
import makepad_widgets::theme_desktop_dark::*;
import makepad_widgets::base::*;
import makepad_draw::shader::std::*;
import crate::editor::fish_theme::*;
import crate::editor::block_header_button::*;
import crate::editor::block_delete_button::*;
import crate::home::editor::fish_theme::*;
import crate::home::editor::block_header_button::*;
import crate::home::editor::block_delete_button::*;
FishBlockEditor = <View>
{

View file

@ -1,6 +1,6 @@
use crate::editor::fish_block::*;
use crate::editor::fish_param_storage::*;
use crate::editor::fish_ports::*;
use crate::home::editor::fish_block::*;
use crate::home::editor::fish_param_storage::*;
use crate::home::editor::fish_ports::*;
use crate::makepad_micro_serde::*;
#[derive(Clone, Debug, SerRon, DeRon, Default)]

View file

@ -1,5 +1,5 @@
use crate::editor::fish_block_template::FishBlockLibrary;
use crate::editor::fish_patch::*;
use crate::home::editor::fish_block_template::FishBlockLibrary;
use crate::home::editor::fish_patch::*;
use crate::makepad_micro_serde::*;
use std::fs;

View file

@ -1,7 +1,7 @@
use crate::editor::fish_block::*;
use crate::editor::fish_block_template::*;
use crate::editor::fish_connection::*;
use crate::editor::fish_preset::*;
use crate::home::editor::fish_block::*;
use crate::home::editor::fish_block_template::*;
use crate::home::editor::fish_connection::*;
use crate::home::editor::fish_preset::*;
use crate::makepad_micro_serde::*;
use makepad_widgets::*;

View file

@ -1,5 +1,5 @@
use crate::{
editor::{
home::editor::{
block_delete_button::BlockDeleteButtonAction, block_header_button::BlockHeaderButtonAction,
fish_block_template::FishBlockCategory, fish_doc::FishDoc, fish_patch::*,
},
@ -10,11 +10,11 @@ use crate::{
live_design! {
import makepad_widgets::theme_desktop_dark::*;
import makepad_widgets::base::*;
import crate::editor::fish_block_editor::*;
import crate::editor::fish_theme::*;
import crate::editor::fish_connection_widget::*;
import crate::editor::fish_selector_widget::*;
import crate::editor::block_connector_button::*;
import crate::home::editor::fish_block_editor::*;
import crate::home::editor::fish_theme::*;
import crate::home::editor::fish_connection_widget::*;
import crate::home::editor::fish_selector_widget::*;
import crate::home::editor::block_connector_button::*;
FishPatchEditor = {{FishPatchEditor}} {
width: Fill,

View file

@ -1,4 +1,4 @@
use crate::editor::fish_param_storage::*;
use crate::home::editor::fish_param_storage::*;
use crate::makepad_micro_serde::*;

29
src/home/editor/mod.rs Normal file
View file

@ -0,0 +1,29 @@
pub mod block_connector_button;
pub mod block_delete_button;
pub mod block_header_button;
pub mod fish_block;
pub mod fish_block_editor;
pub mod fish_block_template;
pub mod fish_connection;
pub mod fish_connection_widget;
pub mod fish_doc;
pub mod fish_param_storage;
pub mod fish_patch;
pub mod fish_patch_editor;
pub mod fish_ports;
pub mod fish_preset;
pub mod fish_selector_widget;
pub mod fish_theme;
use makepad_widgets::Cx;
pub fn live_design(cx: &mut Cx) {
crate::home::editor::fish_patch_editor::live_design(cx);
crate::home::editor::block_header_button::live_design(cx);
crate::home::editor::block_delete_button::live_design(cx);
crate::home::editor::block_connector_button::live_design(cx);
crate::home::editor::fish_block_editor::live_design(cx);
crate::home::editor::fish_connection_widget::live_design(cx);
crate::home::editor::fish_selector_widget::live_design(cx);
crate::home::editor::fish_theme::live_design(cx);
}

128
src/home/home_panel.rs Normal file
View file

@ -0,0 +1,128 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
import crate::home::editor::fish_patch_editor::*;
HomePanel = {{HomePanel}} {
flow: Overlay
width: Fill
height: Fill
<View> {
flow: Overlay,
width: Fill
height: Fill
padding: {left: 25, right: 25, bottom: 20},
<View>{
flow: Down,
spacing:10,
align: {
x: 0.5,
y: 0.0
},
<View>{
flow: Down,
patcheditorscreen = <View>{
flow: Down
<View>
{
flow: Right
height: Fit;
undobutton = <Button>{text:"Undo"}
redobutton = <Button>{text:"Redo"}
addblockbutton = <Button>{text:"New Block"}
}
patchedit = <FishPatchEditor>{}
}
}
button1 = <Button> {
text: "Hello world "
draw_text:{color:#f00}
}
input1 = <TextInput> {
width: 100, height: 30
text: "Click to count "
}
<View>{
scroll_bars: <ScrollBars> {show_scroll_x: false, show_scroll_y: true}
align: {
x: 0.5,
// y: 0.5
},
label1 = <Label> {
draw_text: {
color: #f
},
text: r#"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent tristique condimentum tristique. Donec sapien arcu, molestie vitae neque pretium, ultrices luctus diam. Aenean a eros ac lectus sollicitudin eleifend non in tellus. Nullam sapien velit, sodales et tincidunt vestibulum, sollicitudin et purus. Praesent elementum risus rhoncus enim consectetur pulvinar. Quisque rutrum leo quis odio mattis blandit. Etiam sit amet nibh felis. Vivamus maximus hendrerit turpis, vitae efficitur risus faucibus in. Vestibulum lorem dui, consectetur consectetur magna nec, hendrerit bibendum magna. Mauris faucibus rhoncus turpis luctus porta. Aenean interdum auctor sapien ac hendrerit.
Aliquam erat volutpat. Praesent velit felis, iaculis at interdum sed, pellentesque nec tortor. Nulla mauris augue, sollicitudin non nisi ac, consequat dapibus lorem. Maecenas mollis, nulla id tincidunt finibus, neque enim ultricies libero, vel accumsan metus libero vel mauris. Vivamus et suscipit nisl, vel lacinia massa. Sed et bibendum lectus, nec pellentesque tortor. Cras non est ut eros venenatis volutpat quis quis risus. Suspendisse convallis vestibulum orci. Etiam sit amet nisl eleifend, semper nibh sit amet, tincidunt leo. Sed ut tristique nunc. Nulla dictum hendrerit augue.
Vivamus ac porttitor sem. In auctor posuere velit ac molestie. Suspendisse ornare ex quis eros porttitor tincidunt. Praesent tincidunt purus tellus, vel malesuada dui condimentum at. Morbi pellentesque, velit euismod tristique rhoncus, metus mi tincidunt lacus, at faucibus tortor nunc ut nibh. Etiam efficitur est diam, ut commodo enim bibendum at. Suspendisse accumsan gravida nisi, sit amet sodales lectus maximus eu."#,
// width: 400.0,
width: Fill,
}
}
}
<View>{
footer = <Label> {
margin: {bottom: (SSPACING_1)}
draw_text: {
text_style: <H2_TEXT_BOLD> {},
color: #000
}
text: "Here"
}
}
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct HomePanel {
#[deref]
view: View,
// #[rust]
// state: State,
// #[rust]
// portal_list_end_reached: bool,
#[rust]
counter: usize,
}
impl Widget for HomePanel {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope);
self.widget_match_event(cx, event, scope);
// self.match_event(cx, event);
// self.view.handle_event(cx, event, &mut Scope::empty());
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
// DrawStep::done()
self.view.draw_walk(cx, scope, walk)
}
}
impl WidgetMatchEvent for HomePanel {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
if self.view.button(id!(button1)).clicked(&actions) {
log!("Press button {}", self.counter);
self.counter += 1;
let label = self.view.label(id!(label1));
label.set_text_and_redraw(cx, &format!("Counter: {}", self.counter));
}
}
}
// impl WidgetMatchEvent for ChatPanel {
// fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {}
// }

57
src/home/home_screen.rs Normal file
View file

@ -0,0 +1,57 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
import crate::home::home_panel::HomePanel;
HomeScreen = {{HomeScreen}} {
width: Fill,
height: Fill,
spacing: 10.0,
<View> {
debug: A
<View> {
width: Fill,
height: Fill,
align: {x: 0.5},
padding: {top: 0, bottom: 0 }
// debug: A
home_panel = <HomePanel> {}
}
<View> {
width: Fit,
height: Fill,
// debug: A
app_menu = <View>{}
}
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct HomeScreen {
#[deref]
view: View,
}
impl Widget for HomeScreen {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
// TODO This check is actually copied from Makepad view.rs file
// It's not clear why it's needed here, but without this line
// the "View all files" link in Discover section does not work after visiting the chat screen
if self.visible || !event.requires_visibility() {
self.view.handle_event(cx, event, scope);
}
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
self.view.draw_walk(cx, scope, walk)
}
}

13
src/home/mod.rs Normal file
View file

@ -0,0 +1,13 @@
pub mod app_menu;
pub mod editor;
pub mod home_panel;
pub mod home_screen;
use makepad_widgets::Cx;
pub fn live_design(cx: &mut Cx) {
app_menu::live_design(cx);
home_screen::live_design(cx);
home_panel::live_design(cx);
editor::live_design(cx);
}

View file

@ -3,6 +3,11 @@ pub use makepad_widgets::makepad_draw;
pub use makepad_widgets::makepad_live_id;
pub use makepad_widgets::makepad_micro_serde;
pub use makepad_widgets::makepad_platform;
pub mod aboutus;
pub mod app;
pub mod app_mobile;
pub mod app_ui;
pub mod app_web;
pub mod editor;
pub mod data;
pub mod home;
pub mod shared;

16
src/shared/mod.rs Normal file
View file

@ -0,0 +1,16 @@
use makepad_widgets::Cx;
pub mod styles;
pub mod widgets;
pub fn live_design(cx: &mut Cx) {
styles::live_design(cx);
// resource_imports::live_design(cx);
widgets::live_design(cx);
// portal::live_design(cx);
// modal::live_design(cx);
// external_link::live_design(cx);
// download_notification_popup::live_design(cx);
// tooltip::live_design(cx);
// desktop_buttons::live_design(cx);
}

48
src/shared/styles.rs Normal file
View file

@ -0,0 +1,48 @@
use makepad_widgets::*;
live_design! {
const MODEL_LINK_FONT_COLOR = #x155EEF
SIDEBAR_BG_COLOR = #F8F8F8
REGULAR_FONT = {
font_size: (12),
font: {path: dep("crate://makepad-widgets/resources/GoNotoKurrent-Regular.ttf")}
}
BOLD_FONT = {
font_size: (12),
font: {path: dep("crate://makepad-widgets/resources/GoNotoKurrent-Bold.ttf")}
}
APP_NAME = {
font_size: (12),
}
FONT_SIZE_H2 = 9.5
TEXT_BIG = 12.0
TEXT_MONO = {
font_size: 10.0,
font: {path: dep("crate://makepad-widgets/resources/LiberationMono-Regular.ttf")}
}
H2_TEXT_BOLD = {
font_size: (FONT_SIZE_H2),
font: {path: dep("crate://makepad-widgets/resources/IBMPlexSans-SemiBold.ttf")}
}
// COLOR_DOWN_2 = #x00000022
COLOR_DOWN_2 = #xFFB084
COLOR_DOWN_6 = #x000000CC
COLOR_OVERLAY_BG = #x4685ff
COLOR_HEADER_BG = #x4685ff// xFFB084 x4685ff
SIDEBAR_BG_COLOR = #F8F8F8
SSPACING_0 = 0.0
SSPACING_1 = 4.0
DROPDOWN_WIDTH = 130.0
SSPACING_2 = (SSPACING_1 * 2)
SPACING_0 = {top: (SSPACING_0), right: (SSPACING_0), bottom: (SSPACING_0), left: (SSPACING_0)}
SPACING_2 = {top: (SSPACING_2), right: (SSPACING_2), bottom: (SSPACING_2), left: (SSPACING_2)}
// ICON_CLOSE_PANEL = dep("crate://self/resources/icons/close_left_panel.svg")
// ICON_OPEN_PANEL = dep("crate://self/resources/icons/open_left_panel.svg")
}

303
src/shared/widgets.rs Normal file
View file

@ -0,0 +1,303 @@
use makepad_widgets::*;
live_design! {
import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*;
import makepad_draw::shader::std::*;
import crate::shared::styles::*;
SIDEBAR_FONT_COLOR = #344054
SIDEBAR_FONT_COLOR_HOVER = #344054
SIDEBAR_FONT_COLOR_SELECTED = #127487
SIDEBAR_BG_COLOR_HOVER = #E2F1F199
SIDEBAR_BG_COLOR_SELECTED = #E2F1F199
SidebarMenuButton = <RadioButton> {
width: 80,
height: 70,
padding: 0, margin: 0,
flow: Down, spacing: 8.0, align: {x: 0.5, y: 0.5}
icon_walk: {margin: 0, width: 30, height: 30}
label_walk: {margin: 0}
draw_radio: {
radio_type: Tab,
instance border_width: 0.0
instance border_color: #0000
instance inset: vec4(0.0, 0.0, 0.0, 0.0)
instance radius: 2.5
fn get_color(self) -> vec4 {
return mix(
mix(
(SIDEBAR_BG_COLOR),
(SIDEBAR_BG_COLOR_HOVER),
self.hover
),
(SIDEBAR_BG_COLOR_SELECTED),
self.selected
)
}
fn get_border_color(self) -> vec4 {
return self.border_color
}
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
sdf.box(
self.inset.x + self.border_width,
self.inset.y + self.border_width,
self.rect_size.x - (self.inset.x + self.inset.z + self.border_width * 2.0),
self.rect_size.y - (self.inset.y + self.inset.w + self.border_width * 2.0),
max(1.0, self.radius)
)
sdf.fill_keep(self.get_color())
if self.border_width > 0.0 {
sdf.stroke(self.get_border_color(), self.border_width)
}
return sdf.result;
}
}
draw_text: {
color_unselected: (SIDEBAR_FONT_COLOR)
color_unselected_hover: (SIDEBAR_FONT_COLOR_HOVER)
color_selected: (SIDEBAR_FONT_COLOR_SELECTED)
fn get_color(self) -> vec4 {
return mix(
mix(
self.color_unselected,
self.color_unselected_hover,
self.hover
),
self.color_selected,
self.selected
)
}
}
draw_icon: {
instance color_unselected: (SIDEBAR_FONT_COLOR)
instance color_unselected_hover: (SIDEBAR_FONT_COLOR_HOVER)
instance color_selected: (SIDEBAR_FONT_COLOR_SELECTED)
fn get_color(self) -> vec4 {
return mix(
mix(
self.color_unselected,
self.color_unselected_hover,
self.hover
),
self.color_selected,
self.selected
)
}
}
}
NavbarMenuButton = <RadioButton> {
width: 80,
height: 70,
padding: 0, margin: 0,
flow: Down, spacing: 8.0, align: {x: 0.5, y: 0.5}
icon_walk: {margin: 0, width: 30, height: 30}
label_walk: {margin: 0}
draw_radio: {
radio_type: Tab,
instance border_width: 0.0
instance border_color: #0000
instance inset: vec4(0.0, 0.0, 0.0, 0.0)
instance radius: 2.5
fn get_color(self) -> vec4 {
return mix(
mix(
(SIDEBAR_BG_COLOR),
(SIDEBAR_BG_COLOR_HOVER),
self.hover
),
(SIDEBAR_BG_COLOR_SELECTED),
self.selected
)
}
fn get_border_color(self) -> vec4 {
return self.border_color
}
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
sdf.box(
self.inset.x + self.border_width,
self.inset.y + self.border_width,
self.rect_size.x - (self.inset.x + self.inset.z + self.border_width * 2.0),
self.rect_size.y - (self.inset.y + self.inset.w + self.border_width * 2.0),
max(1.0, self.radius)
)
sdf.fill_keep(self.get_color())
if self.border_width > 0.0 {
sdf.stroke(self.get_border_color(), self.border_width)
}
return sdf.result;
}
}
draw_text: {
color_unselected: (SIDEBAR_FONT_COLOR)
color_unselected_hover: (SIDEBAR_FONT_COLOR_HOVER)
color_selected: (SIDEBAR_FONT_COLOR_SELECTED)
fn get_color(self) -> vec4 {
return mix(
mix(
self.color_unselected,
self.color_unselected_hover,
self.hover
),
self.color_selected,
self.selected
)
}
}
draw_icon: {
instance color_unselected: (SIDEBAR_FONT_COLOR)
instance color_unselected_hover: (SIDEBAR_FONT_COLOR_HOVER)
instance color_selected: (SIDEBAR_FONT_COLOR_SELECTED)
fn get_color(self) -> vec4 {
return mix(
mix(
self.color_unselected,
self.color_unselected_hover,
self.hover
),
self.color_selected,
self.selected
)
}
}
}
MoxinButton = <Button> {
draw_bg: {
instance color: #0000
instance color_hover: #fff
instance border_width: 1.0
instance border_color: #0000
instance border_color_hover: #fff
instance radius: 2.5
fn get_color(self) -> vec4 {
return mix(self.color, mix(self.color, self.color_hover, 0.2), self.hover)
}
fn get_border_color(self) -> vec4 {
return mix(self.border_color, mix(self.border_color, self.border_color_hover, 0.2), self.hover)
}
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
sdf.box(
self.border_width,
self.border_width,
self.rect_size.x - (self.border_width * 2.0),
self.rect_size.y - (self.border_width * 2.0),
max(1.0, self.radius)
)
sdf.fill_keep(self.get_color())
if self.border_width > 0.0 {
sdf.stroke(self.get_border_color(), self.border_width)
}
return sdf.result;
}
}
draw_icon: {
instance color: #fff
instance color_hover: #000
uniform rotation_angle: 0.0,
fn get_color(self) -> vec4 {
return mix(self.color, mix(self.color, self.color_hover, 0.2), self.hover)
}
// Support rotation of the icon
fn clip_and_transform_vertex(self, rect_pos: vec2, rect_size: vec2) -> vec4 {
let clipped: vec2 = clamp(
self.geom_pos * rect_size + rect_pos,
self.draw_clip.xy,
self.draw_clip.zw
)
self.pos = (clipped - rect_pos) / rect_size
// Calculate the texture coordinates based on the rotation angle
let angle_rad = self.rotation_angle * 3.14159265359 / 180.0;
let cos_angle = cos(angle_rad);
let sin_angle = sin(angle_rad);
let rot_matrix = mat2(
cos_angle, -sin_angle,
sin_angle, cos_angle
);
self.tex_coord1 = mix(
self.icon_t1.xy,
self.icon_t2.xy,
(rot_matrix * (self.pos.xy - vec2(0.5))) + vec2(0.5)
);
return self.camera_projection * (self.camera_view * (self.view_transform * vec4(
clipped.x,
clipped.y,
self.draw_depth + self.draw_zbias,
1.
)))
}
}
icon_walk: {width: 14, height: 14}
draw_text: {
text_style: <REGULAR_FONT>{font_size: 9},
fn get_color(self) -> vec4 {
return self.color;
}
}
reset_hover_on_click: true
}
TogglePanelButton = <MoxinButton> {
width: Fit,
height: Fit,
icon_walk: {width: 20, height: 20},
draw_icon: {
fn get_color(self) -> vec4 {
return #475467;
}
}
}
MoxinTogglePanel = <TogglePanel> {
persistent_content = {
default = {
open = <TogglePanelButton> {
visible: false,
draw_icon: {
svg_file: (TOGGLE_PANEL_OPEN_ICON)
}
}
close = <TogglePanelButton> {
draw_icon: {
svg_file: (TOGGLE_PANEL_CLOSE_ICON)
}
}
}
}
}
}

56
vcf.rs Normal file
View file

@ -0,0 +1,56 @@
use std::fs::File;
use std::io::{self, Write};
fn main() -> io::Result<()> {
let contacts = vec![
("Dershi Vishram Versani", "0722410530", "neelbid@yahoo.com"),
("Solomon Njenga", "0727646358", "ranciengineerin@gmail.com"),
("Mutemi Ndonga", "0724686448", "mutemindonga@gmail.com"),
("ERICMUTUNE", "0710158374", "mestumerica@ghail.com"),
("SHREEKANT KERAI", "0731337014", "pscl@seyani.com"),
("Mangela Musyoka", "0722614616", "hidayacom@yahoo.com"),
("Rhoda rugendo", "0719382929", "huashieastafrica@gmail.com"),
("Kenneth Mwenda", "0723127076", "project31@burhaniengineers.com"),
("RAMESH VSIHRAM", "0722515390", "kenya@cementers.com"),
("WILLY KIPROTCH", "0705167161", "INFO@MILICONS.COM"),
("IVY NJOKI", "0726150870", "info@mwembeandmwembe.co.ke"),
("Erick Ouko", "0722290050", "Info@orionnebulaltd.co.ke"),
("GEORGE K MGURE", "0721438066", "ngare@seyanibrosk.com"),
("BRUCE N. GCIHMIU", "0715414407", "bgichimn@eaconcontracting.co.ke"),
("DANIELL KIABI", "0728776794", "dci@dinconkenya.com"),
("Laura Musavi", "0748410310/0714059407", "info@jinsing.net"),
("Eric Wanjau", "0722883949", "into@tulsi.co.ke"),
("Ramila Patel", "0722344844", "admin@nirmaholdings.com"),
("Vimal Venkay", "0712652679", "gadapali@gmail.com"),
("Jimmy Ji", "0724593434/0786732627", "kenyaoffice@cjic.cc"),
("Deng Tiqiang", "0724770581", "csceckenya@chinaconstruction.com"),
("Benson Onduso", "0759110330", "crjekenya@gmail.com,sunshinexinxinwu@gmail.com"),
("RITA NUNGARI", "0724100019", "RITANUNGARIE@GMALL.COM"),
("Manraj MATON", "0722866369", "manraj"),
("ZAKAYO EMONG'OCE", "0718881676", "info@cyt.co.ke"),
("JAMES ODEGI", "0726916060", "info@lbl.co.ke"),
("Martin Ogola", "0734000064", "info@epco.co.ke"),
("Thomas Njuguna", "0795711697", "info@2xkenya.com"),
("Suraj Vekaria", "0729268206", "info@parklaneconstruction.co.ke"),
("MWANIKI HELEN", "0717239007/0720793007", "info@arconworks.com"),
];
let mut file = File::create("contacts.vcf")?;
for (name, phone, email) in contacts {
writeln!(file, "BEGIN:VCARD")?;
writeln!(file, "VERSION:3.0")?;
writeln!(file, "FN:{}", name)?;
// Split the phone numbers by '/' and write them as separate TEL entries
for number in phone.split('/') {
writeln!(file, "TEL;TYPE=CELL:{}", number.trim())?;
}
writeln!(file, "EMAIL:{}", email)?;
writeln!(file, "END:VCARD")?;
}
println!("VCF file created successfully.");
Ok(())
}