replace Swift editor with Iced TextEditor, delete old compositor
This commit is contained in:
parent
50aad4bf84
commit
7a2aa08d1c
|
|
@ -24,8 +24,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
_ = ConfigManager.shared
|
||||
appState = AppState()
|
||||
|
||||
let contentView = ContentView(state: appState)
|
||||
let hostingView = NSHostingView(rootView: contentView)
|
||||
let viewport = IcedViewportView(frame: NSRect(x: 0, y: 0, width: 1200, height: 800))
|
||||
viewport.autoresizingMask = [.width, .height]
|
||||
|
||||
window = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 1200, height: 800),
|
||||
|
|
@ -37,7 +37,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
window.titleVisibility = .hidden
|
||||
window.backgroundColor = Theme.current.base
|
||||
window.title = "Swiftly"
|
||||
window.contentView = hostingView
|
||||
window.contentView = viewport
|
||||
window.center()
|
||||
window.setFrameAutosaveName("SwiftlyMainWindow")
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
|
|
@ -235,8 +235,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
@objc private func newWindow() {
|
||||
let state = AppState()
|
||||
let contentView = ContentView(state: state)
|
||||
let hostingView = NSHostingView(rootView: contentView)
|
||||
let viewport = IcedViewportView(frame: NSRect(x: 0, y: 0, width: 1200, height: 800))
|
||||
viewport.autoresizingMask = [.width, .height]
|
||||
|
||||
let win = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 1200, height: 800),
|
||||
|
|
@ -248,7 +248,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
win.titleVisibility = .hidden
|
||||
win.backgroundColor = Theme.current.base
|
||||
win.title = "Swiftly"
|
||||
win.contentView = hostingView
|
||||
win.contentView = viewport
|
||||
win.center()
|
||||
win.makeKeyAndOrderFront(nil)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,12 +6,7 @@ struct ContentView: View {
|
|||
|
||||
var body: some View {
|
||||
let _ = themeVersion
|
||||
HSplitView {
|
||||
EditorView(state: state)
|
||||
.frame(minWidth: 400)
|
||||
IcedViewportRepresentable()
|
||||
.frame(minWidth: 200)
|
||||
}
|
||||
.frame(minWidth: 700, minHeight: 400)
|
||||
.background(Color(ns: Theme.current.base))
|
||||
.onReceive(NotificationCenter.default.publisher(for: .settingsChanged)) { _ in
|
||||
|
|
|
|||
3199
src/EditorView.swift
3199
src/EditorView.swift
File diff suppressed because it is too large
Load Diff
|
|
@ -26,6 +26,7 @@ class IcedViewportView: NSView {
|
|||
if window != nil && viewportHandle == nil {
|
||||
createViewport()
|
||||
startDisplayLink()
|
||||
window?.makeFirstResponder(self)
|
||||
} else if window == nil {
|
||||
stopDisplayLink()
|
||||
destroyViewport()
|
||||
|
|
@ -105,6 +106,7 @@ class IcedViewportView: NSView {
|
|||
// MARK: - Mouse Events
|
||||
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
window?.makeFirstResponder(self)
|
||||
guard let h = viewportHandle else { return }
|
||||
let pt = convert(event.locationInWindow, from: nil)
|
||||
viewport_mouse_event(h, Float(pt.x), Float(pt.y), 0, true)
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
import SwiftUI
|
||||
|
|
@ -6,7 +6,7 @@ use smol_str::SmolStr;
|
|||
use crate::ViewportHandle;
|
||||
|
||||
pub fn push_mouse_event(handle: &mut ViewportHandle, x: f32, y: f32, button: u8, pressed: bool) {
|
||||
let position = Point::new(x / handle.scale, y / handle.scale);
|
||||
let position = Point::new(x, y);
|
||||
handle.cursor = mouse::Cursor::Available(position);
|
||||
|
||||
handle.events.push(Event::Mouse(mouse::Event::CursorMoved { position }));
|
||||
|
|
@ -34,10 +34,21 @@ pub fn push_key_event(
|
|||
) {
|
||||
let modifiers = decode_modifiers(modifier_flags);
|
||||
let physical = key::Physical::Unidentified(key::NativeCode::MacOS(keycode as u16));
|
||||
let logical = text
|
||||
.filter(|s| !s.is_empty())
|
||||
|
||||
let named = keycode_to_named(keycode);
|
||||
let logical = if let Some(n) = named {
|
||||
keyboard::Key::Named(n)
|
||||
} else {
|
||||
text.filter(|s| !s.is_empty())
|
||||
.map(|s| keyboard::Key::Character(SmolStr::new(s)))
|
||||
.unwrap_or(keyboard::Key::Unidentified);
|
||||
.unwrap_or(keyboard::Key::Unidentified)
|
||||
};
|
||||
|
||||
let insert_text = if named.is_some() {
|
||||
None
|
||||
} else {
|
||||
text.filter(|s| !s.is_empty()).map(SmolStr::new)
|
||||
};
|
||||
|
||||
if pressed {
|
||||
handle.events.push(Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
|
|
@ -46,7 +57,7 @@ pub fn push_key_event(
|
|||
physical_key: physical,
|
||||
location: keyboard::Location::Standard,
|
||||
modifiers,
|
||||
text: text.filter(|s| !s.is_empty()).map(SmolStr::new),
|
||||
text: insert_text,
|
||||
repeat: false,
|
||||
}));
|
||||
} else {
|
||||
|
|
@ -60,6 +71,38 @@ pub fn push_key_event(
|
|||
}
|
||||
}
|
||||
|
||||
fn keycode_to_named(keycode: u32) -> Option<keyboard::key::Named> {
|
||||
use keyboard::key::Named;
|
||||
match keycode {
|
||||
36 => Some(Named::Enter),
|
||||
48 => Some(Named::Tab),
|
||||
51 => Some(Named::Backspace),
|
||||
53 => Some(Named::Escape),
|
||||
117 => Some(Named::Delete),
|
||||
123 => Some(Named::ArrowLeft),
|
||||
124 => Some(Named::ArrowRight),
|
||||
125 => Some(Named::ArrowDown),
|
||||
126 => Some(Named::ArrowUp),
|
||||
115 => Some(Named::Home),
|
||||
119 => Some(Named::End),
|
||||
116 => Some(Named::PageUp),
|
||||
121 => Some(Named::PageDown),
|
||||
122 => Some(Named::F1),
|
||||
120 => Some(Named::F2),
|
||||
99 => Some(Named::F3),
|
||||
118 => Some(Named::F4),
|
||||
96 => Some(Named::F5),
|
||||
97 => Some(Named::F6),
|
||||
98 => Some(Named::F7),
|
||||
100 => Some(Named::F8),
|
||||
101 => Some(Named::F9),
|
||||
109 => Some(Named::F10),
|
||||
103 => Some(Named::F11),
|
||||
111 => Some(Named::F12),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_scroll_event(
|
||||
handle: &mut ViewportHandle,
|
||||
x: f32,
|
||||
|
|
@ -67,7 +110,7 @@ pub fn push_scroll_event(
|
|||
delta_x: f32,
|
||||
delta_y: f32,
|
||||
) {
|
||||
let position = Point::new(x / handle.scale, y / handle.scale);
|
||||
let position = Point::new(x, y);
|
||||
handle.cursor = mouse::Cursor::Available(position);
|
||||
handle.events.push(Event::Mouse(mouse::Event::WheelScrolled {
|
||||
delta: mouse::ScrollDelta::Pixels {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,50 @@
|
|||
use iced_wgpu::core::{Color, Element, Length, Theme};
|
||||
use iced_widget::{container, Text};
|
||||
use iced_wgpu::core::text::Wrapping;
|
||||
use iced_wgpu::core::{
|
||||
Background, Border, Color, Element, Font, Length, Padding, Theme,
|
||||
};
|
||||
use iced_widget::text_editor::{self, Style};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
EditorAction(text_editor::Action),
|
||||
}
|
||||
|
||||
pub struct EditorState {
|
||||
pub text: String,
|
||||
pub content: text_editor::Content<iced_wgpu::Renderer>,
|
||||
pub font_size: f32,
|
||||
}
|
||||
|
||||
impl EditorState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
text: String::from("Swiftly"),
|
||||
content: text_editor::Content::new(),
|
||||
font_size: 14.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<'_, (), Theme, iced_wgpu::Renderer> {
|
||||
container(
|
||||
Text::new(&self.text)
|
||||
.size(32)
|
||||
.color(Color::WHITE),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
pub fn update(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::EditorAction(action) => {
|
||||
self.content.perform(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<'_, Message, Theme, iced_wgpu::Renderer> {
|
||||
iced_widget::text_editor(&self.content)
|
||||
.on_action(Message::EditorAction)
|
||||
.font(Font::MONOSPACE)
|
||||
.size(self.font_size)
|
||||
.height(Length::Fill)
|
||||
.center_x(Length::Fill)
|
||||
.center_y(Length::Fill)
|
||||
.padding(Padding { top: 38.0, right: 8.0, bottom: 8.0, left: 8.0 })
|
||||
.wrapping(Wrapping::Word)
|
||||
.style(|_theme, _status| Style {
|
||||
background: Background::Color(Color::from_rgb(0.08, 0.08, 0.10)),
|
||||
border: Border::default(),
|
||||
placeholder: Color::from_rgb(0.4, 0.4, 0.4),
|
||||
value: Color::WHITE,
|
||||
selection: Color::from_rgba(0.3, 0.5, 0.8, 0.4),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,49 @@
|
|||
use std::ffi::c_void;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use iced_graphics::{Viewport, Shell};
|
||||
use iced_graphics::{Shell, Viewport};
|
||||
use iced_runtime::user_interface::{self, UserInterface};
|
||||
use iced_wgpu::core::renderer::Style;
|
||||
use iced_wgpu::core::{clipboard, mouse, Color, Font, Pixels, Size, Theme};
|
||||
use iced_wgpu::core::time::Instant;
|
||||
use iced_wgpu::core::{clipboard, mouse, window, Color, Event, Font, Pixels, Point, Size, Theme};
|
||||
use iced_wgpu::Engine;
|
||||
use raw_window_handle::{AppKitDisplayHandle, AppKitWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
use raw_window_handle::{
|
||||
AppKitDisplayHandle, AppKitWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
|
||||
use crate::editor::EditorState;
|
||||
use crate::editor::{EditorState, Message};
|
||||
use crate::ViewportHandle;
|
||||
|
||||
pub fn create(nsview: *mut c_void, width: f32, height: f32, scale: f32) -> Option<ViewportHandle> {
|
||||
struct MacClipboard;
|
||||
|
||||
impl clipboard::Clipboard for MacClipboard {
|
||||
fn read(&self, _kind: clipboard::Kind) -> Option<String> {
|
||||
std::process::Command::new("pbpaste")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||
}
|
||||
|
||||
fn write(&mut self, _kind: clipboard::Kind, contents: String) {
|
||||
use std::io::Write;
|
||||
if let Ok(mut child) = std::process::Command::new("pbcopy")
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
{
|
||||
if let Some(stdin) = child.stdin.as_mut() {
|
||||
let _ = stdin.write_all(contents.as_bytes());
|
||||
}
|
||||
let _ = child.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
nsview: *mut c_void,
|
||||
width: f32,
|
||||
height: f32,
|
||||
scale: f32,
|
||||
) -> Option<ViewportHandle> {
|
||||
let ptr = NonNull::new(nsview)?;
|
||||
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
||||
|
|
@ -72,16 +104,17 @@ pub fn create(nsview: *mut c_void, width: f32, height: f32, scale: f32) -> Optio
|
|||
Shell::headless(),
|
||||
);
|
||||
|
||||
let renderer = iced_wgpu::Renderer::new(
|
||||
engine,
|
||||
Font::DEFAULT,
|
||||
Pixels(16.0),
|
||||
);
|
||||
let renderer = iced_wgpu::Renderer::new(engine, Font::DEFAULT, Pixels(16.0));
|
||||
|
||||
let viewport = Viewport::with_physical_size(
|
||||
Size::new(phys_w.max(1), phys_h.max(1)),
|
||||
scale,
|
||||
);
|
||||
let viewport =
|
||||
Viewport::with_physical_size(Size::new(phys_w.max(1), phys_h.max(1)), scale);
|
||||
|
||||
let focus_point = Point::new(width / 2.0, height / 2.0);
|
||||
let initial_events = vec![
|
||||
Event::Mouse(mouse::Event::CursorMoved { position: focus_point }),
|
||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
|
||||
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)),
|
||||
];
|
||||
|
||||
Some(ViewportHandle {
|
||||
surface,
|
||||
|
|
@ -95,8 +128,8 @@ pub fn create(nsview: *mut c_void, width: f32, height: f32, scale: f32) -> Optio
|
|||
viewport,
|
||||
cache: user_interface::Cache::new(),
|
||||
state: EditorState::new(),
|
||||
events: Vec::new(),
|
||||
cursor: mouse::Cursor::Unavailable,
|
||||
events: initial_events,
|
||||
cursor: mouse::Cursor::Available(focus_point),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +142,10 @@ pub fn render(handle: &mut ViewportHandle) {
|
|||
|
||||
let logical_size = handle.viewport.logical_size();
|
||||
|
||||
handle
|
||||
.events
|
||||
.push(Event::Window(window::Event::RedrawRequested(Instant::now())));
|
||||
|
||||
let cache = std::mem::take(&mut handle.cache);
|
||||
let mut ui = UserInterface::build(
|
||||
handle.state.view(),
|
||||
|
|
@ -117,8 +154,8 @@ pub fn render(handle: &mut ViewportHandle) {
|
|||
&mut handle.renderer,
|
||||
);
|
||||
|
||||
let mut clipboard = clipboard::Null;
|
||||
let mut messages: Vec<()> = Vec::new();
|
||||
let mut clipboard = MacClipboard;
|
||||
let mut messages: Vec<Message> = Vec::new();
|
||||
|
||||
let _ = ui.update(
|
||||
&handle.events,
|
||||
|
|
@ -129,21 +166,31 @@ pub fn render(handle: &mut ViewportHandle) {
|
|||
);
|
||||
handle.events.clear();
|
||||
|
||||
let cache = ui.into_cache();
|
||||
|
||||
for msg in messages.drain(..) {
|
||||
handle.state.update(msg);
|
||||
}
|
||||
|
||||
let theme = Theme::Dark;
|
||||
let style = Style {
|
||||
text_color: Color::WHITE,
|
||||
};
|
||||
|
||||
let mut ui = UserInterface::build(
|
||||
handle.state.view(),
|
||||
Size::new(logical_size.width, logical_size.height),
|
||||
cache,
|
||||
&mut handle.renderer,
|
||||
);
|
||||
|
||||
ui.draw(&mut handle.renderer, &theme, &style, handle.cursor);
|
||||
handle.cache = ui.into_cache();
|
||||
|
||||
let bg = Color::from_rgb(0.08, 0.08, 0.10);
|
||||
handle.renderer.present(
|
||||
Some(bg),
|
||||
handle.format,
|
||||
&view,
|
||||
&handle.viewport,
|
||||
);
|
||||
handle
|
||||
.renderer
|
||||
.present(Some(bg), handle.format, &view, &handle.viewport);
|
||||
|
||||
frame.present();
|
||||
}
|
||||
|
|
@ -159,10 +206,7 @@ pub fn resize(handle: &mut ViewportHandle, width: f32, height: f32, scale: f32)
|
|||
handle.height = phys_h;
|
||||
handle.scale = scale;
|
||||
|
||||
handle.viewport = Viewport::with_physical_size(
|
||||
Size::new(phys_w, phys_h),
|
||||
scale,
|
||||
);
|
||||
handle.viewport = Viewport::with_physical_size(Size::new(phys_w, phys_h), scale);
|
||||
|
||||
handle.surface.configure(
|
||||
&handle.device,
|
||||
|
|
|
|||
Loading…
Reference in New Issue