Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ target_include_directories(
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(webview_core_headers INTERFACE ${WEBVIEW_DEPENDENCIES})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(webview_core_headers INTERFACE util sqlite3)
endif()
# Note that we also use CMAKE_CXX_STANDARD which can override this
target_compile_features(webview_core_headers INTERFACE cxx_std_11)
set_target_properties(webview_core_headers PROPERTIES
Expand All @@ -16,12 +19,30 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND WEBVIEW_USE_COMPAT_MINGW)
target_link_libraries(webview_core_headers INTERFACE webview::compat_mingw)
endif()

set(ALLOY_GUI_SOURCES
src/alloy_gui/signals.cc
src/alloy_gui/window.cc
src/alloy_gui/button.cc
src/alloy_gui/label.cc
src/alloy_gui/input.cc
src/alloy_gui/layout.cc
src/alloy_gui/selection.cc
src/alloy_gui/navigation.cc
src/alloy_gui/dialog.cc
src/alloy_gui/extra.cc
)

# Core shared library
if(WEBVIEW_BUILD_SHARED_LIBRARY)
add_library(webview_core_shared SHARED)
add_library(webview::core_shared ALIAS webview_core_shared)
target_sources(webview_core_shared PRIVATE src/webview.cc)
target_sources(webview_core_shared PRIVATE
src/webview.cc
src/alloy.cc
${ALLOY_GUI_SOURCES}
)
target_link_libraries(webview_core_shared PUBLIC webview_core_headers)
target_link_libraries(webview_core_shared PRIVATE util sqlite3)
set_target_properties(webview_core_shared PROPERTIES
OUTPUT_NAME webview
VERSION "${WEBVIEW_VERSION_NUMBER}"
Expand All @@ -43,8 +64,17 @@ if(WEBVIEW_BUILD_STATIC_LIBRARY)

add_library(webview_core_static STATIC)
add_library(webview::core_static ALIAS webview_core_static)
target_sources(webview_core_static PRIVATE src/webview.cc)
target_sources(webview_core_static PRIVATE
src/webview.cc
src/alloy.cc
${ALLOY_GUI_SOURCES}
)
target_link_libraries(webview_core_static PUBLIC webview_core_headers)
target_link_libraries(webview_core_static PRIVATE util sqlite3)

# Requirements Document: expose alloy_gui target
add_library(alloy_gui ALIAS webview_core_static)

set_target_properties(webview_core_static PROPERTIES
OUTPUT_NAME "${STATIC_LIBRARY_OUTPUT_NAME}"
POSITION_INDEPENDENT_CODE ON
Expand Down
199 changes: 199 additions & 0 deletions core/include/alloy_gui/api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#ifndef ALLOY_GUI_API_H
#define ALLOY_GUI_API_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef ALLOY_API
#define ALLOY_API
#endif

// ── Types ──────────────────────────────────────────────────────────────────

typedef void *alloy_component_t; // opaque component handle
typedef void *alloy_signal_t; // opaque signal handle
typedef void *alloy_computed_t; // opaque computed signal handle
typedef void *alloy_effect_t; // opaque effect handle

typedef enum {
ALLOY_OK = 0,
ALLOY_ERROR_INVALID_ARGUMENT,
ALLOY_ERROR_INVALID_STATE,
ALLOY_ERROR_PLATFORM,
ALLOY_ERROR_BUFFER_TOO_SMALL,
ALLOY_ERROR_NOT_SUPPORTED,
} alloy_error_t;

typedef enum {
ALLOY_EVENT_CLICK = 0,
ALLOY_EVENT_CHANGE,
ALLOY_EVENT_CLOSE,
ALLOY_EVENT_FOCUS,
ALLOY_EVENT_BLUR,
} alloy_event_type_t;

typedef enum {
ALLOY_PROP_TEXT = 0,
ALLOY_PROP_CHECKED,
ALLOY_PROP_VALUE,
ALLOY_PROP_ENABLED,
ALLOY_PROP_VISIBLE,
ALLOY_PROP_LABEL,
ALLOY_PROP_TITLE,
} alloy_prop_id_t;

typedef void (*alloy_event_cb_t)(alloy_component_t handle,
alloy_event_type_t event,
void *userdata);

typedef struct {
unsigned int background; // RGBA packed
unsigned int foreground; // RGBA packed
float font_size; // points; 0 = inherit
const char *font_family; // NULL = inherit
float border_radius;// points
float opacity; // 0.0–1.0
} alloy_style_t;

// ── Error ──────────────────────────────────────────────────────────────────

ALLOY_API const char *alloy_error_message(alloy_error_t err);

// ── Signal system ──────────────────────────────────────────────────────────

ALLOY_API alloy_signal_t alloy_signal_create_str(const char *initial);
ALLOY_API alloy_signal_t alloy_signal_create_double(double initial);
ALLOY_API alloy_signal_t alloy_signal_create_int(int initial);
ALLOY_API alloy_signal_t alloy_signal_create_bool(int initial);

ALLOY_API alloy_error_t alloy_signal_set_str(alloy_signal_t s, const char *v);
ALLOY_API alloy_error_t alloy_signal_set_double(alloy_signal_t s, double v);
ALLOY_API alloy_error_t alloy_signal_set_int(alloy_signal_t s, int v);
ALLOY_API alloy_error_t alloy_signal_set_bool(alloy_signal_t s, int v);

ALLOY_API const char *alloy_signal_get_str(alloy_signal_t s);
ALLOY_API double alloy_signal_get_double(alloy_signal_t s);
ALLOY_API int alloy_signal_get_int(alloy_signal_t s);
ALLOY_API int alloy_signal_get_bool(alloy_signal_t s);

typedef void (*alloy_compute_cb_t)(alloy_signal_t *deps, size_t dep_count, void *out, void *userdata);

ALLOY_API alloy_computed_t alloy_computed_create(
alloy_signal_t *deps, size_t dep_count,
alloy_compute_cb_t compute,
void *userdata);

ALLOY_API alloy_effect_t alloy_effect_create(
alloy_signal_t *deps, size_t dep_count,
void (*run)(void *userdata), void *userdata);

ALLOY_API alloy_error_t alloy_signal_destroy(alloy_signal_t s);
ALLOY_API alloy_error_t alloy_computed_destroy(alloy_computed_t c);
ALLOY_API alloy_error_t alloy_effect_destroy(alloy_effect_t e);

// ── Property binding ───────────────────────────────────────────────────────

ALLOY_API alloy_error_t alloy_bind_property(alloy_component_t component,
alloy_prop_id_t property,
alloy_signal_t signal);
ALLOY_API alloy_error_t alloy_unbind_property(alloy_component_t component,
alloy_prop_id_t property);

// ── Component lifecycle ────────────────────────────────────────────────────

ALLOY_API alloy_component_t alloy_create_window(const char *title, int width, int height);
ALLOY_API alloy_component_t alloy_create_button(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_textfield(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_textarea(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_label(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_checkbox(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_radiobutton(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_combobox(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_slider(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_spinner(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_progressbar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_tabview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_listview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_treeview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_webview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_vstack(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_hstack(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_scrollview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_menu(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_menubar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_toolbar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_statusbar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_splitter(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_dialog(const char *title, int width, int height);
ALLOY_API alloy_component_t alloy_create_filedialog(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_colorpicker(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_datepicker(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_timepicker(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_divider(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_image(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_icon(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_separator(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_groupbox(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_accordion(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_popover(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_contextmenu(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_switch(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_badge(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_chip(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_loading_indicator(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_card(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_link(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_rating(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_richtexteditor(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_codeeditor(alloy_component_t parent);

ALLOY_API alloy_error_t alloy_destroy(alloy_component_t handle);

// ── Property getters/setters ───────────────────────────────────────────────

ALLOY_API alloy_error_t alloy_set_text(alloy_component_t h, const char *text);
ALLOY_API int alloy_get_text(alloy_component_t h, char *buf, size_t buf_len);
ALLOY_API alloy_error_t alloy_set_checked(alloy_component_t h, int checked);
ALLOY_API int alloy_get_checked(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_value(alloy_component_t h, double value);
ALLOY_API double alloy_get_value(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_enabled(alloy_component_t h, int enabled);
ALLOY_API int alloy_get_enabled(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_visible(alloy_component_t h, int visible);
ALLOY_API int alloy_get_visible(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_style(alloy_component_t h, const alloy_style_t *style);

// ── Layout ─────────────────────────────────────────────────────────────────

ALLOY_API alloy_error_t alloy_add_child(alloy_component_t container, alloy_component_t child);
ALLOY_API alloy_error_t alloy_set_flex(alloy_component_t h, float flex);
ALLOY_API alloy_error_t alloy_set_padding(alloy_component_t h,
float top, float right,
float bottom, float left);
ALLOY_API alloy_error_t alloy_set_margin(alloy_component_t h,
float top, float right,
float bottom, float left);
ALLOY_API alloy_error_t alloy_layout(alloy_component_t window);

// ── Events ─────────────────────────────────────────────────────────────────

ALLOY_API alloy_error_t alloy_set_event_callback(alloy_component_t handle,
alloy_event_type_t event,
alloy_event_cb_t callback,
void *userdata);

// ── Event loop ─────────────────────────────────────────────────────────────

ALLOY_API alloy_error_t alloy_run(alloy_component_t window);
ALLOY_API alloy_error_t alloy_terminate(alloy_component_t window);
ALLOY_API alloy_error_t alloy_dispatch(alloy_component_t window,
void (*fn)(void *arg), void *arg);

#ifdef __cplusplus
}
#endif

#endif // ALLOY_GUI_API_H
58 changes: 58 additions & 0 deletions core/include/alloy_gui/detail/backends/cocoa_backend.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef ALLOY_GUI_COCOA_BACKEND_HH
#define ALLOY_GUI_COCOA_BACKEND_HH

#include "../component.hh"
#include "webview/detail/platform/darwin/cocoa/NSWindow.hh"
#include "webview/detail/platform/darwin/cocoa/NSView.hh"
#include "webview/detail/platform/darwin/cocoa/NSString.hh"

namespace alloy {
namespace detail {

class CocoaBackend {
public:
static Component* create_window(const char *title, int width, int height) {
using namespace webview::detail::cocoa;
NSRect rect = { {0, 0}, {(double)width, (double)height} };
id win = NSWindow_withContentRect(rect,
(NSWindowStyleMask)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable),
NSBackingStoreBuffered, false);
NSWindow_set_title(win, title);
NSWindow_makeKeyAndOrderFront(win);
return new Component(win);
}

static Component* create_button(Component */*parent*/) {
using namespace webview::detail;
id btn = objc::msg_send<id>(objc::get_class("NSButton"), objc::selector("alloc"));
NSRect rect = { {0, 0}, {100, 30} };
btn = objc::msg_send<id>(btn, objc::selector("initWithFrame:"), rect);
objc::msg_send<void>(btn, objc::selector("setButtonType:"), 0); // NSButtonTypeMomentaryLight
objc::msg_send<void>(btn, objc::selector("setBezelStyle:"), 2); // NSBezelStyleRounded
return new Component(btn);
}

static Component* create_label(Component */*parent*/) {
using namespace webview::detail;
id lbl = objc::msg_send<id>(objc::get_class("NSTextField"), objc::selector("alloc"));
NSRect rect = { {0, 0}, {100, 20} };
lbl = objc::msg_send<id>(lbl, objc::selector("initWithFrame:"), rect);
objc::msg_send<void>(lbl, objc::selector("setEditable:"), static_cast<BOOL>(false));
objc::msg_send<void>(lbl, objc::selector("setBezeled:"), static_cast<BOOL>(false));
objc::msg_send<void>(lbl, objc::selector("setDrawsBackground:"), static_cast<BOOL>(false));
return new Component(lbl);
}

static Component* create_textfield(Component */*parent*/) {
using namespace webview::detail;
id txt = objc::msg_send<id>(objc::get_class("NSTextField"), objc::selector("alloc"));
NSRect rect = { {0, 0}, {150, 25} };
txt = objc::msg_send<id>(txt, objc::selector("initWithFrame:"), rect);
return new Component(txt);
}
};

} // namespace detail
} // namespace alloy

#endif
Loading