changes to app_web.rs

This commit is contained in:
aOK 2024-08-20 16:41:31 +03:00
parent dc1efaeed6
commit 8d9de58378
15 changed files with 891 additions and 46 deletions

View file

@ -1,5 +1,7 @@
use makepad_widgets::*; use makepad_widgets::*;
use crate::data::state::State;
live_design! { live_design! {
import makepad_widgets::base::*; import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*; import makepad_widgets::theme_desktop_dark::*;
@ -32,6 +34,8 @@ app_main!(App);
pub struct App { pub struct App {
#[live] #[live]
ui: WidgetRef, ui: WidgetRef,
#[rust]
state: State,
} }
impl LiveRegister for App { impl LiveRegister for App {
@ -46,14 +50,20 @@ impl LiveRegister for App {
crate::shared::live_design(cx); crate::shared::live_design(cx);
} }
} }
impl MatchEvent for App { impl MatchEvent for App {
fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions) {} fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions) {}
} }
impl AppMain for App { impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) { fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.ui
.handle_event(cx, event, &mut Scope::with_data(&mut self.state));
self.match_event(cx, event); self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
} }
} }
// 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());
// }
// }

View file

@ -1,5 +1,9 @@
use std::path::Path;
use makepad_widgets::*; use makepad_widgets::*;
use crate::data::state::State;
live_design! { live_design! {
import makepad_widgets::base::*; import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*; import makepad_widgets::theme_desktop_dark::*;
@ -45,55 +49,74 @@ pub struct AppUI {
view: View, view: View,
#[rust] #[rust]
screen_width: f64, state: State,
// #[rust]
// screen_width: f64,
} }
impl LiveHook for AppUI { impl LiveHook for AppUI {
fn after_new_from_doc(&mut self, cx: &mut Cx) { fn after_new_from_doc(&mut self, cx: &mut Cx) {
let mobile_screen = self.view.view(id!(mobile)); let mobile_screen = self.view.view(id!(mobile));
let web_screen = self.view.view(id!(web)); let web_screen = self.view.view(id!(web));
if self.screen_width < 960_f64 { if self.state.screen_width < 960_f64 {
log!("SCREEN_WIDTH ===> {}", self.screen_width); log!("SCREEN_WIDTH ===> {}", self.state.screen_width);
web_screen.set_visible(false); web_screen.set_visible(false);
mobile_screen.set_visible_and_redraw(cx, true); mobile_screen.set_visible_and_redraw(cx, true);
// web_screen.draw_all(cx, &mut Scope::empty()); // web_screen.draw_all(cx, &mut Scope::empty());
} else if self.screen_width > 960_f64 { } else if self.state.screen_width > 960_f64 {
mobile_screen.set_visible(false); mobile_screen.set_visible(false);
web_screen.set_visible_and_redraw(cx, true); web_screen.set_visible_and_redraw(cx, true);
// web_screen.draw_all(cx, &mut Scope::empty()); // web_screen.draw_all(cx, &mut Scope::empty());
} else { } else {
log!("SCREEN_WIDTH ===> {}", self.screen_width); log!("SCREEN_WIDTH ===> {}", self.state.screen_width);
} }
// Image directory
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.expect("home not found");
self.state.load_images(&Path::new(&home).join("Downloads"));
} }
// fn handle_startup(&mut self, _cx: &mut Cx) {
// let home = std::env::var("HOME")
// .or_else(|_| std::env::var("USERPROFILE"))
// .expect("home not found");
// self.state.load_images(&Path::new(&home).join("Downloads"));
// }
} }
impl Widget for AppUI { impl Widget for AppUI {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) { fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope); self.view
.handle_event(cx, event, &mut Scope::with_data(&mut self.state));
// self.view.handle_event(cx, event, scope);
self.widget_match_event(cx, event, scope); self.widget_match_event(cx, event, scope);
} }
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
// DrawStep::done() // DrawStep::done()
// let state = scope.data.get::<State>().unwrap();
let mobile_screen = self.view.view(id!(mobile)); let mobile_screen = self.view.view(id!(mobile));
let web_screen = self.view.view(id!(web)); let web_screen = self.view.view(id!(web));
while let Some(_next) = self.view.draw(cx, &mut Scope::empty()).step() { while let Some(_next) = self.view.draw(cx, scope).step() {
// if let Some(mut mobile_screen) = mobile_screen.has_widget(&next).borrow_mut() {} // if let Some(mut mobile_screen) = mobile_screen.has_widget(&next).borrow_mut() {}
if self.screen_width == 0_f64 { if self.state.screen_width == 0_f64 {
continue; continue;
} }
if self.screen_width < 960_f64 { // if self.state.screen_width < 960_f64 {
if self.state.screen_width < 960_f64 {
web_screen.set_visible(false); web_screen.set_visible(false);
mobile_screen.set_visible_and_redraw(cx, true); mobile_screen.set_visible_and_redraw(cx, true);
mobile_screen.draw_all(cx, &mut Scope::empty()); mobile_screen.draw_all(cx, scope);
self.view.draw_walk(cx, scope, walk)?; self.view.draw_walk(cx, scope, walk)?;
} else if self.screen_width > 960_f64 { } else if self.state.screen_width > 960_f64 {
mobile_screen.set_visible(false); mobile_screen.set_visible(false);
web_screen.set_visible_and_redraw(cx, true); web_screen.set_visible_and_redraw(cx, true);
web_screen.draw_all(cx, &mut Scope::empty()); web_screen.draw_all(cx, scope);
self.view.draw_walk(cx, scope, walk)?; self.view.draw_walk(cx, scope, walk)?;
} else { } else {
log!("ESLE_SCREEN_WIDTH ===> {}", self.screen_width); log!("ESLE_SCREEN_WIDTH ===> {}", self.state.screen_width);
} }
} }
DrawStep::done() DrawStep::done()
@ -101,20 +124,21 @@ impl Widget for AppUI {
} }
impl WidgetMatchEvent for AppUI { impl WidgetMatchEvent for AppUI {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) { fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
let state = scope.data.get_mut::<State>().unwrap();
for action in actions { for action in actions {
if let WindowAction::WindowGeomChange(ce) = action.as_widget_action().cast() { if let WindowAction::WindowGeomChange(ce) = action.as_widget_action().cast() {
self.screen_width = ce.new_geom.inner_size.x * ce.new_geom.dpi_factor; state.screen_width = ce.new_geom.inner_size.x * ce.new_geom.dpi_factor;
let mobile_screen = self.view.view(id!(mobile)); let mobile_screen = self.view.view(id!(mobile));
let web_screen = self.view.view(id!(web)); let web_screen = self.view.view(id!(web));
if self.screen_width < 960_f64 { if state.screen_width < 960_f64 {
web_screen.set_visible(false); web_screen.set_visible(false);
mobile_screen.set_visible_and_redraw(cx, true); mobile_screen.set_visible_and_redraw(cx, true);
} else if self.screen_width > 960_f64 { } else if state.screen_width > 960_f64 {
mobile_screen.set_visible(false); mobile_screen.set_visible(false);
web_screen.set_visible_and_redraw(cx, true); web_screen.set_visible_and_redraw(cx, true);
} else { } else {
log!("ELSE_SCREEN_WIDTH ===> {}", self.screen_width); log!("ELSE_SCREEN_WIDTH ===> {}", state.screen_width);
} }
} }
} }

View file

@ -1,5 +1,7 @@
use makepad_widgets::*; use makepad_widgets::*;
use crate::data::state::State;
live_design! { live_design! {
import makepad_widgets::base::*; import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*; import makepad_widgets::theme_desktop_dark::*;
@ -52,32 +54,71 @@ live_design! {
margin: 0.0, margin: 0.0,
padding: 0.0, padding: 0.0,
flow: Down, flow: Down,
width: Fit, width: Fill,
height: Fit, height: Fill,
// debug: A // debug: A
home_screen_frame = <HomeScreen> {visible: true} home_screen_frame = <HomeScreen> {align: {x: 0.5, y: 0.5}, visible: true}
aboutus_screen_frame = <AboutUs> {visible: false} aboutus_screen_frame = <AboutUs> {visible: false}
} }
} }
} }
} }
#[derive(Live, LiveHook, Widget)] #[derive(Live)]
pub struct AppWebUI { pub struct AppWebUI {
#[deref] #[live]
view: View, view: WidgetRef,
} }
impl Widget for AppWebUI {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) { impl LiveRegister for AppWebUI {
self.view.handle_event(cx, event, scope); fn live_register(cx: &mut Cx) {
self.widget_match_event(cx, event, scope); crate::makepad_widgets::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);
} }
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { }
// DrawStep::done() impl LiveHook for AppWebUI {
self.view.draw_walk(cx, scope, walk) fn after_new_from_doc(&mut self, _cx: &mut Cx) {
println!("after_new_from_doc(): starting some kind of a loop");
} }
} }
impl WidgetMatchEvent for AppWebUI { impl MatchEvent for AppWebUI {
fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions, _scope: &mut Scope) {} fn handle_draw_2d(&mut self, cx: &mut Cx2d) {
let navbar_menu = self.view.view(id!(navbar_menu));
while let Some(next) = self.view.draw(cx, &mut Scope::empty()).step() {
navbar_menu.draw_all(cx, &mut Scope::empty());
}
}
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
self.view
.radio_button_set(ids!(
navbar_menu.home_screen_tab,
navbar_menu.aboutus_screen_tab,
))
.selected_to_visible(
cx,
&self.view,
actions,
ids!(
application_pages.home_screen_frame,
application_pages.aboutus_screen_frame,
),
);
}
}
impl AppMain for AppWebUI {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
if self.match_event_with_draw_2d(cx, event).is_ok() {
return;
}
self.match_event(cx, event);
self.view.handle_event(cx, event, &mut Scope::empty());
}
} }

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

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

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

@ -0,0 +1,27 @@
use std::{
fs,
path::{Path, PathBuf},
};
#[derive(Default)]
pub struct State {
pub images: Vec<PathBuf>,
pub screen_width: f64,
}
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

@ -18,7 +18,6 @@ live_design! {
height: Fill height: Fill
padding: {left: 25, right: 25, bottom: 20}, padding: {left: 25, right: 25, bottom: 20},
<View>{ <View>{
flow: Down, flow: Down,
spacing:10, spacing:10,
@ -35,6 +34,8 @@ live_design! {
width: 100, height: 30 width: 100, height: 30
text: "Click to count " text: "Click to count "
} }
<View>{
scroll_bars: <ScrollBars> {show_scroll_x: false, show_scroll_y: true}
label1 = <Label> { label1 = <Label> {
draw_text: { draw_text: {
color: #f color: #f
@ -47,6 +48,8 @@ live_design! {
// width: 400.0, // width: 400.0,
width: Fill, width: Fill,
} }
}
} }

View file

@ -11,9 +11,11 @@ live_design! {
HomeScreen = {{HomeScreen}} { HomeScreen = {{HomeScreen}} {
width: Fill, width: Fill,
height: Fill, height: Fill,
spacing: 10, spacing: 10.0,
<View> { <View> {
debug: A
<View> { <View> {
width: Fill, width: Fill,
height: Fill, height: Fill,

View file

@ -3,6 +3,7 @@ pub mod app;
pub mod app_mobile; pub mod app_mobile;
pub mod app_ui; pub mod app_ui;
pub mod app_web; pub mod app_web;
pub mod data;
pub mod aboutus; pub mod aboutus;
pub mod home; pub mod home;

View file

View file

View file

@ -0,0 +1,121 @@
use crate::makepad_widgets::*;
live_design! {
import makepad_widgets::theme_desktop_dark::*;
import makepad_widgets::base::*;
import makepad_draw::shader::std::*;
import crate::fish_theme::*;
import crate::block_header_button::*;
import crate::block_delete_button::*;
FishBlockEditor = <View>
{
margin: 0
width: 200
height: Fit
flow: Down
optimize: DrawList
title = <View>
{
show_bg: true
flow: Down
width: Fill
height: Fit
padding: 0
draw_bg:
{
fn pixel(self) -> vec4
{
return mix(vec4(1,1,0.6,1), vec4(1,1,0.5,1),self.pos.y);
}
},
topbar = <View>
{
flow:Right,
height: Fit,
header = <BlockHeaderButton>
{
draw_text:
{
color: #0
text_style: <H2_TEXT_BOLD> {}
}
}
delete = <BlockDeleteButton>
{
width: Fit,
draw_text:
{
color: #0
text_style: <H2_TEXT_BOLD> {}
}
}
padding = <View>
{
width: 20
}
}
}
body = <View>
{
show_bg: true
width: Fill
height: Fit
flow: Down
padding: {left: 30, right: 30, top: 4, bottom: 4}
draw_bg: {
fn pixel(self) -> vec4 {
return mix(vec4(1,1,0.9,1), vec4(1,1,0.8,1),self.pos.y);
}
}
<FishSlider>{text:"Slider A"}
<FishSlider>{text:"Slider B"}
<FishSlider>{text:"Slider C"}
}
}
FishBlockEditorGenerator = <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_GENERATOR, THEME_COLOR_GENERATOR_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_GENERATOR_FADE} } }
}
FishBlockEditorEffect = <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_EFFECT, THEME_COLOR_EFFECT_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_EFFECT_FADE} } }
}
FishBlockEditorMeta = <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_META, THEME_COLOR_META_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_META_FADE} } }
}
FishBlockEditorUtility = <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_UTILITY, THEME_COLOR_UTILITY_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_UTILITY_FADE} } }
}
FishBlockEditorModulator = <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_MODULATION, THEME_COLOR_MODULATION_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_MODULATION_FADE} } }
}
FishBlockEditorEnvelope= <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_ENVELOPE, THEME_COLOR_ENVELOPE_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_ENVELOPE_FADE} } }
}
FishBlockEditorFilter= <FishBlockEditor>
{
title = {draw_bg: { fn pixel(self) -> vec4 { return mix(THEME_COLOR_FILTER, THEME_COLOR_FILTER_DARK, self.pos.y) }} }
body = {draw_bg: { fn pixel(self) -> vec4 { return THEME_COLOR_FILTER_FADE} } }
}
}

