Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add GUI to the example plugin (#110) #111

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Simulate winit-like view attachment in the example
ales-tsurko committed May 29, 2020
commit 541692319b760c6c95a37fa4bc62a9758f61f88f
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -25,13 +25,14 @@ cc = { version = "1.0", features = ["parallel"] }

[dev-dependencies]
bincode = "1.2"
chrono = "0.4"
iced = { git = "https://github.com/hecrj/iced.git", features = ["canvas", "tokio", "debug"] }
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
simple-logging = "2.0"
simplelog = "0.7"
minifb = "0.16"

[[example]]
name = "simple"
path = "examples/simple.rs"
path = "examples/simple/simple.rs"
crate-type = ["cdylib"]
133 changes: 133 additions & 0 deletions examples/simple/gui.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use iced::{
canvas::{self, Cache, Canvas, Cursor, Geometry, LineCap, Path, Stroke},
executor, time, Application, Color, Command, Container, Element, Length,
Point, Rectangle, Settings, Subscription, Vector,
};

pub fn main() {
Clock::run(Settings {
antialiasing: true,
..Settings::default()
})
}

struct Clock {
now: chrono::DateTime<chrono::Local>,
clock: Cache,
}

#[derive(Debug, Clone, Copy)]
enum Message {
Tick(chrono::DateTime<chrono::Local>),
}

impl Application for Clock {
type Executor = executor::Default;
type Message = Message;
type Flags = ();

fn new(_flags: ()) -> (Self, Command<Message>) {
(
Clock {
now: chrono::Local::now(),
clock: Default::default(),
},
Command::none(),
)
}

fn title(&self) -> String {
String::from("Clock - Iced")
}

fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(local_time) => {
let now = local_time;

if now != self.now {
self.now = now;
self.clock.clear();
}
}
}

Command::none()
}

fn subscription(&self) -> Subscription<Message> {
time::every(std::time::Duration::from_millis(500))
.map(|_| Message::Tick(chrono::Local::now()))
}

fn view(&mut self) -> Element<Message> {
let canvas = Canvas::new(self)
.width(Length::Units(400))
.height(Length::Units(400));

Container::new(canvas)
.width(Length::Fill)
.height(Length::Fill)
.padding(20)
.center_x()
.center_y()
.into()
}
}

impl canvas::Program<Message> for Clock {
fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry> {
use chrono::Timelike;

let clock = self.clock.draw(bounds.size(), |frame| {
let center = frame.center();
let radius = frame.width().min(frame.height()) / 2.0;

let background = Path::circle(center, radius);
frame.fill(&background, Color::from_rgb8(0x12, 0x93, 0xD8));

let short_hand =
Path::line(Point::ORIGIN, Point::new(0.0, -0.5 * radius));

let long_hand =
Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius));

let thin_stroke = Stroke {
width: radius / 100.0,
color: Color::WHITE,
line_cap: LineCap::Round,
..Stroke::default()
};

let wide_stroke = Stroke {
width: thin_stroke.width * 3.0,
..thin_stroke
};

frame.translate(Vector::new(center.x, center.y));

frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.hour(), 12));
frame.stroke(&short_hand, wide_stroke);
});

frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.minute(), 60));
frame.stroke(&long_hand, wide_stroke);
});

frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.second(), 60));
frame.stroke(&long_hand, thin_stroke);
})
});

vec![clock]
}
}

fn hand_rotation(n: u32, total: u32) -> f32 {
let turns = n as f32 / total as f32;

2.0 * std::f32::consts::PI * turns
}
45 changes: 30 additions & 15 deletions examples/simple.rs → examples/simple/simple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod ui;
pub mod gui;

use std::collections::HashMap;
#[cfg(unix)]
@@ -8,6 +8,12 @@ use std::sync::{Arc, Mutex, Once};
use std::time::{SystemTime, UNIX_EPOCH};

use bincode;
#[cfg(target_os = "macos")]
use cocoa::appkit::{NSBackingStoreType, NSColor, NSView, NSWindow, NSWindowStyleMask};
#[cfg(target_os = "macos")]
use cocoa::base::{id, nil};
#[cfg(target_os = "macos")]
use cocoa::foundation::{NSPoint, NSRect, NSSize};
use log::{error, info, trace, LevelFilter};
use serde::{Deserialize, Serialize};
#[cfg(windows)]
@@ -20,11 +26,11 @@ use fpsdk::plugin::message;
use fpsdk::plugin::{self, Info, InfoBuilder, Plugin, StateReader, StateWriter};
use fpsdk::voice::{self, ReceiveVoiceHandler, SendVoiceHandler, Voice};
use fpsdk::{
add_child_window_s, create_plugin, AsRawPtr, FromRawPtr, MessageBoxFlags, MidiMessage, Note,
Notes, NotesFlags, ProcessParamFlags, TimeFormat, ValuePtr, VstView,
create_plugin, AsRawPtr, FromRawPtr, MessageBoxFlags, MidiMessage, Note, Notes, NotesFlags,
ProcessParamFlags, TimeFormat, ValuePtr,
};

use ui::init_window;
// use gui;

static ONCE: Once = Once::new();
const LOG_PATH: &str = "simple.log";
@@ -36,9 +42,11 @@ struct Simple {
param_names: Vec<String>,
state: State,
voice_handler: SimpleVoiceHandler,
view: Option<VstView>,
}

unsafe impl Send for Simple {}
unsafe impl Sync for Simple {}

#[derive(Debug, Default, Deserialize, Serialize)]
struct State {
_time: u64,
@@ -65,7 +73,6 @@ impl Plugin for Simple {
"Parameter 3".into(),
],
state: Default::default(),
view: None,
}
}

@@ -128,16 +135,24 @@ impl Plugin for Simple {
}

if let host::Message::ShowEditor(Some(parent)) = message {
if !parent.is_null() {
if self.view.is_none() {
self.view = Some(VstView::new(parent));
}
self.view.as_mut().unwrap().open();
let view = parent.raw_handle() as id;
unsafe {
NSView::setFrameSize(view, NSSize::new(200.0, 100.0));
let frame = NSView::frame(view);
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
frame,
NSWindowStyleMask::NSBorderlessWindowMask
| NSWindowStyleMask::NSTitledWindowMask,
NSBackingStoreType::NSBackingStoreBuffered,
0,
);
let color = NSColor::colorWithRed_green_blue_alpha_(nil, 1.0, 0.5, 0.0, 1.0);
window.orderFront_(window);
window.contentView().setWantsLayer(1);
window.contentView().setBackgroundColor_(color);

view.addSubview_(window.contentView());
}
// let window = init_window();
// let handle = window.get_window_handle();
// info!("got window handle {:?}", handle);
// add_child_window_s(parent, handle);
}
// if let host::Message::ShowEditor(None) = message {
// if self.view.is_some() {
83 changes: 0 additions & 83 deletions examples/ui.rs

This file was deleted.

6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -273,7 +273,7 @@ impl EditorHandle {
self.raw_handle
}
/// Attach your editor the handle.
pub fn attach_editor<V: HasRawWindowHandle>(&mut self, view: &mut V) {
pub fn attach_editor<V: HasRawWindowHandle>(&self, view: &mut V) {
// We make separate private implementations here, because docs on docs.rs is compiled under
// linux, so if we just use different attach_editor per platform, it'll be hidden on
// docs.rs.
@@ -289,7 +289,7 @@ impl EditorHandle {
}

#[cfg(target_os = "macos")]
unsafe fn attach_editor_mac<V: HasRawWindowHandle>(&mut self, view: &mut V) {
unsafe fn attach_editor_mac<V: HasRawWindowHandle>(&self, view: &mut V) {
if let RawWindowHandle::MacOS(handle) = view.raw_window_handle() {
if handle.ns_view.is_null() {
return;
@@ -303,7 +303,7 @@ impl EditorHandle {
}

#[cfg(target_os = "windows")]
unsafe fn attach_editor_win<V: HasRawWindowHandle>(&mut self, view: &mut V) {}
unsafe fn attach_editor_win<V: HasRawWindowHandle>(&self, view: &mut V) {}
}

impl FromRawPtr for EditorHandle {
4 changes: 2 additions & 2 deletions src/voice.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Voices used by generators to track events like their instantiation, release, freeing and
//! processing some events.
//! Voices used by the generator plugins to track their instantiation, release, freeing and events
//! processing.
use std::os::raw::c_void;

use crate::plugin::PluginAdapter;