Skip to content

Commit 21d7a90

Browse files
committed
🎉 improve the plugin list interface a bit
1 parent f7628a6 commit 21d7a90

File tree

5 files changed

+116
-52
lines changed

5 files changed

+116
-52
lines changed

editor/src/editorinterface.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ impl EditorState {
258258
let ctx = platform.context();
259259

260260
draw_editor_menu(self, &ctx);
261+
262+
if self.project.borrow().is_none() {
263+
draw_empty_screen(self, &ctx);
264+
}
265+
261266
draw_editor_console(self, &ctx);
262267
draw_editor_resources(self, painter, &ctx);
263268
draw_editor_watcher(self, &ctx);
@@ -266,10 +271,6 @@ impl EditorState {
266271
draw_editor_plugin_manager(self, &ctx);
267272
draw_editor_preferences(self, &ctx);
268273

269-
if self.project.borrow().is_none() {
270-
draw_empty_screen(self, &ctx);
271-
}
272-
273274
// Stop drawing the egui frame and get the full output
274275
let full_output = platform.end_frame(&mut self.video.borrow_mut());
275276
match full_output {

editor/src/editorinterface/editorplugins.rs

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use std::{borrow::Cow, fs};
22

3-
use egui_extras::{Column, TableBuilder};
3+
use egui_extras::{Column, TableBody, TableBuilder};
44
use runtime::egui;
55

66
use crate::{
7-
editorinterface::{EditorState, extra::geteditorpaths::get_editor_plugins_path},
7+
editorinterface::{
8+
EditorState,
9+
extra::geteditorpaths::{get_editor_plugins_path, get_end_of_path},
10+
},
811
pluginsystem::trustedplugin::{self, PluginEntry, TrustedPlugin},
912
};
1013

@@ -13,13 +16,18 @@ pub fn draw_editor_plugin_manager(editor: &mut EditorState, ctx: &egui::Context)
1316

1417
if editor.config.borrow().is_plugins_window_shown {
1518
let window = egui::Window::new("Plugin manager")
16-
.default_height(200.0)
17-
.default_width(300.0)
19+
.resizable(true)
20+
.default_height(300.0)
21+
.default_width(500.0)
1822
.open(&mut is_shown)
1923
.collapsible(false)
2024
.vscroll(false);
2125
let response = window.show(ctx, |ui| {
22-
draw_editor_plugin_manager_content(editor, ui);
26+
egui::ScrollArea::both()
27+
.auto_shrink([true; 2])
28+
.show(ui, |ui| {
29+
draw_editor_plugin_manager_content(editor, ui);
30+
});
2331
});
2432
if let Some(response) = response {
2533
let on_top = Some(response.response.layer_id) == ctx.top_layer_id();
@@ -34,8 +42,8 @@ pub fn draw_editor_plugin_manager(editor: &mut EditorState, ctx: &egui::Context)
3442

3543
fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::Ui) {
3644
ui.horizontal(|ui|{
37-
if ui.button("Open plugin folder")
38-
.on_hover_text("Open the folder where plugins are stored. You can add plugins there and they will appear in the list of available plugins.")
45+
if ui.button("Open plugins folder")
46+
.on_hover_text("Open the folder where plugins are stored. You can add plugins there and they will appear in the list of trusted plugins.")
3947
.clicked(){
4048
let plugin_library_path = get_editor_plugins_path();
4149
if !plugin_library_path.exists() {
@@ -54,15 +62,17 @@ fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::U
5462
if plugins.is_empty() {
5563
ui.label("No plugins found").on_hover_text("Plugins are programs that extend Vectarine's functionality. They are files ending with '.vecta.plugin'. You can download plugins or create them using the template provided by Vectarine GitHub repository.");
5664
} else {
65+
ui.heading("Trusted plugins").on_hover_text("Trusted plugins are the list of plugins known to the editor. Only trusted plugins of a game are loaded and executed. To be trusted, a plugin needs to be inside the plugins folder of the editor");
66+
5767
let available_height = ui.available_height();
5868
let table = TableBuilder::new(ui)
5969
.striped(true)
6070
.resizable(true)
61-
.auto_shrink(false)
71+
.auto_shrink(true)
6272
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
6373
.column(Column::auto()) // Name
64-
.column(Column::auto().at_most(100.0).clip(true)) // Path
65-
.column(Column::auto()) // About (description, version, url, errors, supported platforms, ...)
74+
.column(Column::auto().at_most(200.0).clip(true)) // Path
75+
.column(Column::auto().resizable(true)) // About (description, version, url, errors, supported platforms, ...)
6676
.column(Column::auto()) // Supported platforms
6777
.column(Column::auto()) // Actions
6878
.min_scrolled_height(0.0)
@@ -72,7 +82,7 @@ fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::U
7282
ui.label("Name");
7383
});
7484
header.col(|ui| {
75-
ui.label("Path");
85+
ui.label("Filename");
7686
});
7787
header.col(|ui| {
7888
ui.label("Description");
@@ -89,9 +99,7 @@ fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::U
8999
let row_height = 20.0;
90100
match plugin {
91101
PluginEntry::Trusted(trusted_plugin) => {
92-
body.row(row_height, |mut row| {
93-
draw_trusted_plugin_row(&mut row, trusted_plugin);
94-
});
102+
draw_trusted_plugin_row(&mut body, trusted_plugin);
95103
}
96104
PluginEntry::Malformed(malformed) => {
97105
let filename = malformed
@@ -104,7 +112,12 @@ fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::U
104112
ui.label(filename);
105113
});
106114
row.col(|ui| {
107-
ui.label(malformed.path.to_string_lossy());
115+
let path_shown = &malformed
116+
.path
117+
.file_name()
118+
.map(|p| p.display().to_string())
119+
.unwrap_or_else(|| get_end_of_path(&malformed.path));
120+
ui.label(path_shown);
108121
});
109122
row.col(|ui| {
110123
ui.label(&malformed.error);
@@ -121,28 +134,77 @@ fn draw_editor_plugin_manager_content(editor: &mut EditorState, ui: &mut egui::U
121134
}
122135
});
123136
}
137+
138+
ui.heading("Game plugins")
139+
.on_hover_text("Game plugins are the list of plugins belonging to the current game. Only trusted plugins are actually loaded and executed.");
140+
141+
let project = editor.project.borrow();
142+
if let Some(_project) = &project.as_ref() {
143+
if ui
144+
.button("Open game plugin folder")
145+
.on_hover_text("Open the folder with the plugins specific to your project")
146+
.clicked()
147+
{
148+
// ...
149+
}
150+
} else {
151+
ui.label("No project loaded")
152+
.on_hover_text("Load a project to see its plugins.");
153+
}
124154
}
125155

126-
fn draw_trusted_plugin_row(row: &mut egui_extras::TableRow, plugin: &mut TrustedPlugin) {
127-
row.col(|ui| {
128-
ui.label(&plugin.name);
129-
});
130-
row.col(|ui| {
131-
ui.label(plugin.path.to_string_lossy());
132-
});
133-
row.col(|ui| {
134-
ui.label(&plugin.description);
135-
});
136-
row.col(|ui| {
137-
let supported_platforms = plugin
138-
.supported_platforms
139-
.iter()
140-
.map(|platform| format!("{}", platform))
141-
.collect::<Vec<_>>()
142-
.join(", ");
143-
ui.label(supported_platforms);
156+
fn draw_trusted_plugin_row(body: &mut TableBody, plugin: &mut TrustedPlugin) {
157+
let ui = body.ui_mut();
158+
let font_id = egui::TextStyle::Body.resolve(ui.style());
159+
160+
let description_width = body.widths()[2];
161+
162+
let ui = body.ui_mut();
163+
let galley = ui.fonts(|f| {
164+
f.layout_job(egui::text::LayoutJob::simple(
165+
plugin.description.clone(),
166+
font_id,
167+
ui.visuals().text_color(),
168+
description_width,
169+
))
144170
});
145-
row.col(|ui| {
146-
ui.label("Actions");
171+
172+
let row_height = galley.size().y + 8.0;
173+
174+
body.row(row_height, |mut row| {
175+
row.col(|ui| {
176+
if ui.link(&plugin.name).on_hover_text(&plugin.url).clicked() {
177+
// For safety reasons, we're not opening a file
178+
if plugin.url.starts_with("http") {
179+
let _ = open::that(&plugin.url);
180+
}
181+
}
182+
});
183+
row.col(|ui| {
184+
let path_shown = &plugin
185+
.path
186+
.file_name()
187+
.map(|p| p.display().to_string())
188+
.unwrap_or_else(|| get_end_of_path(&plugin.path));
189+
ui.label(path_shown);
190+
});
191+
row.col(|ui| {
192+
let label = egui::Label::new(&plugin.description).wrap();
193+
ui.add(label);
194+
});
195+
row.col(|ui| {
196+
let supported_platforms = plugin
197+
.supported_platforms
198+
.iter()
199+
.map(|platform| format!("{}", platform))
200+
.collect::<Vec<_>>()
201+
.join(", ");
202+
ui.label(supported_platforms);
203+
});
204+
row.col(|ui| {
205+
if ui.button("Add to game").clicked() {
206+
// ...
207+
}
208+
});
147209
});
148210
}

editor/src/editorinterface/emptyscreen.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use runtime::{
1414

1515
use crate::editorinterface::{
1616
EditorState, emptyscreen::createproject::create_game_and_open_it,
17-
geteditorpaths::get_gallery_path,
17+
extra::geteditorpaths::get_end_of_path, geteditorpaths::get_gallery_path,
1818
};
1919

2020
pub mod createproject;
@@ -103,17 +103,6 @@ pub fn draw_empty_screen_window_content(
103103
});
104104
}
105105

106-
pub fn get_end_of_path(path: &Path) -> String {
107-
// Show last 5 components of the path.
108-
let components = path.components().collect::<Vec<_>>();
109-
let end_of_path = &components
110-
[std::cmp::max(0, components.len().saturating_sub(5))..components.len()]
111-
.iter()
112-
.map(|c| PathBuf::from(c.as_os_str()))
113-
.fold(PathBuf::new(), |a, b| a.join(b));
114-
format!("{}", end_of_path.display())
115-
}
116-
117106
pub fn draw_new_game_window_content(
118107
state: &mut EditorState,
119108
ui: &mut egui::Ui,

editor/src/editorinterface/extra/geteditorpaths.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,15 @@ pub static PLUGIN_FILE_EXTENSION: &str = ".vectaplugin";
125125
pub fn does_path_end_with(path: &Path, suffix: &str) -> bool {
126126
path.to_string_lossy().ends_with(suffix)
127127
}
128+
129+
/// Returns the last components of a path. Ideal for displaying long paths.
130+
pub fn get_end_of_path(path: &Path) -> String {
131+
// Show last 5 components of the path.
132+
let components = path.components().collect::<Vec<_>>();
133+
let end_of_path = &components
134+
[std::cmp::max(0, components.len().saturating_sub(5))..components.len()]
135+
.iter()
136+
.map(|c| PathBuf::from(c.as_os_str()))
137+
.fold(PathBuf::new(), |a, b| a.join(b));
138+
format!("{}", end_of_path.display())
139+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
name = "Plugin template"
22
description = """A demo plugin that squares a number."""
33
version = 1
4-
url = "https://github.com/vanyle/vectarine/"
4+
url = "https://github.com/vanyle/vectarine/tree/main/vectarine-plugin-template"

0 commit comments

Comments
 (0)