View file

@ -0,0 +1,483 @@
use crate::{
// block_connector_button::BlockConnectorButtonAction,
// block_delete_button::BlockDeleteButtonAction, block_header_button::BlockHeaderButtonAction,
// fish_block_template::FishBlockCategory, fish_doc::FishDoc, fish_patch::*,
// fish_ports::ConnectionType,
makepad_draw::*,
makepad_widgets::*,
};
live_design! {
import makepad_widgets::theme_desktop_dark::*;
import makepad_widgets::base::*;
import crate::fish_block_editor::*;
// import crate::fish_theme::*;
// import crate::fish_connection_widget::*;
// import crate::fish_selector_widget::*;
// import crate::block_connector_button::*;
FishPatchEditor = {{FishPatchEditor}} {
width: Fill,
height: Fill,
scroll_bars: <ScrollBars> {}
BlockTemplateGenerator = <FishBlockEditorGenerator>{};
BlockTemplateMeta = <FishBlockEditorMeta>{};
BlockTemplateFilter = <FishBlockEditorFilter>{};
BlockTemplateEffect = <FishBlockEditorEffect>{};
BlockTemplateModulator = <FishBlockEditorModulator>{};
BlockTemplateEnvelope = <FishBlockEditorEnvelope>{};
BlockTemplateUtility = <FishBlockEditorUtility>{};
ConnectorTemplate = <FishConnectionWidget>{color: #d0d0a0ff};
SelectorTemplate = <FishSelectorWidget>{color: #d0d0a0ff};
AudioButtonTemplate = <BlockConnectorButton>{flow: Overlay, draw_bg: { bodytop: (CABLE_AUDIO_COLOR);}};
ControlButtonTemplate = <BlockConnectorButton>{flow: Overlay, draw_bg: { bodytop: (CABLE_CONTROL_COLOR);}};
GateButtonTemplate = <BlockConnectorButton>{flow: Overlay, draw_bg: { bodytop: (CABLE_GATE_COLOR);}};
MIDIButtonTemplate = <BlockConnectorButton>{flow: Overlay, draw_bg: { bodytop:(CABLE_MIDI_COLOR);}};
draw_bg: {
fn pixel(self) -> vec4 {
return vec4(0.03,0.03,0.03,1);
}
}
}
}
#[derive(Live, Widget)]
pub struct FishPatchEditor {
#[animator]
animator: Animator,
#[walk]
walk: Walk,
#[live]
draw_ls: DrawLine,
#[redraw]
#[live]
scroll_bars: ScrollBars,
#[live]
draw_bg: DrawColor,
#[rust]
unscrolled_rect: Rect,
#[rust]
templates: ComponentMap<LiveId, LivePtr>,
#[rust]
items: ComponentMap<LiveId, (LiveId, WidgetRef)>,
#[rust]
selectstart: DVec2,
#[rust]
selectend: DVec2,
#[rust]
selecting: bool,
#[rust]
dragstartx: f64,
#[rust]
dragstarty: f64,
#[rust]
active_undo_level: usize,
#[rust]
connectingid: u64,
#[rust]
connectingx: f64,
#[rust]
connectingy: f64,
#[rust]
connectingcurrentx: f64,
#[rust]
connectingcurrenty: f64,
#[rust]
connectinginput: bool,
#[rust]
connecting: bool,
#[rust]
selection: FishPatchSelection,
}
impl Widget for FishPatchEditor {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
let uid = self.widget_uid();
self.animator_handle_event(cx, event);
self.scroll_bars.handle_event(cx, event);
for (_item_id, item) in self.items.values_mut() {
let _item_uid = item.widget_uid();
for action in cx.capture_actions(|cx| item.handle_event(cx, event, scope)) {
match action.as_widget_action().cast() {
BlockHeaderButtonAction::Select { id } => {
self.selection.clear();
self.selection.add(id);
}
BlockHeaderButtonAction::Move { id, dx, dy } => {
self.scroll_bars.redraw(cx);
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
patch.move_selection(&self.selection, dx, dy);
}
BlockHeaderButtonAction::RecordDragStart { id } => {
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
let block = patch.blocks.find(id);
if block.is_some() {
if !self.selection.blocks.contains(&id) {
if self.selection.blocks.len() > 0 {
self.selection.clear();
}
self.selection.add(id);
}
let b = block.unwrap();
self.dragstartx = b.x;
self.dragstarty = b.y;
self.scroll_bars.redraw(cx);
self.active_undo_level = patch.undo_checkpoint_start();
}
}
BlockHeaderButtonAction::RecordDragEnd { id: _ } => {
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
patch.undo_checkpoint_end_if_match(self.active_undo_level);
self.active_undo_level = 0;
}
_ => {}
}
match action.as_widget_action().cast() {
BlockDeleteButtonAction::KillBlock { id } => {
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
patch.remove_block(id);
self.scroll_bars.redraw(cx);
}
_ => {}
}
}
}
match event.hits(cx, self.draw_bg.area()) {
Hit::FingerDown(fe) => {
// if fe.digit_id == live_id!(0).into() {
self.selecting = true;
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
// start selecting
self.selectstart = fe.abs.clone();
self.selectend = fe.abs.clone();
self.selection = patch.select_rectangle(self.selectstart, self.selectend);
// }
self.scroll_bars.redraw(cx);
self.animator_play(cx, id!(hover.pressed));
}
Hit::FingerMove(fe) => {
if
//fe.digit_id == live_id!(0).into() &&
self.selecting {
self.selectend = fe.abs.clone();
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
self.selection = patch.select_rectangle(self.selectstart, self.selectend);
self.scroll_bars.redraw(cx);
}
}
Hit::FingerHoverIn(_) => {
cx.set_cursor(MouseCursor::Hand);
self.animator_play(cx, id!(hover.on));
}
Hit::FingerHoverOut(_) => {
self.animator_play(cx, id!(hover.off));
}
Hit::FingerUp(fe) => {
if
//fe.digit_id == live_id!(0).into() &&
self.selecting {
self.selecting = false;
// stop selecting
self.scroll_bars.redraw(cx);
}
if fe.is_over {
// cx.widget_action(uid, &scope.path, ButtonAction::Clicked);
// cx.widget_action(uid, &scope.path, ButtonAction::Released);
if fe.device.has_hovers() {
self.animator_play(cx, id!(hover.on));
} else {
self.animator_play(cx, id!(hover.off));
}
} else {
// cx.widget_action(uid, &scope.path, ButtonAction::Released);
self.animator_play(cx, id!(hover.off));
}
}
_ => (),
}
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
let patch = &mut scope.data.get_mut::<FishDoc>().unwrap().patches[0];
//let mut _fullrect = cx.walk_turtle_with_area(&mut self.area, walk);
self.scroll_bars.begin(cx, walk, Layout::flow_overlay());
let _turtle_rect = cx.turtle().rect();
let scroll_pos = self.scroll_bars.get_scroll_pos();
self.unscrolled_rect = cx.turtle().unscrolled_rect();
self.draw_bg.draw_abs(cx, cx.turtle().unscrolled_rect());
self.draw_connections(cx, patch, scroll_pos);
self.draw_selection(cx, patch, scroll_pos);
for i in &mut patch.blocks.iter_mut() {
let item_id = LiveId::from_num(1, i.id as u64);
let templateid = match i.category {
FishBlockCategory::Effect => live_id!(BlockTemplateEffect),
FishBlockCategory::Generator => live_id!(BlockTemplateGenerator),
FishBlockCategory::Modulator => live_id!(BlockTemplateModulator),
FishBlockCategory::Envelope => live_id!(BlockTemplateEnvelope),
FishBlockCategory::Filter => live_id!(BlockTemplateFilter),
FishBlockCategory::Meta => live_id!(BlockTemplateMeta),
FishBlockCategory::Utility => live_id!(BlockTemplateUtility),
};
let item = self.item(cx, item_id, templateid).unwrap().as_view();
item.apply_over(
cx,
live! {title= {topbar = {header= {text: (i.name) , blockid: (i.id)}, delete = {blockid: (i.id)}}},
abs_pos: (dvec2(i.x as f64, i.y as f64 )-scroll_pos)},
);
item.draw_all(cx, &mut Scope::empty());
let itemarea = item.area().rect(cx);
i.h = itemarea.size.y;
i.w = itemarea.size.x;
if self.selection.blocks.contains(&i.id) {
self.draw_selected_outline(cx, i.x, i.y, i.w, i.h);
}
for inp in &i.input_ports {
let item_id = LiveId::from_num(2000 + i.id, inp.id as u64);
let templateid = match inp.datatype {
ConnectionType::Audio => live_id!(AudioButtonTemplate),
ConnectionType::MIDI => live_id!(MIDIButtonTemplate),
ConnectionType::Control => live_id!(ControlButtonTemplate),
ConnectionType::Gate => live_id!(GateButtonTemplate),
_ => live_id!(AudioButtonTemplate),
};
let item = self.item(cx, item_id, templateid).unwrap();
item.apply_over(
cx,
live! {
input: true,
abs_pos: (dvec2(i.x as f64, i.y as f64 + inp.id as f64 * 20.)-scroll_pos) ,
},
);
item.draw_all(cx, &mut Scope::empty());
}
for outp in &i.output_ports {
let item_id = LiveId::from_num(3000 + i.id, outp.id as u64);
let templateid = match outp.datatype {
ConnectionType::Audio => live_id!(AudioButtonTemplate),
ConnectionType::MIDI => live_id!(MIDIButtonTemplate),
ConnectionType::Control => live_id!(ControlButtonTemplate),
ConnectionType::Gate => live_id!(GateButtonTemplate),
_ => live_id!(AudioButtonTemplate),
};
let item = self.item(cx, item_id, templateid).unwrap();
item.apply_over(
cx,
live! {
input: false,
abs_pos: (dvec2(i.x as f64 + itemarea.size.x - 20. + 1., i.y as f64 + outp.id as f64 * 20.)-scroll_pos) ,
},
);
item.draw_all(cx, &mut Scope::empty());
}
}
if self.connecting {
self.draw_active_connection(cx, patch, scroll_pos);
}
self.scroll_bars.end(cx);
DrawStep::done()
}
}
impl LiveHook for FishPatchEditor {
fn after_new_from_doc(&mut self, _cx: &mut Cx) {}
fn before_apply(
&mut self,
_cx: &mut Cx,
apply: &mut Apply,
_index: usize,
_nodes: &[LiveNode],
) {
if let ApplyFrom::UpdateFromDoc { .. } = apply.from {
self.templates.clear();
}
}
// hook the apply flow to collect our templates and apply to instanced childnodes
fn apply_value_instance(
&mut self,
cx: &mut Cx,
apply: &mut Apply,
index: usize,
nodes: &[LiveNode],
) -> usize {
let id = nodes[index].id;
match apply.from {
ApplyFrom::NewFromDoc { file_id } | ApplyFrom::UpdateFromDoc { file_id } => {
if nodes[index].origin.has_prop_type(LivePropType::Instance) {
let live_ptr = cx
.live_registry
.borrow()
.file_id_index_to_live_ptr(file_id, index);
self.templates.insert(id, live_ptr);
// lets apply this thing over all our childnodes with that template
for (templ_id, node) in self.items.values_mut() {
if *templ_id == id {
node.apply(cx, apply, index, nodes);
}
}
} else {
cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
}
}
_ => (),
}
nodes.skip_node(index)
}
}
impl FishPatchEditor {
pub fn item(&mut self, cx: &mut Cx, id: LiveId, template: LiveId) -> Option<WidgetRef> {
if let Some(ptr) = self.templates.get(&template) {
let (_, entry) = self.items.get_or_insert(cx, id, |cx| {
(template, WidgetRef::new_from_ptr(cx, Some(*ptr)))
});
return Some(entry.clone());
}
None
}
}
impl FishPatchEditor {
pub fn draw_active_connection(&mut self, cx: &mut Cx2d, _patch: &FishPatch, scroll_pos: DVec2) {
let item_id = LiveId::from_str("ActiveConnectionWidget");
let templateid = live_id!(ConnectorTemplate);
let preitem = self.item(cx, item_id, templateid);
let item = preitem.unwrap();
if self.connectinginput {
item.apply_over(
cx,
live! {
end_pos: (dvec2(self.connectingx as f64 , self.connectingy as f64 ) - scroll_pos),
start_pos: (dvec2(self.connectingcurrentx as f64, self.connectingcurrenty as f64) - scroll_pos ),
color: #ff0,
abs_pos: (dvec2(0.,0.)),
},
);
} else {
item.apply_over(
cx,
live! {
start_pos: (dvec2(self.connectingx as f64 , self.connectingy as f64 ) - scroll_pos),
end_pos: (dvec2(self.connectingcurrentx as f64, self.connectingcurrenty as f64) - scroll_pos ),
color: #ff0,
abs_pos: (dvec2(0.,0.)),
},
);
}
item.draw_all(cx, &mut Scope::empty());
}
pub fn draw_selection(&mut self, cx: &mut Cx2d, _patch: &FishPatch, scroll_pos: DVec2) {
if self.selecting {
let item_id = LiveId::from_str("ActiveSelectionWidget");
let templateid = live_id!(SelectorTemplate);
let preitem = self.item(cx, item_id, templateid);
let item = preitem.unwrap();
item.apply_over(
cx,
live! {
start_pos: (self.selectstart - scroll_pos),
end_pos: (self.selectend - scroll_pos),
color: #eee,
line_width: 2.0
},
);
item.draw_all(cx, &mut Scope::empty());
}
}
pub fn draw_selected_outline(&mut self, cx: &mut Cx2d, x: f64, y: f64, w: f64, h: f64) {
let tl = DVec2 {
x: x as f64 - 1.5,
y: y as f64 - 1.5,
};
let br = DVec2 {
x: (x + w) as f64 + 1.5,
y: (y + h) as f64 + 1.5,
};
let bl = DVec2 { x: tl.x, y: br.y };
let tr = DVec2 { x: br.x, y: tl.y };
let color = vec4(1., 1., 0., 1.);
self.draw_ls.draw_line_abs(cx, tl, tr, color, 4.);
self.draw_ls.draw_line_abs(cx, tr, br, color, 4.);
self.draw_ls.draw_line_abs(cx, br, bl, color, 4.);
self.draw_ls.draw_line_abs(cx, tl, bl, color, 4.);
}
pub fn draw_connections(&mut self, cx: &mut Cx2d, patch: &FishPatch, scroll_pos: DVec2) {
for i in patch.connections.iter() {
let item_id = LiveId::from_num(2, i.id as u64);
let templateid = live_id!(ConnectorTemplate);
let preitem = self.item(cx, item_id, templateid);
let item = preitem.unwrap();
let blockfromopt = patch.get_block(&i.from_block);
let blocktoopt = patch.get_block(&i.to_block);
let mut inselection = false;
if blockfromopt.is_some() && blocktoopt.is_some() {
let blockfrom = blockfromopt.unwrap();
let blockto = blocktoopt.unwrap();
let _portfrom = blockfrom.get_output_instance(i.from_port).unwrap();
let _portto = blockto.get_input_instance(i.to_port).unwrap();
if self.selection.blocks.contains(&blockfrom.id)
&& self.selection.blocks.contains(&blockto.id)
{
inselection = true;
}
item.apply_over( cx, live! {
start_pos: (dvec2(blockfrom.x as f64 + 200.0, blockfrom.y as f64 + 10. + 20. * _portfrom.id as f64) - scroll_pos),
end_pos: (dvec2(blockto.x as f64, blockto.y as f64+ 10. + 20. * _portto.id as f64) - scroll_pos ),
from_top: (blockfrom.y- scroll_pos.y ),
from_bottom: (blockfrom.y + blockfrom.h - scroll_pos.y ),
to_top: (blockto.y - scroll_pos.y ),
to_bottom: (blockto.y + blockto.h - scroll_pos.y ) ,
color: #x888,
abs_pos: (dvec2(0.,0.)),
selected: (inselection)
},
);
item.draw_all(cx, &mut Scope::empty());
}
// println!("{:?} ({:?},{:?})", i.id, i.x,i.y);
}
}
}

2
src/shared/editor/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod fish_block_editor;
pub mod fish_patch_editor;

View file

@ -1,5 +1,6 @@
use makepad_widgets::Cx; use makepad_widgets::Cx;
// pub mod editor;
pub mod styles; pub mod styles;
pub mod widgets; pub mod widgets;
@ -7,6 +8,7 @@ pub fn live_design(cx: &mut Cx) {
styles::live_design(cx); styles::live_design(cx);
// resource_imports::live_design(cx); // resource_imports::live_design(cx);
widgets::live_design(cx); widgets::live_design(cx);
// editor::live_design(cx);
// portal::live_design(cx); // portal::live_design(cx);
// modal::live_design(cx); // modal::live_design(cx);
// external_link::live_design(cx); // external_link::live_design(cx);

128
src/web.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 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},
padding: {top: 0, bottom: 48 }
// 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),
}
}
application_pages = <View> {
margin: 0.0,
padding: 0.0,
flow: Down,
width: Fill,
height: Fill,
// debug: A
home_screen_frame = <HomeScreen> {visible: true}
aboutus_screen_frame = <AboutUs> {visible: false}
}
}
}
}
#[derive(Live, Widget)]
pub struct AppWebUI {
#[deref]
view: Window,
// #[live]
// view: WidgetRef,
}
impl LiveHook for AppWebUI {
fn after_new_from_doc(&mut self, _cx: &mut Cx) {
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.view.handle_event(cx, event, scope);
self.widget_match_event(cx, event, scope);
}
// fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
// 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 AppWebUI {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
self.view
.radio_button_set(ids!(
navbar_menu.home_screen_tab,
navbar_menu.aboutus_screen_tab,
))
.selected_to_visible(
cx,
&self.view,
actions,
ids!(
application_pages.home_screen_frame,
application_pages.aboutus_screen_frame,
),
);
}
}
/*
error[E0308]: mismatched types
--> src/app_web.rs:102:17
|
100 | .selected_to_visible(
| ------------------- arguments to this method are incorrect
101 | cx,
102 | &self.view,
| ^^^^^^^^^^ expected `&WidgetRef`, found `&Window`
|
= note: expected reference `&makepad_widgets::WidgetRef`
found reference `&makepad_widgets::Window`
note: method defined here
--> /Users/aok/Projects/rustdev/MadeByMakepad/makepad/widgets/src/radio_button.rs:202:12
|
202 | pub fn selected_to_visible(&self, cx: &mut Cx, ui:&WidgetRef, actions: &Actions, paths:&[&[Liv...
| ^^^^^^^^^^^^^^^^^^^
*/