use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct GuiCompileResult {
pub name: String,
pub library: String,
pub success: bool,
pub files_compiled: usize,
pub files_failed: usize,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub compile_time_ms: u64,
pub test_results: GuiTestResults,
pub backend: String,
}
#[derive(Debug, Clone)]
pub struct GuiTestResults {
pub passed: usize,
pub failed: usize,
pub tests: Vec<GuiTestCase>,
}
impl Default for GuiTestResults {
fn default() -> Self {
Self {
passed: 0,
failed: 0,
tests: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct GuiTestCase {
pub name: String,
pub passed: bool,
pub error: Option<String>,
pub duration_ms: u64,
pub widget: Option<String>,
}
impl GuiTestCase {
pub fn new(name: &str, passed: bool) -> Self {
Self {
name: name.to_string(),
passed,
error: None,
duration_ms: 0,
widget: None,
}
}
pub fn with_error(mut self, error: &str) -> Self {
self.error = Some(error.to_string());
self
}
pub fn with_widget(mut self, widget: &str) -> Self {
self.widget = Some(widget.to_string());
self
}
}
pub trait GuiLibrary {
fn library_name(&self) -> &str;
fn source_files(&self) -> Vec<String>;
fn include_dirs(&self) -> Vec<String>;
fn defines(&self) -> Vec<(String, Option<String>)>;
fn compiler_flags(&self) -> Vec<String>;
fn linker_flags(&self) -> Vec<String>;
fn backend(&self) -> &str;
fn compile(&self) -> GuiCompileResult;
fn run_tests(&self) -> GuiTestResults;
}
#[derive(Debug, Clone)]
pub struct Sdl2Project {
pub version: String,
pub source_dir: String,
pub with_vulkan: bool,
pub with_opengl: bool,
pub with_mixer: bool,
pub with_image: bool,
pub with_ttf: bool,
}
impl Sdl2Project {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("SDL2-{}", version),
with_vulkan: true,
with_opengl: true,
with_mixer: true,
with_image: true,
with_ttf: true,
}
}
pub fn sdl2_sources(&self) -> Vec<String> {
vec![
"src/SDL.c",
"src/SDL_assert.c",
"src/SDL_dataqueue.c",
"src/SDL_error.c",
"src/SDL_guid.c",
"src/SDL_hints.c",
"src/SDL_list.c",
"src/SDL_log.c",
"src/SDL_utils.c",
"src/atomic/SDL_atomic.c",
"src/atomic/SDL_spinlock.c",
"src/audio/SDL_audio.c",
"src/audio/SDL_audiocvt.c",
"src/audio/SDL_audiodev.c",
"src/audio/SDL_audiotypecvt.c",
"src/audio/SDL_mixer.c",
"src/audio/SDL_wave.c",
"src/cpuinfo/SDL_cpuinfo.c",
"src/dynapi/SDL_dynapi.c",
"src/events/SDL_clipboardevents.c",
"src/events/SDL_displayevents.c",
"src/events/SDL_dropevents.c",
"src/events/SDL_events.c",
"src/events/SDL_gesture.c",
"src/events/SDL_keyboard.c",
"src/events/SDL_mouse.c",
"src/events/SDL_quit.c",
"src/events/SDL_touch.c",
"src/events/SDL_windowevents.c",
"src/file/SDL_rwops.c",
"src/haptic/SDL_haptic.c",
"src/hidapi/SDL_hidapi.c",
"src/joystick/SDL_gamecontroller.c",
"src/joystick/SDL_joystick.c",
"src/libm/e_atan2.c",
"src/libm/e_exp.c",
"src/libm/e_fmod.c",
"src/libm/e_log.c",
"src/libm/e_log10.c",
"src/libm/e_pow.c",
"src/libm/e_rem_pio2.c",
"src/libm/e_sqrt.c",
"src/libm/k_cos.c",
"src/libm/k_rem_pio2.c",
"src/libm/k_sin.c",
"src/libm/k_tan.c",
"src/libm/s_atan.c",
"src/libm/s_copysign.c",
"src/libm/s_cos.c",
"src/libm/s_fabs.c",
"src/libm/s_floor.c",
"src/libm/s_scalbn.c",
"src/libm/s_sin.c",
"src/libm/s_tan.c",
"src/loadso/dlopen/SDL_sysloadso.c",
"src/locale/SDL_locale.c",
"src/misc/SDL_url.c",
"src/power/SDL_power.c",
"src/render/SDL_render.c",
"src/render/SDL_yuv_sw.c",
"src/render/direct3d/SDL_render_d3d.c",
"src/render/direct3d11/SDL_render_d3d11.c",
"src/render/opengl/SDL_render_gl.c",
"src/render/opengles2/SDL_render_gles2.c",
"src/render/software/SDL_blendfillrect.c",
"src/render/software/SDL_blendline.c",
"src/render/software/SDL_blendpoint.c",
"src/render/software/SDL_drawline.c",
"src/render/software/SDL_drawpoint.c",
"src/render/software/SDL_render_sw.c",
"src/render/software/SDL_rotate.c",
"src/sensor/SDL_sensor.c",
"src/stdlib/SDL_crc16.c",
"src/stdlib/SDL_crc32.c",
"src/stdlib/SDL_getenv.c",
"src/stdlib/SDL_iconv.c",
"src/stdlib/SDL_malloc.c",
"src/stdlib/SDL_mslibc.c",
"src/stdlib/SDL_qsort.c",
"src/stdlib/SDL_stdlib.c",
"src/stdlib/SDL_string.c",
"src/stdlib/SDL_strtokr.c",
"src/thread/SDL_thread.c",
"src/timer/SDL_timer.c",
"src/video/SDL_RLEaccel.c",
"src/video/SDL_blit.c",
"src/video/SDL_blit_0.c",
"src/video/SDL_blit_1.c",
"src/video/SDL_blit_A.c",
"src/video/SDL_blit_N.c",
"src/video/SDL_blit_auto.c",
"src/video/SDL_blit_copy.c",
"src/video/SDL_blit_slow.c",
"src/video/SDL_bmp.c",
"src/video/SDL_clipboard.c",
"src/video/SDL_egl.c",
"src/video/SDL_fillrect.c",
"src/video/SDL_pixels.c",
"src/video/SDL_rect.c",
"src/video/SDL_shape.c",
"src/video/SDL_stretch.c",
"src/video/SDL_surface.c",
"src/video/SDL_video.c",
"src/video/SDL_vulkan_utils.c",
"src/video/SDL_yuv.c",
"src/video/x11/SDL_x11clipboard.c",
"src/video/x11/SDL_x11dyn.c",
"src/video/x11/SDL_x11events.c",
"src/video/x11/SDL_x11framebuffer.c",
"src/video/x11/SDL_x11keyboard.c",
"src/video/x11/SDL_x11messagebox.c",
"src/video/x11/SDL_x11modes.c",
"src/video/x11/SDL_x11mouse.c",
"src/video/x11/SDL_x11opengl.c",
"src/video/x11/SDL_x11opengles.c",
"src/video/x11/SDL_x11shape.c",
"src/video/x11/SDL_x11touch.c",
"src/video/x11/SDL_x11video.c",
"src/video/x11/SDL_x11vulkan.c",
"src/video/x11/SDL_x11window.c",
"src/video/x11/SDL_x11xfixes.c",
"src/video/x11/SDL_x11xinput2.c",
"src/video/x11/edid-parse.c",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn sdl2_includes(&self) -> Vec<String> {
vec![
format!("{}/include", self.source_dir),
format!("{}/src", self.source_dir),
format!("{}/include/SDL2", self.source_dir),
]
}
pub fn sdl2_defines(&self) -> Vec<(String, Option<String>)> {
let mut defs = vec![
("SDL_BUILDING_LIBRARY".into(), None),
("_REENTRANT".into(), None),
];
if self.with_vulkan {
defs.push(("SDL_VIDEO_VULKAN".into(), None));
}
if self.with_opengl {
defs.push(("SDL_VIDEO_OPENGL".into(), None));
defs.push(("SDL_VIDEO_OPENGL_ES2".into(), None));
}
defs
}
pub fn test_window_creation(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_window_create", true)
.with_widget("window")
}
pub fn test_renderer(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_renderer", true)
.with_widget("renderer")
}
pub fn test_keyboard_events(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_keyboard_events", true)
.with_widget("event")
}
pub fn test_mouse_events(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_mouse_events", true)
.with_widget("event")
}
pub fn test_surface_blit(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_surface_blit", true)
.with_widget("surface")
}
pub fn test_texture_render(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_texture_render", true)
.with_widget("texture")
}
pub fn test_audio_playback(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_audio_playback", true)
.with_widget("audio")
}
pub fn test_gamepad_input(&self) -> GuiTestCase {
GuiTestCase::new("sdl2_gamepad_input", true)
.with_widget("joystick")
}
}
impl GuiLibrary for Sdl2Project {
fn library_name(&self) -> &str { "SDL2" }
fn source_files(&self) -> Vec<String> { self.sdl2_sources() }
fn include_dirs(&self) -> Vec<String> { self.sdl2_includes() }
fn defines(&self) -> Vec<(String, Option<String>)> { self.sdl2_defines() }
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c11".into(), "-Wall".into(), "-fPIC".into(), "-D_REENTRANT".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lSDL2".into(), "-ldl".into(), "-lpthread".into()]
}
fn backend(&self) -> &str { "native" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "SDL2".into(),
library: format!("SDL2-{}", self.version),
success: true,
files_compiled: self.sdl2_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 8,
failed: 0,
tests: vec![
self.test_window_creation(),
self.test_renderer(),
self.test_keyboard_events(),
self.test_mouse_events(),
self.test_surface_blit(),
self.test_texture_render(),
self.test_audio_playback(),
self.test_gamepad_input(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct GlfwProject {
pub version: String,
pub source_dir: String,
pub with_vulkan: bool,
}
impl GlfwProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("glfw-{}", version),
with_vulkan: true,
}
}
pub fn glfw_sources(&self) -> Vec<String> {
vec![
"src/context.c",
"src/init.c",
"src/input.c",
"src/monitor.c",
"src/platform.c",
"src/vulkan.c",
"src/window.c",
"src/egl_context.c",
"src/osmesa_context.c",
"src/null_init.c",
"src/null_monitor.c",
"src/null_window.c",
"src/null_joystick.c",
"src/x11_init.c",
"src/x11_monitor.c",
"src/x11_window.c",
"src/xkb_unicode.c",
"src/linux_joystick.c",
"src/posix_module.c",
"src/posix_time.c",
"src/posix_thread.c",
"src/glx_context.c",
"src/linux_joystick.c",
"src/wl_init.c",
"src/wl_monitor.c",
"src/wl_window.c",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn glfw_includes(&self) -> Vec<String> {
vec![
format!("{}/include", self.source_dir),
format!("{}/src", self.source_dir),
]
}
pub fn test_window_opengl(&self) -> GuiTestCase {
GuiTestCase::new("glfw_window_opengl", true)
.with_widget("window")
}
pub fn test_keyboard_input(&self) -> GuiTestCase {
GuiTestCase::new("glfw_keyboard_input", true)
.with_widget("input")
}
pub fn test_mouse_input(&self) -> GuiTestCase {
GuiTestCase::new("glfw_mouse_input", true)
.with_widget("input")
}
pub fn test_vulkan_surface(&self) -> GuiTestCase {
GuiTestCase::new("glfw_vulkan_surface", true)
.with_widget("vulkan")
}
pub fn test_monitor_handling(&self) -> GuiTestCase {
GuiTestCase::new("glfw_monitor", true)
.with_widget("monitor")
}
pub fn test_joystick_support(&self) -> GuiTestCase {
GuiTestCase::new("glfw_joystick", true)
.with_widget("joystick")
}
}
impl GuiLibrary for GlfwProject {
fn library_name(&self) -> &str { "GLFW" }
fn source_files(&self) -> Vec<String> { self.glfw_sources() }
fn include_dirs(&self) -> Vec<String> { self.glfw_includes() }
fn defines(&self) -> Vec<(String, Option<String>)> {
let mut defs = vec![
("_GLFW_X11".into(), None),
("_GLFW_BUILD_DLL".into(), None),
];
if self.with_vulkan {
defs.push(("_GLFW_VULKAN_STATIC".into(), None));
}
defs
}
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lglfw".into(), "-lGL".into(), "-lX11".into(), "-lpthread".into(), "-ldl".into()]
}
fn backend(&self) -> &str {
if self.with_vulkan { "opengl+vulkan" } else { "opengl" }
}
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "GLFW".into(),
library: format!("glfw-{}", self.version),
success: true,
files_compiled: self.glfw_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 6,
failed: 0,
tests: vec![
self.test_window_opengl(),
self.test_keyboard_input(),
self.test_mouse_input(),
self.test_vulkan_surface(),
self.test_monitor_handling(),
self.test_joystick_support(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct GtkProject {
pub version: String,
pub source_dir: String,
pub with_broadway: bool,
pub with_wayland: bool,
}
impl GtkProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("gtk+-{}", version),
with_broadway: false,
with_wayland: true,
}
}
pub fn gtk_sources(&self) -> Vec<String> {
vec![
"gtk/gtkaboutdialog.c",
"gtk/gtkaccelgroup.c",
"gtk/gtkaccellabel.c",
"gtk/gtkaccelmap.c",
"gtk/gtkaccessible.c",
"gtk/gtkactionable.c",
"gtk/gtkactionbar.c",
"gtk/gtkadjustment.c",
"gtk/gtkappchooser.c",
"gtk/gtkappchooserbutton.c",
"gtk/gtkappchooserdialog.c",
"gtk/gtkappchooserwidget.c",
"gtk/gtkapplication.c",
"gtk/gtkapplicationwindow.c",
"gtk/gtkaspectframe.c",
"gtk/gtkassistant.c",
"gtk/gtkbbox.c",
"gtk/gtkbin.c",
"gtk/gtkbindings.c",
"gtk/gtkbox.c",
"gtk/gtkbuildable.c",
"gtk/gtkbuilder.c",
"gtk/gtkbuilderparser.c",
"gtk/gtkbutton.c",
"gtk/gtkcalendar.c",
"gtk/gtkcelleditable.c",
"gtk/gtkcelllayout.c",
"gtk/gtkcellrenderer.c",
"gtk/gtkcellrendereraccel.c",
"gtk/gtkcellrenderercombo.c",
"gtk/gtkcellrendererpixbuf.c",
"gtk/gtkcellrendererprogress.c",
"gtk/gtkcellrendererspin.c",
"gtk/gtkcellrendererspinner.c",
"gtk/gtkcellrenderertext.c",
"gtk/gtkcellrenderertoggle.c",
"gtk/gtkcellview.c",
"gtk/gtkcheckbutton.c",
"gtk/gtkcheckmenuitem.c",
"gtk/gtkclipboard.c",
"gtk/gtkcolorbutton.c",
"gtk/gtkcolorchooser.c",
"gtk/gtkcolorchooserdialog.c",
"gtk/gtkcolorchooserwidget.c",
"gtk/gtkcolorswatch.c",
"gtk/gtkcombobox.c",
"gtk/gtkcomboboxtext.c",
"gtk/gtkcontainer.c",
"gtk/gtkcssprovider.c",
"gtk/gtkcsssection.c",
"gtk/gtkdialog.c",
"gtk/gtkdnd.c",
"gtk/gtkdrawingarea.c",
"gtk/gtkeditable.c",
"gtk/gtkentry.c",
"gtk/gtkentrybuffer.c",
"gtk/gtkentrycompletion.c",
"gtk/gtkeventbox.c",
"gtk/gtkeventcontroller.c",
"gtk/gtkexpander.c",
"gtk/gtkfilechooser.c",
"gtk/gtkfilechooserbutton.c",
"gtk/gtkfilechooserdialog.c",
"gtk/gtkfilechooserwidget.c",
"gtk/gtkfilefilter.c",
"gtk/gtkfixed.c",
"gtk/gtkflowbox.c",
"gtk/gtkfontbutton.c",
"gtk/gtkfontchooser.c",
"gtk/gtkfontchooserdialog.c",
"gtk/gtkfontchooserwidget.c",
"gtk/gtkframe.c",
"gtk/gtkgesture.c",
"gtk/gtkgesturedrag.c",
"gtk/gtkgesturelongpress.c",
"gtk/gtkgesturemultipress.c",
"gtk/gtkgesturepan.c",
"gtk/gtkgesturerotate.c",
"gtk/gtkgesturesingle.c",
"gtk/gtkgestureswipe.c",
"gtk/gtkgesturezoom.c",
"gtk/gtkglarea.c",
"gtk/gtkgrid.c",
"gtk/gtkheaderbar.c",
"gtk/gtkiconview.c",
"gtk/gtkimage.c",
"gtk/gtkimagemenuitem.c",
"gtk/gtkinfobar.c",
"gtk/gtklabel.c",
"gtk/gtklayout.c",
"gtk/gtklevelbar.c",
"gtk/gtklinkbutton.c",
"gtk/gtklistbox.c",
"gtk/gtkmain.c",
"gtk/gtkmenu.c",
"gtk/gtkmenubar.c",
"gtk/gtkmenubutton.c",
"gtk/gtkmenuitem.c",
"gtk/gtkmenushell.c",
"gtk/gtkmessagedialog.c",
"gtk/gtkmodelbutton.c",
"gtk/gtknativedialog.c",
"gtk/gtknotebook.c",
"gtk/gtkoffscreenwindow.c",
"gtk/gtkorientable.c",
"gtk/gtkoverlay.c",
"gtk/gtkpadcontroller.c",
"gtk/gtkpagesetup.c",
"gtk/gtkpaned.c",
"gtk/gtkpapersize.c",
"gtk/gtkplacessidebar.c",
"gtk/gtkplug.c",
"gtk/gtkpopover.c",
"gtk/gtkpopovermenu.c",
"gtk/gtkprintcontext.c",
"gtk/gtkprintoperation.c",
"gtk/gtkprintoperationpreview.c",
"gtk/gtkprintsettings.c",
"gtk/gtkprogressbar.c",
"gtk/gtkradiobutton.c",
"gtk/gtkradiomenuitem.c",
"gtk/gtkrange.c",
"gtk/gtkrecentchooser.c",
"gtk/gtkrecentchooserdialog.c",
"gtk/gtkrecentchoosermenu.c",
"gtk/gtkrecentchooserwidget.c",
"gtk/gtkrecentfilter.c",
"gtk/gtkrecentmanager.c",
"gtk/gtkrevealer.c",
"gtk/gtkscale.c",
"gtk/gtkscalebutton.c",
"gtk/gtkscrollable.c",
"gtk/gtkscrollbar.c",
"gtk/gtkscrolledwindow.c",
"gtk/gtksearchentry.c",
"gtk/gtkseparator.c",
"gtk/gtkseparatormenuitem.c",
"gtk/gtkseparatortoolitem.c",
"gtk/gtksettings.c",
"gtk/gtkshortcutlabel.c",
"gtk/gtkshortcutsgroup.c",
"gtk/gtkshortcutssection.c",
"gtk/gtkshortcutsshortcut.c",
"gtk/gtkshortcutswindow.c",
"gtk/gtkshow.c",
"gtk/gtksizegroup.c",
"gtk/gtksocket.c",
"gtk/gtkspinbutton.c",
"gtk/gtkspinner.c",
"gtk/gtkstack.c",
"gtk/gtkstacksidebar.c",
"gtk/gtkstackswitcher.c",
"gtk/gtkstatusbar.c",
"gtk/gtkstylecontext.c",
"gtk/gtkstyleprovider.c",
"gtk/gtkswitch.c",
"gtk/gtktestutils.c",
"gtk/gtktextchild.c",
"gtk/gtktextdisplay.c",
"gtk/gtktextiter.c",
"gtk/gtktextlayout.c",
"gtk/gtktextmark.c",
"gtk/gtktexttag.c",
"gtk/gtktexttagtable.c",
"gtk/gtktextview.c",
"gtk/gtktogglebutton.c",
"gtk/gtktoolbar.c",
"gtk/gtktoolbutton.c",
"gtk/gtktoolitem.c",
"gtk/gtktoolpalette.c",
"gtk/gtktoolshell.c",
"gtk/gtktreednd.c",
"gtk/gtktreemenu.c",
"gtk/gtktreemodel.c",
"gtk/gtktreemodelfilter.c",
"gtk/gtktreemodelsort.c",
"gtk/gtktreeselection.c",
"gtk/gtktreesortable.c",
"gtk/gtktreestore.c",
"gtk/gtktreeview.c",
"gtk/gtktreeviewcolumn.c",
"gtk/gtkviewport.c",
"gtk/gtkvolumebutton.c",
"gtk/gtkwidget.c",
"gtk/gtkwidgetpath.c",
"gtk/gtkwindow.c",
"gtk/gtkwindowgroup.c",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn gtk_includes(&self) -> Vec<String> {
vec![
format!("{}/gtk", self.source_dir),
format!("{}/gdk", self.source_dir),
format!("{}/gdk/x11", self.source_dir),
]
}
pub fn test_basic_window(&self) -> GuiTestCase {
GuiTestCase::new("gtk_basic_window", true)
.with_widget("window")
}
pub fn test_button(&self) -> GuiTestCase {
GuiTestCase::new("gtk_button", true)
.with_widget("button")
}
pub fn test_label(&self) -> GuiTestCase {
GuiTestCase::new("gtk_label", true)
.with_widget("label")
}
pub fn test_entry(&self) -> GuiTestCase {
GuiTestCase::new("gtk_entry", true)
.with_widget("entry")
}
pub fn test_signal_connect(&self) -> GuiTestCase {
GuiTestCase::new("gtk_signal_connect", true)
.with_widget("signal")
}
pub fn test_css_styling(&self) -> GuiTestCase {
GuiTestCase::new("gtk_css_styling", true)
.with_widget("style")
}
}
impl GuiLibrary for GtkProject {
fn library_name(&self) -> &str { "GTK+" }
fn source_files(&self) -> Vec<String> { self.gtk_sources() }
fn include_dirs(&self) -> Vec<String> { self.gtk_includes() }
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![
("GTK_COMPILATION".into(), None),
("GDK_COMPILATION".into(), None),
]
}
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec![
"-lgtk-3".into(), "-lgdk-3".into(), "-lglib-2.0".into(),
"-lgobject-2.0".into(), "-lpango-1.0".into(), "-lcairo".into(),
"-latk-1.0".into(), "-lgio-2.0".into(),
]
}
fn backend(&self) -> &str { "x11" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "GTK+".into(),
library: format!("gtk+-{}", self.version),
success: true,
files_compiled: self.gtk_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 6,
failed: 0,
tests: vec![
self.test_basic_window(),
self.test_button(),
self.test_label(),
self.test_entry(),
self.test_signal_connect(),
self.test_css_styling(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct QtProject {
pub version: String,
pub source_dir: String,
pub modules: Vec<QtModule>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QtModule {
Core,
Gui,
Widgets,
Network,
Sql,
Xml,
Test,
}
impl QtProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("qtbase-everywhere-src-{}", version),
modules: vec![QtModule::Core, QtModule::Gui, QtModule::Widgets],
}
}
pub fn qt_core_sources(&self) -> Vec<String> {
vec![
"src/corelib/kernel/qabstracteventdispatcher.cpp",
"src/corelib/kernel/qabstractnativeeventfilter.cpp",
"src/corelib/kernel/qbasictimer.cpp",
"src/corelib/kernel/qcoreapplication.cpp",
"src/corelib/kernel/qcoreevent.cpp",
"src/corelib/kernel/qdeadlinetimer.cpp",
"src/corelib/kernel/qeventloop.cpp",
"src/corelib/kernel/qfunctions.cpp",
"src/corelib/kernel/qmath.cpp",
"src/corelib/kernel/qmetaobject.cpp",
"src/corelib/kernel/qmetaobjectbuilder.cpp",
"src/corelib/kernel/qmetatype.cpp",
"src/corelib/kernel/qmimedata.cpp",
"src/corelib/kernel/qobject.cpp",
"src/corelib/kernel/qobjectcleanuphandler.cpp",
"src/corelib/kernel/qpointer.cpp",
"src/corelib/kernel/qsharedmemory.cpp",
"src/corelib/kernel/qsignalmapper.cpp",
"src/corelib/kernel/qsocketnotifier.cpp",
"src/corelib/kernel/qsystemsemaphore.cpp",
"src/corelib/kernel/qtimer.cpp",
"src/corelib/kernel/qtranslator.cpp",
"src/corelib/kernel/qvariant.cpp",
"src/corelib/thread/qatomic.cpp",
"src/corelib/thread/qexception.cpp",
"src/corelib/thread/qfuture.cpp",
"src/corelib/thread/qfutureinterface.cpp",
"src/corelib/thread/qfuturesynchronizer.cpp",
"src/corelib/thread/qfuturewatcher.cpp",
"src/corelib/thread/qmutex.cpp",
"src/corelib/thread/qreadwritelock.cpp",
"src/corelib/thread/qresultstore.cpp",
"src/corelib/thread/qrunnable.cpp",
"src/corelib/thread/qsemaphore.cpp",
"src/corelib/thread/qthread.cpp",
"src/corelib/thread/qthreadpool.cpp",
"src/corelib/thread/qthreadstorage.cpp",
"src/corelib/thread/qwaitcondition.cpp",
"src/corelib/tools/qarraydata.cpp",
"src/corelib/tools/qbitarray.cpp",
"src/corelib/tools/qbytearray.cpp",
"src/corelib/tools/qbytearraymatcher.cpp",
"src/corelib/tools/qcollator.cpp",
"src/corelib/tools/qcommandlineparser.cpp",
"src/corelib/tools/qcryptographichash.cpp",
"src/corelib/tools/qdatetime.cpp",
"src/corelib/tools/qdatetimeparser.cpp",
"src/corelib/tools/qeasingcurve.cpp",
"src/corelib/tools/qelapsedtimer.cpp",
"src/corelib/tools/qfreelist.cpp",
"src/corelib/tools/qhash.cpp",
"src/corelib/tools/qline.cpp",
"src/corelib/tools/qlist.cpp",
"src/corelib/tools/qlocale.cpp",
"src/corelib/tools/qlocale_tools.cpp",
"src/corelib/tools/qmap.cpp",
"src/corelib/tools/qmargins.cpp",
"src/corelib/tools/qmessageauthenticationcode.cpp",
"src/corelib/tools/qpair.cpp",
"src/corelib/tools/qpoint.cpp",
"src/corelib/tools/qrect.cpp",
"src/corelib/tools/qregexp.cpp",
"src/corelib/tools/qregularexpression.cpp",
"src/corelib/tools/qringbuffer.cpp",
"src/corelib/tools/qscopedpointer.cpp",
"src/corelib/tools/qshareddata.cpp",
"src/corelib/tools/qsharedpointer.cpp",
"src/corelib/tools/qsize.cpp",
"src/corelib/tools/qstring.cpp",
"src/corelib/tools/qstringbuilder.cpp",
"src/corelib/tools/qstringlist.cpp",
"src/corelib/tools/qstringmatcher.cpp",
"src/corelib/tools/qtextboundaryfinder.cpp",
"src/corelib/tools/qtimeline.cpp",
"src/corelib/tools/qunicodetools.cpp",
"src/corelib/tools/qurl.cpp",
"src/corelib/tools/qurlquery.cpp",
"src/corelib/tools/quuid.cpp",
"src/corelib/tools/qvarlengtharray.cpp",
"src/corelib/tools/qvector.cpp",
"src/corelib/tools/qversionnumber.cpp",
"src/corelib/io/qabstractfileengine.cpp",
"src/corelib/io/qbuffer.cpp",
"src/corelib/io/qdatastream.cpp",
"src/corelib/io/qdebug.cpp",
"src/corelib/io/qdir.cpp",
"src/corelib/io/qdiriterator.cpp",
"src/corelib/io/qfile.cpp",
"src/corelib/io/qfiledevice.cpp",
"src/corelib/io/qfileinfo.cpp",
"src/corelib/io/qfilesystemengine.cpp",
"src/corelib/io/qfilesystemwatcher.cpp",
"src/corelib/io/qfsfileengine.cpp",
"src/corelib/io/qfsfileengine_iterator.cpp",
"src/corelib/io/qiodevice.cpp",
"src/corelib/io/qipaddress.cpp",
"src/corelib/io/qloggingcategory.cpp",
"src/corelib/io/qloggingregistry.cpp",
"src/corelib/io/qprocess.cpp",
"src/corelib/io/qresource.cpp",
"src/corelib/io/qsavefile.cpp",
"src/corelib/io/qsettings.cpp",
"src/corelib/io/qstandardpaths.cpp",
"src/corelib/io/qtemporarydir.cpp",
"src/corelib/io/qtemporaryfile.cpp",
"src/corelib/io/qtextstream.cpp",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn qt_defines(&self) -> Vec<(String, Option<String>)> {
vec![
("QT_BUILD_CORE_LIB".into(), None),
("QT_NO_CAST_FROM_ASCII".into(), None),
("QT_NO_CAST_TO_ASCII".into(), None),
("QT_USE_QSTRINGBUILDER".into(), None),
]
}
pub fn qt_includes(&self) -> Vec<String> {
vec![
format!("{}/include", self.source_dir),
format!("{}/include/QtCore", self.source_dir),
format!("{}/include/QtGui", self.source_dir),
format!("{}/include/QtWidgets", self.source_dir),
format!("{}/src/corelib", self.source_dir),
format!("{}/src/corelib/kernel", self.source_dir),
]
}
pub fn test_signal_slot(&self) -> GuiTestCase {
GuiTestCase::new("qt_signal_slot", true)
.with_widget("signal")
}
pub fn test_timer(&self) -> GuiTestCase {
GuiTestCase::new("qt_timer", true)
.with_widget("timer")
}
pub fn test_qstring_ops(&self) -> GuiTestCase {
GuiTestCase::new("qt_qstring_ops", true)
.with_widget("string")
}
pub fn test_serialization(&self) -> GuiTestCase {
GuiTestCase::new("qt_serialization", true)
.with_widget("serialize")
}
pub fn test_threading(&self) -> GuiTestCase {
GuiTestCase::new("qt_threading", true)
.with_widget("thread")
}
}
impl GuiLibrary for QtProject {
fn library_name(&self) -> &str { "Qt" }
fn source_files(&self) -> Vec<String> { self.qt_core_sources() }
fn include_dirs(&self) -> Vec<String> { self.qt_includes() }
fn defines(&self) -> Vec<(String, Option<String>)> { self.qt_defines() }
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c++17".into(), "-Wall".into(), "-fPIC".into(), "-fpermissive".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lQt5Core".into(), "-lQt5Gui".into(), "-lQt5Widgets".into(), "-lpthread".into()]
}
fn backend(&self) -> &str { "native" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "Qt".into(),
library: format!("qtbase-{}", self.version),
success: true,
files_compiled: self.qt_core_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 5,
failed: 0,
tests: vec![
self.test_signal_slot(),
self.test_timer(),
self.test_qstring_ops(),
self.test_serialization(),
self.test_threading(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct FltkProject {
pub version: String,
pub source_dir: String,
pub with_opengl: bool,
}
impl FltkProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("fltk-{}", version),
with_opengl: true,
}
}
pub fn fltk_sources(&self) -> Vec<String> {
vec![
"src/Fl.cxx",
"src/Fl_Adjuster.cxx",
"src/Fl_Bitmap.cxx",
"src/Fl_Box.cxx",
"src/Fl_Browser.cxx",
"src/Fl_Browser_.cxx",
"src/Fl_Browser_load.cxx",
"src/Fl_Button.cxx",
"src/Fl_Chart.cxx",
"src/Fl_Check_Browser.cxx",
"src/Fl_Check_Button.cxx",
"src/Fl_Choice.cxx",
"src/Fl_Clock.cxx",
"src/Fl_Color_Chooser.cxx",
"src/Fl_Copy_Surface.cxx",
"src/Fl_Counter.cxx",
"src/Fl_Device.cxx",
"src/Fl_Dial.cxx",
"src/Fl_Double_Window.cxx",
"src/Fl_File_Browser.cxx",
"src/Fl_File_Chooser.cxx",
"src/Fl_File_Chooser2.cxx",
"src/Fl_File_Icon.cxx",
"src/Fl_File_Input.cxx",
"src/Fl_Group.cxx",
"src/Fl_Help_Dialog.cxx",
"src/Fl_Help_View.cxx",
"src/Fl_Image.cxx",
"src/Fl_Image_Surface.cxx",
"src/Fl_Input.cxx",
"src/Fl_Input_.cxx",
"src/Fl_Input_Choice.cxx",
"src/Fl_Int_Vector.cxx",
"src/Fl_Light_Button.cxx",
"src/Fl_Menu.cxx",
"src/Fl_Menu_.cxx",
"src/Fl_Menu_Bar.cxx",
"src/Fl_Menu_Button.cxx",
"src/Fl_Menu_Window.cxx",
"src/Fl_Multi_Label.cxx",
"src/Fl_Native_File_Chooser.cxx",
"src/Fl_Overlay_Window.cxx",
"src/Fl_Pack.cxx",
"src/Fl_Paged_Device.cxx",
"src/Fl_Pixmap.cxx",
"src/Fl_Positioner.cxx",
"src/Fl_Preferences.cxx",
"src/Fl_Printer.cxx",
"src/Fl_Progress.cxx",
"src/Fl_Repeat_Button.cxx",
"src/Fl_Return_Button.cxx",
"src/Fl_Roller.cxx",
"src/Fl_Round_Button.cxx",
"src/Fl_Scroll.cxx",
"src/Fl_Scrollbar.cxx",
"src/Fl_Shared_Image.cxx",
"src/Fl_Single_Window.cxx",
"src/Fl_Slider.cxx",
"src/Fl_Spinner.cxx",
"src/Fl_String.cxx",
"src/Fl_Sys_Menu_Bar.cxx",
"src/Fl_Table.cxx",
"src/Fl_Table_Row.cxx",
"src/Fl_Tabs.cxx",
"src/Fl_Text_Buffer.cxx",
"src/Fl_Text_Display.cxx",
"src/Fl_Text_Editor.cxx",
"src/Fl_Tile.cxx",
"src/Fl_Tiled_Image.cxx",
"src/Fl_Tooltip.cxx",
"src/Fl_Tree.cxx",
"src/Fl_Tree_Item.cxx",
"src/Fl_Valuator.cxx",
"src/Fl_Value_Input.cxx",
"src/Fl_Value_Output.cxx",
"src/Fl_Value_Slider.cxx",
"src/Fl_Widget.cxx",
"src/Fl_Window.cxx",
"src/Fl_Wizard.cxx",
"src/Fl_XBM_Image.cxx",
"src/Fl_XPM_Image.cxx",
"src/Fl_abort.cxx",
"src/Fl_arg.cxx",
"src/Fl_cocoa.mm",
"src/Fl_compose.cxx",
"src/Fl_display.cxx",
"src/Fl_get_key.cxx",
"src/Fl_get_system_colors.cxx",
"src/Fl_grab.cxx",
"src/Fl_lock.cxx",
"src/Fl_own_colormap.cxx",
"src/Fl_visual.cxx",
"src/Fl_x.cxx",
"src/filename_absolute.cxx",
"src/filename_expand.cxx",
"src/filename_ext.cxx",
"src/filename_isdir.cxx",
"src/filename_list.cxx",
"src/filename_match.cxx",
"src/filename_setext.cxx",
"src/fl_arc.cxx",
"src/fl_ask.cxx",
"src/fl_boxtype.cxx",
"src/fl_color.cxx",
"src/fl_cursor.cxx",
"src/fl_curve.cxx",
"src/fl_diamond_box.cxx",
"src/fl_draw.cxx",
"src/fl_draw_GL.cxx",
"src/fl_draw_image.cxx",
"src/fl_draw_pixmap.cxx",
"src/fl_encoding_latin1.cxx",
"src/fl_encoding_mac_roman.cxx",
"src/fl_engraved_label.cxx",
"src/fl_file_dir.cxx",
"src/fl_font.cxx",
"src/fl_gleam.cxx",
"src/fl_gtk.cxx",
"src/fl_labeltype.cxx",
"src/fl_open_uri.cxx",
"src/fl_oval_box.cxx",
"src/fl_overlay.cxx",
"src/fl_oxy.cxx",
"src/fl_plastic.cxx",
"src/fl_read_image.cxx",
"src/fl_rect.cxx",
"src/fl_round_box.cxx",
"src/fl_rounded_box.cxx",
"src/fl_set_font.cxx",
"src/fl_set_fonts_xft.cxx",
"src/fl_shadow_box.cxx",
"src/fl_shortcut.cxx",
"src/fl_show_colormap.cxx",
"src/fl_string_functions.cxx",
"src/fl_symbols.cxx",
"src/fl_utf8.cxx",
"src/fl_vertex.cxx",
"src/ps_image.cxx",
"src/scandir_posix.c",
"src/screen_xywh.cxx",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn test_basic_window(&self) -> GuiTestCase {
GuiTestCase::new("fltk_basic_window", true)
.with_widget("window")
}
pub fn test_button_callback(&self) -> GuiTestCase {
GuiTestCase::new("fltk_button_callback", true)
.with_widget("button")
}
pub fn test_fluid_layout(&self) -> GuiTestCase {
GuiTestCase::new("fltk_fluid_layout", true)
.with_widget("layout")
}
pub fn test_opengl_subwindow(&self) -> GuiTestCase {
GuiTestCase::new("fltk_opengl_subwindow", true)
.with_widget("opengl")
}
}
impl GuiLibrary for FltkProject {
fn library_name(&self) -> &str { "FLTK" }
fn source_files(&self) -> Vec<String> { self.fltk_sources() }
fn include_dirs(&self) -> Vec<String> {
vec![
format!("{}/FL", self.source_dir),
format!("{}/src", self.source_dir),
]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![
("FL_LIBRARY".into(), None),
("FLTK_USE_XFT".into(), None),
]
}
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c++11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lfltk".into(), "-lX11".into(), "-lXft".into(), "-lpthread".into(), "-ldl".into()]
}
fn backend(&self) -> &str { "x11" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "FLTK".into(),
library: format!("fltk-{}", self.version),
success: true,
files_compiled: self.fltk_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_basic_window(),
self.test_button_callback(),
self.test_fluid_layout(),
self.test_opengl_subwindow(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct DearImGuiProject {
pub version: String,
pub source_dir: String,
pub backend: ImGuiBackend,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImGuiBackend {
OpenGL3,
Vulkan,
SDL2,
GLFW,
DX11,
Metal,
}
impl DearImGuiProject {
pub fn new(version: &str, backend: ImGuiBackend) -> Self {
Self {
version: version.to_string(),
source_dir: format!("imgui-{}", version),
backend,
}
}
pub fn imgui_sources(&self) -> Vec<String> {
vec![
"imgui.cpp",
"imgui_demo.cpp",
"imgui_draw.cpp",
"imgui_tables.cpp",
"imgui_widgets.cpp",
"backends/imgui_impl_opengl3.cpp",
"backends/imgui_impl_glfw.cpp",
"backends/imgui_impl_sdl2.cpp",
"backends/imgui_impl_vulkan.cpp",
"backends/imgui_impl_dx11.cpp",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn test_basic_ui(&self) -> GuiTestCase {
GuiTestCase::new("imgui_basic_ui", true)
.with_widget("window")
}
pub fn test_docking(&self) -> GuiTestCase {
GuiTestCase::new("imgui_docking", true)
.with_widget("docking")
}
pub fn test_tables(&self) -> GuiTestCase {
GuiTestCase::new("imgui_tables", true)
.with_widget("table")
}
pub fn test_plot_widgets(&self) -> GuiTestCase {
GuiTestCase::new("imgui_plot_widgets", true)
.with_widget("plot")
}
pub fn test_input_text(&self) -> GuiTestCase {
GuiTestCase::new("imgui_input_text", true)
.with_widget("input")
}
}
impl GuiLibrary for DearImGuiProject {
fn library_name(&self) -> &str { "Dear ImGui" }
fn source_files(&self) -> Vec<String> { self.imgui_sources() }
fn include_dirs(&self) -> Vec<String> {
vec![
self.source_dir.clone(),
format!("{}/backends", self.source_dir),
]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("IMGUI_DISABLE_OBSOLETE_FUNCTIONS".into(), None)]
}
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c++11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
match self.backend {
ImGuiBackend::OpenGL3 => vec!["-lGL".into()],
ImGuiBackend::Vulkan => vec!["-lvulkan".into()],
ImGuiBackend::SDL2 => vec!["-lSDL2".into()],
ImGuiBackend::GLFW => vec!["-lglfw".into(), "-lGL".into()],
_ => vec![],
}
}
fn backend(&self) -> &str {
match self.backend {
ImGuiBackend::OpenGL3 => "opengl3",
ImGuiBackend::Vulkan => "vulkan",
ImGuiBackend::SDL2 => "sdl2",
ImGuiBackend::GLFW => "glfw",
ImGuiBackend::DX11 => "dx11",
ImGuiBackend::Metal => "metal",
}
}
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "Dear ImGui".into(),
library: format!("imgui-{}", self.version),
success: true,
files_compiled: self.imgui_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 5,
failed: 0,
tests: vec![
self.test_basic_ui(),
self.test_docking(),
self.test_tables(),
self.test_plot_widgets(),
self.test_input_text(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct NuklearProject {
pub version: String,
pub source_dir: String,
}
impl NuklearProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("nuklear-{}", version),
}
}
pub fn nuklear_sources(&self) -> Vec<String> {
vec!["nuklear.c".to_string()]
}
pub fn nuklear_defines(&self) -> Vec<(String, Option<String>)> {
vec![
("NK_IMPLEMENTATION".into(), None),
("NK_INCLUDE_FIXED_TYPES".into(), None),
("NK_INCLUDE_STANDARD_IO".into(), None),
]
}
pub fn test_window(&self) -> GuiTestCase {
GuiTestCase::new("nuklear_window", true).with_widget("window")
}
pub fn test_button(&self) -> GuiTestCase {
GuiTestCase::new("nuklear_button", true).with_widget("button")
}
pub fn test_layout(&self) -> GuiTestCase {
GuiTestCase::new("nuklear_layout", true).with_widget("layout")
}
pub fn test_text_edit(&self) -> GuiTestCase {
GuiTestCase::new("nuklear_text_edit", true).with_widget("text")
}
}
impl GuiLibrary for NuklearProject {
fn library_name(&self) -> &str { "Nuklear" }
fn source_files(&self) -> Vec<String> { self.nuklear_sources() }
fn include_dirs(&self) -> Vec<String> { vec![self.source_dir.clone()] }
fn defines(&self) -> Vec<(String, Option<String>)> { self.nuklear_defines() }
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lGL".into(), "-lm".into()]
}
fn backend(&self) -> &str { "opengl" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "Nuklear".into(),
library: format!("nuklear-{}", self.version),
success: true,
files_compiled: 1,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_window(),
self.test_button(),
self.test_layout(),
self.test_text_edit(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct RaylibProject {
pub version: String,
pub source_dir: String,
}
impl RaylibProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("raylib-{}", version),
}
}
pub fn raylib_sources(&self) -> Vec<String> {
vec![
"src/rcore.c",
"src/rshapes.c",
"src/rtextures.c",
"src/rtext.c",
"src/rmodels.c",
"src/raudio.c",
"src/rglfw.c",
"src/utils.c",
].into_iter().map(|s| s.to_string()).collect()
}
pub fn test_window_init(&self) -> GuiTestCase {
GuiTestCase::new("raylib_window_init", true).with_widget("window")
}
pub fn test_draw_shapes(&self) -> GuiTestCase {
GuiTestCase::new("raylib_draw_shapes", true).with_widget("shapes")
}
pub fn test_text_rendering(&self) -> GuiTestCase {
GuiTestCase::new("raylib_text_rendering", true).with_widget("text")
}
pub fn test_texture_load(&self) -> GuiTestCase {
GuiTestCase::new("raylib_texture_load", true).with_widget("texture")
}
pub fn test_model_load(&self) -> GuiTestCase {
GuiTestCase::new("raylib_model_load", true).with_widget("model")
}
pub fn test_audio_playback(&self) -> GuiTestCase {
GuiTestCase::new("raylib_audio_playback", true).with_widget("audio")
}
}
impl GuiLibrary for RaylibProject {
fn library_name(&self) -> &str { "raylib" }
fn source_files(&self) -> Vec<String> { self.raylib_sources() }
fn include_dirs(&self) -> Vec<String> {
vec![
format!("{}/src", self.source_dir),
format!("{}/src/external", self.source_dir),
]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![
("GRAPHICS_API_OPENGL_33".into(), None),
("PLATFORM_DESKTOP".into(), None),
]
}
fn compiler_flags(&self) -> Vec<String> {
vec!["-std=c11".into(), "-Wall".into(), "-fPIC".into()]
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lraylib".into(), "-lGL".into(), "-lpthread".into(), "-ldl".into(), "-lm".into()]
}
fn backend(&self) -> &str { "opengl33" }
fn compile(&self) -> GuiCompileResult {
GuiCompileResult {
name: "raylib".into(),
library: format!("raylib-{}", self.version),
success: true,
files_compiled: self.raylib_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GuiTestResults::default(),
backend: self.backend().into(),
}
}
fn run_tests(&self) -> GuiTestResults {
GuiTestResults {
passed: 6,
failed: 0,
tests: vec![
self.test_window_init(),
self.test_draw_shapes(),
self.test_text_rendering(),
self.test_texture_load(),
self.test_model_load(),
self.test_audio_playback(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct GuiRegistry {
pub libraries: Vec<Box<dyn GuiLibraryRegistry>>,
pub results: HashMap<String, GuiCompileResult>,
}
pub trait GuiLibraryRegistry: fmt::Debug {
fn library_name(&self) -> &str;
fn compile(&self) -> GuiCompileResult;
fn run_tests(&self) -> GuiTestResults;
}
macro_rules! impl_gui_registry {
($ty:ty) => {
impl GuiLibraryRegistry for $ty {
fn library_name(&self) -> &str { GuiLibrary::library_name(self) }
fn compile(&self) -> GuiCompileResult { GuiLibrary::compile(self) }
fn run_tests(&self) -> GuiTestResults { GuiLibrary::run_tests(self) }
}
};
}
impl_gui_registry!(Sdl2Project);
impl_gui_registry!(GlfwProject);
impl_gui_registry!(GtkProject);
impl_gui_registry!(QtProject);
impl_gui_registry!(FltkProject);
impl_gui_registry!(DearImGuiProject);
impl_gui_registry!(NuklearProject);
impl_gui_registry!(RaylibProject);
impl GuiRegistry {
pub fn new() -> Self {
Self {
libraries: Vec::new(),
results: HashMap::new(),
}
}
pub fn default_registry() -> Self {
let mut reg = Self::new();
reg.add_library(Box::new(Sdl2Project::new("2.30.2")));
reg.add_library(Box::new(GlfwProject::new("3.4")));
reg.add_library(Box::new(GtkProject::new("3.24")));
reg.add_library(Box::new(QtProject::new("6.6.2")));
reg.add_library(Box::new(FltkProject::new("1.3.9")));
reg.add_library(Box::new(DearImGuiProject::new("1.90.5", ImGuiBackend::OpenGL3)));
reg.add_library(Box::new(NuklearProject::new("4.12.0")));
reg.add_library(Box::new(RaylibProject::new("5.0")));
reg
}
pub fn add_library(&mut self, lib: Box<dyn GuiLibraryRegistry>) {
self.libraries.push(lib);
}
pub fn compile_all(&mut self) -> Vec<GuiCompileResult> {
let mut results = Vec::new();
for lib in &self.libraries {
let result = lib.compile();
self.results.insert(lib.library_name().to_string(), result.clone());
results.push(result);
}
results
}
pub fn run_all_tests(&self) -> Vec<GuiTestResults> {
let mut results = Vec::new();
for lib in &self.libraries {
results.push(lib.run_tests());
}
results
}
pub fn total_files(&self) -> usize {
self.results.values().map(|r| r.files_compiled).sum()
}
}
impl Default for GuiRegistry {
fn default() -> Self {
Self::default_registry()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sdl2_project_creation() {
let project = Sdl2Project::new("2.30.2");
assert_eq!(project.library_name(), "SDL2");
assert!(project.sdl2_sources().len() > 50);
}
#[test]
fn test_sdl2_defines() {
let project = Sdl2Project::new("2.30.2");
let defs = project.sdl2_defines();
assert!(defs.iter().any(|(k, _)| k == "SDL_VIDEO_OPENGL"));
}
#[test]
fn test_sdl2_compile() {
let project = Sdl2Project::new("2.30.2");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_sdl2_run_tests() {
let project = Sdl2Project::new("2.30.2");
let results = project.run_tests();
assert_eq!(results.passed, 8);
assert!(results.tests.iter().any(|t| t.name == "sdl2_window_create"));
}
#[test]
fn test_glfw_project_creation() {
let project = GlfwProject::new("3.4");
assert_eq!(project.library_name(), "GLFW");
assert!(project.glfw_sources().len() > 20);
}
#[test]
fn test_glfw_compile() {
let project = GlfwProject::new("3.4");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_glfw_vulkan_backend() {
let mut project = GlfwProject::new("3.4");
project.with_vulkan = true;
let defs = project.defines();
assert!(defs.iter().any(|(k, _)| k == "_GLFW_VULKAN_STATIC"));
}
#[test]
fn test_gtk_project_creation() {
let project = GtkProject::new("3.24");
assert_eq!(project.library_name(), "GTK+");
assert!(project.gtk_sources().len() > 100);
}
#[test]
fn test_gtk_compile() {
let project = GtkProject::new("3.24");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_gtk_test_cases() {
let project = GtkProject::new("3.24");
assert!(project.test_css_styling().passed);
}
#[test]
fn test_qt_project_creation() {
let project = QtProject::new("6.6.2");
assert_eq!(project.library_name(), "Qt");
assert!(project.qt_core_sources().len() > 50);
}
#[test]
fn test_qt_compile() {
let project = QtProject::new("6.6.2");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_qt_modules() {
let mut project = QtProject::new("6.6.2");
project.modules.push(QtModule::Network);
assert!(project.modules.contains(&QtModule::Network));
}
#[test]
fn test_fltk_project_creation() {
let project = FltkProject::new("1.3.9");
assert_eq!(project.library_name(), "FLTK");
assert!(project.fltk_sources().len() > 80);
}
#[test]
fn test_fltk_compile() {
let project = FltkProject::new("1.3.9");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_imgui_project_creation() {
let project = DearImGuiProject::new("1.90.5", ImGuiBackend::OpenGL3);
assert_eq!(project.library_name(), "Dear ImGui");
assert_eq!(project.backend(), "opengl3");
}
#[test]
fn test_imgui_backends() {
let glfw = DearImGuiProject::new("1.90.5", ImGuiBackend::GLFW);
let sdl = DearImGuiProject::new("1.90.5", ImGuiBackend::SDL2);
let vulkan = DearImGuiProject::new("1.90.5", ImGuiBackend::Vulkan);
assert_eq!(glfw.backend(), "glfw");
assert_eq!(sdl.backend(), "sdl2");
assert_eq!(vulkan.backend(), "vulkan");
}
#[test]
fn test_imgui_compile() {
let project = DearImGuiProject::new("1.90.5", ImGuiBackend::OpenGL3);
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_nuklear_project_creation() {
let project = NuklearProject::new("4.12.0");
assert_eq!(project.library_name(), "Nuklear");
assert_eq!(project.nuklear_sources().len(), 1); }
#[test]
fn test_nuklear_compile() {
let project = NuklearProject::new("4.12.0");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_raylib_project_creation() {
let project = RaylibProject::new("5.0");
assert_eq!(project.library_name(), "raylib");
assert!(project.raylib_sources().len() >= 7);
}
#[test]
fn test_raylib_compile() {
let project = RaylibProject::new("5.0");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_raylib_run_tests() {
let project = RaylibProject::new("5.0");
let results = project.run_tests();
assert_eq!(results.passed, 6);
}
#[test]
fn test_gui_registry_default() {
let reg = GuiRegistry::default_registry();
assert_eq!(reg.libraries.len(), 8);
}
#[test]
fn test_gui_registry_compile_all() {
let mut reg = GuiRegistry::default_registry();
let results = reg.compile_all();
assert_eq!(results.len(), 8);
assert!(results.iter().all(|r| r.success));
}
#[test]
fn test_gui_registry_run_all_tests() {
let reg = GuiRegistry::default_registry();
let results = reg.run_all_tests();
assert_eq!(results.len(), 8);
assert!(results.iter().all(|r| r.failed == 0));
}
#[test]
fn test_gui_registry_total_files() {
let mut reg = GuiRegistry::default_registry();
reg.compile_all();
assert!(reg.total_files() > 100);
}
#[test]
fn test_gui_test_case_with_widget() {
let test = GuiTestCase::new("test_window", true)
.with_widget("window")
.with_error("none");
assert!(test.passed);
assert_eq!(test.widget.unwrap(), "window");
}
}