changes to app_web.rs
This commit is contained in:
parent
dc1efaeed6
commit
8d9de58378
15 changed files with 891 additions and 46 deletions
14
src/app.rs
14
src/app.rs
|
@ -1,5 +1,7 @@
|
|||
use makepad_widgets::*;
|
||||
|
||||
use crate::data::state::State;
|
||||
|
||||
live_design! {
|
||||
import makepad_widgets::base::*;
|
||||
import makepad_widgets::theme_desktop_dark::*;
|
||||
|
@ -32,6 +34,8 @@ app_main!(App);
|
|||
pub struct App {
|
||||
#[live]
|
||||
ui: WidgetRef,
|
||||
#[rust]
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl LiveRegister for App {
|
||||
|
@ -46,14 +50,20 @@ impl LiveRegister for App {
|
|||
crate::shared::live_design(cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl MatchEvent for App {
|
||||
fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions) {}
|
||||
}
|
||||
|
||||
impl AppMain for App {
|
||||
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.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());
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use std::path::Path;
|
||||
|
||||
use makepad_widgets::*;
|
||||
|
||||
use crate::data::state::State;
|
||||
|
||||
live_design! {
|
||||
import makepad_widgets::base::*;
|
||||
import makepad_widgets::theme_desktop_dark::*;
|
||||
|
@ -45,55 +49,74 @@ pub struct AppUI {
|
|||
view: View,
|
||||
|
||||
#[rust]
|
||||
screen_width: f64,
|
||||
state: State,
|
||||
// #[rust]
|
||||
// screen_width: f64,
|
||||
}
|
||||
|
||||
impl LiveHook for AppUI {
|
||||
fn after_new_from_doc(&mut self, cx: &mut Cx) {
|
||||
let mobile_screen = self.view.view(id!(mobile));
|
||||
let web_screen = self.view.view(id!(web));
|
||||
if self.screen_width < 960_f64 {
|
||||
log!("SCREEN_WIDTH ===> {}", self.screen_width);
|
||||
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.screen_width > 960_f64 {
|
||||
} 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.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 {
|
||||
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);
|
||||
}
|
||||
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||
// DrawStep::done()
|
||||
// let state = scope.data.get::<State>().unwrap();
|
||||
let mobile_screen = self.view.view(id!(mobile));
|
||||
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 self.screen_width == 0_f64 {
|
||||
if self.state.screen_width == 0_f64 {
|
||||
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);
|
||||
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)?;
|
||||
} else if self.screen_width > 960_f64 {
|
||||
} 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());
|
||||
web_screen.draw_all(cx, scope);
|
||||
self.view.draw_walk(cx, scope, walk)?;
|
||||
} else {
|
||||
log!("ESLE_SCREEN_WIDTH ===> {}", self.screen_width);
|
||||
log!("ESLE_SCREEN_WIDTH ===> {}", self.state.screen_width);
|
||||
}
|
||||
}
|
||||
DrawStep::done()
|
||||
|
@ -101,20 +124,21 @@ impl Widget 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 {
|
||||
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 web_screen = self.view.view(id!(web));
|
||||
if self.screen_width < 960_f64 {
|
||||
if state.screen_width < 960_f64 {
|
||||
web_screen.set_visible(false);
|
||||
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);
|
||||
web_screen.set_visible_and_redraw(cx, true);
|
||||
} else {
|
||||
log!("ELSE_SCREEN_WIDTH ===> {}", self.screen_width);
|
||||
log!("ELSE_SCREEN_WIDTH ===> {}", state.screen_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use makepad_widgets::*;
|
||||
|
||||
use crate::data::state::State;
|
||||
|
||||
live_design! {
|
||||
import makepad_widgets::base::*;
|
||||
import makepad_widgets::theme_desktop_dark::*;
|
||||
|
@ -52,32 +54,71 @@ live_design! {
|
|||
margin: 0.0,
|
||||
padding: 0.0,
|
||||
flow: Down,
|
||||
width: Fit,
|
||||
height: Fit,
|
||||
width: Fill,
|
||||
height: Fill,
|
||||
// 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}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Live, LiveHook, Widget)]
|
||||
#[derive(Live)]
|
||||
pub struct AppWebUI {
|
||||
#[deref]
|
||||
view: View,
|
||||
#[live]
|
||||
view: WidgetRef,
|
||||
}
|
||||
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);
|
||||
|
||||
impl LiveRegister for AppWebUI {
|
||||
fn live_register(cx: &mut Cx) {
|
||||
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()
|
||||
self.view.draw_walk(cx, scope, walk)
|
||||
}
|
||||
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 WidgetMatchEvent for AppWebUI {
|
||||
fn handle_actions(&mut self, _cx: &mut Cx, _actions: &Actions, _scope: &mut Scope) {}
|
||||
impl MatchEvent for AppWebUI {
|
||||
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
1
src/data/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod state;
|
27
src/data/state.rs
Normal file
27
src/data/state.rs
Normal 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())
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ live_design! {
|
|||
height: Fill
|
||||
padding: {left: 25, right: 25, bottom: 20},
|
||||
|
||||
|
||||
<View>{
|
||||
flow: Down,
|
||||
spacing:10,
|
||||
|
@ -35,6 +34,8 @@ live_design! {
|
|||
width: 100, height: 30
|
||||
text: "Click to count "
|
||||
}
|
||||
<View>{
|
||||
scroll_bars: <ScrollBars> {show_scroll_x: false, show_scroll_y: true}
|
||||
label1 = <Label> {
|
||||
draw_text: {
|
||||
color: #f
|
||||
|
@ -47,6 +48,8 @@ live_design! {
|
|||
// width: 400.0,
|
||||
width: Fill,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@ live_design! {
|
|||
HomeScreen = {{HomeScreen}} {
|
||||
width: Fill,
|
||||
height: Fill,
|
||||
spacing: 10,
|
||||
spacing: 10.0,
|
||||
|
||||
<View> {
|
||||
debug: A
|
||||
|
||||
<View> {
|
||||
width: Fill,
|
||||
height: Fill,
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod app;
|
|||
pub mod app_mobile;
|
||||
pub mod app_ui;
|
||||
pub mod app_web;
|
||||
pub mod data;
|
||||
|
||||
pub mod aboutus;
|
||||
pub mod home;
|
||||
|
|
0
src/shared/editor/block_delete_button.rs
Normal file
0
src/shared/editor/block_delete_button.rs
Normal file
0
src/shared/editor/block_header_button.rs
Normal file
0
src/shared/editor/block_header_button.rs
Normal file
121
src/shared/editor/fish_block_editor.rs
Normal file
121
src/shared/editor/fish_block_editor.rs
Normal 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} } }
|
||||
}
|
||||
}
|
483
src/shared/editor/fish_patch_editor.rs
Normal file
483
src/shared/editor/fish_patch_editor.rs
Normal 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
2
src/shared/editor/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod fish_block_editor;
|
||||
pub mod fish_patch_editor;
|
|
@ -1,5 +1,6 @@
|
|||
use makepad_widgets::Cx;
|
||||
|
||||
// pub mod editor;
|
||||
pub mod styles;
|
||||
pub mod widgets;
|
||||
|
||||
|
@ -7,6 +8,7 @@ pub fn live_design(cx: &mut Cx) {
|
|||
styles::live_design(cx);
|
||||
// resource_imports::live_design(cx);
|
||||
widgets::live_design(cx);
|
||||
// editor::live_design(cx);
|
||||
// portal::live_design(cx);
|
||||
// modal::live_design(cx);
|
||||
// external_link::live_design(cx);
|
||||
|
|
128
src/web.rs
Normal file
128
src/web.rs
Normal 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...
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue