gtk3-node 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +56 -0
- package/package.json +5 -1
- package/src/button.cpp +146 -0
- package/src/gtk3_node.cpp +150 -0
- package/widgets/box/README.md +42 -0
- package/widgets/box/box.cpp +77 -0
- package/widgets/box/box.h +10 -0
- package/widgets/label/README.md +41 -0
- package/widgets/label/label.cpp +95 -0
- package/widgets/label/label.h +10 -0
- package/widgets/scroll/README.md +40 -0
- package/widgets/scroll/scroll.cpp +72 -0
- package/widgets/scroll/scroll.h +10 -0
package/binding.gyp
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "gtk3_node",
|
|
5
|
+
"sources": [
|
|
6
|
+
"src/gtk3_node.cpp",
|
|
7
|
+
"src/button.cpp",
|
|
8
|
+
"widgets/label/label.cpp",
|
|
9
|
+
"widgets/box/box.cpp",
|
|
10
|
+
"widgets/scroll/scroll.cpp"
|
|
11
|
+
],
|
|
12
|
+
"include_dirs": [
|
|
13
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
14
|
+
"/usr/include/gtk-3.0",
|
|
15
|
+
"/usr/include/glib-2.0",
|
|
16
|
+
"/usr/lib/x86_64-linux-gnu/glib-2.0/include",
|
|
17
|
+
"/usr/include/pango-1.0",
|
|
18
|
+
"/usr/include/harfbuzz",
|
|
19
|
+
"/usr/include/freetype2",
|
|
20
|
+
"/usr/include/libpng16",
|
|
21
|
+
"/usr/include/libmount",
|
|
22
|
+
"/usr/include/blkid",
|
|
23
|
+
"/usr/include/fribidi",
|
|
24
|
+
"/usr/include/cairo",
|
|
25
|
+
"/usr/include/pixman-1",
|
|
26
|
+
"/usr/include/gdk-pixbuf-2.0",
|
|
27
|
+
"/usr/include/x86_64-linux-gnu",
|
|
28
|
+
"/usr/include/gio-unix-2.0",
|
|
29
|
+
"/usr/include/atk-1.0",
|
|
30
|
+
"/usr/include/at-spi2-atk/2.0",
|
|
31
|
+
"/usr/include/at-spi-2.0",
|
|
32
|
+
"/usr/include/dbus-1.0",
|
|
33
|
+
"/usr/lib/x86_64-linux-gnu/dbus-1.0/include"
|
|
34
|
+
],
|
|
35
|
+
"libraries": [
|
|
36
|
+
"-lgtk-3",
|
|
37
|
+
"-lgobject-2.0",
|
|
38
|
+
"-lglib-2.0",
|
|
39
|
+
"-lgdk-3",
|
|
40
|
+
"-lpango-1.0",
|
|
41
|
+
"-lcairo",
|
|
42
|
+
"-lgdk_pixbuf-2.0",
|
|
43
|
+
"-latk-1.0"
|
|
44
|
+
],
|
|
45
|
+
"cflags": [
|
|
46
|
+
"-std=c++17"
|
|
47
|
+
],
|
|
48
|
+
"cflags_cc": [
|
|
49
|
+
"-std=c++17"
|
|
50
|
+
],
|
|
51
|
+
"defines": [
|
|
52
|
+
"NAPI_DISABLE_CPP_EXCEPTIONS"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtk3-node",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Native Node.js extension for creating GTK3 widgets",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
],
|
|
49
49
|
"author": "Usuario",
|
|
50
50
|
"license": "MIT",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://gitlab.com/bytedogssyndicate1/nodetk3.git"
|
|
54
|
+
},
|
|
51
55
|
"dependencies": {
|
|
52
56
|
"node-addon-api": "^7.0.0"
|
|
53
57
|
},
|
package/src/button.cpp
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <gtk/gtk.h>
|
|
3
|
+
|
|
4
|
+
// Estructura para almacenar datos del botón
|
|
5
|
+
struct ButtonData {
|
|
6
|
+
GtkWidget* button;
|
|
7
|
+
Napi::FunctionReference callback;
|
|
8
|
+
Napi::Env env;
|
|
9
|
+
|
|
10
|
+
ButtonData(Napi::Env e) : button(nullptr), env(e) {}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Callback para el evento de clic en GTK
|
|
14
|
+
static void button_click_callback(GtkWidget *widget, gpointer data) {
|
|
15
|
+
ButtonData* btn_data = static_cast<ButtonData*>(data);
|
|
16
|
+
|
|
17
|
+
if (!btn_data->callback.IsEmpty()) {
|
|
18
|
+
Napi::HandleScope scope(btn_data->env);
|
|
19
|
+
btn_data->callback.Call({});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Constructor de botón
|
|
24
|
+
Napi::Value CreateButton(const Napi::CallbackInfo& info) {
|
|
25
|
+
Napi::Env env = info.Env();
|
|
26
|
+
|
|
27
|
+
std::string label = "Button";
|
|
28
|
+
if (info.Length() > 0 && info[0].IsString()) {
|
|
29
|
+
label = info[0].As<Napi::String>().Utf8Value();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
GtkWidget* button = gtk_button_new_with_label(label.c_str());
|
|
33
|
+
|
|
34
|
+
// Crear estructura de datos para el botón
|
|
35
|
+
ButtonData* btn_data = new ButtonData(env);
|
|
36
|
+
btn_data->button = button;
|
|
37
|
+
|
|
38
|
+
// Guardar la estructura en los datos del widget
|
|
39
|
+
g_object_set_data_full(G_OBJECT(button), "button_data", btn_data,
|
|
40
|
+
GDestroyNotify([](gpointer data) {
|
|
41
|
+
ButtonData* btn_data = static_cast<ButtonData*>(data);
|
|
42
|
+
if (!btn_data->callback.IsEmpty()) {
|
|
43
|
+
btn_data->callback.Reset();
|
|
44
|
+
}
|
|
45
|
+
delete btn_data;
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
// Convertir el widget a External para pasarlo a JavaScript
|
|
49
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
50
|
+
obj.Set("widget", Napi::External<GtkWidget>::New(env, button));
|
|
51
|
+
|
|
52
|
+
return obj;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Función para conectar el callback de clic
|
|
56
|
+
Napi::Value ConnectClick(const Napi::CallbackInfo& info) {
|
|
57
|
+
Napi::Env env = info.Env();
|
|
58
|
+
|
|
59
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsFunction()) {
|
|
60
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget y una función callback").ThrowAsJavaScriptException();
|
|
61
|
+
return Napi::Boolean::New(env, false);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
65
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
66
|
+
|
|
67
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
68
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
69
|
+
return Napi::Boolean::New(env, false);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
73
|
+
GtkWidget* button = widgetExt.Data();
|
|
74
|
+
|
|
75
|
+
// Obtener la estructura de datos del botón
|
|
76
|
+
ButtonData* btn_data = static_cast<ButtonData*>(g_object_get_data(G_OBJECT(button), "button_data"));
|
|
77
|
+
if (!btn_data) {
|
|
78
|
+
Napi::TypeError::New(env, "Datos del botón no encontrados").ThrowAsJavaScriptException();
|
|
79
|
+
return Napi::Boolean::New(env, false);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Almacenar el nuevo callback
|
|
83
|
+
btn_data->callback.Reset(callback, 1);
|
|
84
|
+
|
|
85
|
+
// Conectar el callback de GTK
|
|
86
|
+
g_signal_connect(button, "clicked", G_CALLBACK(button_click_callback), btn_data);
|
|
87
|
+
|
|
88
|
+
return Napi::Boolean::New(env, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Función para cambiar el texto del botón
|
|
92
|
+
Napi::Value SetButtonText(const Napi::CallbackInfo& info) {
|
|
93
|
+
Napi::Env env = info.Env();
|
|
94
|
+
|
|
95
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsString()) {
|
|
96
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget y un texto").ThrowAsJavaScriptException();
|
|
97
|
+
return Napi::Boolean::New(env, false);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
101
|
+
std::string newText = info[1].As<Napi::String>().Utf8Value();
|
|
102
|
+
|
|
103
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
104
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
105
|
+
return Napi::Boolean::New(env, false);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
109
|
+
GtkWidget* button = widgetExt.Data();
|
|
110
|
+
|
|
111
|
+
gtk_button_set_label(GTK_BUTTON(button), newText.c_str());
|
|
112
|
+
|
|
113
|
+
return Napi::Boolean::New(env, true);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Función para obtener el texto del botón
|
|
117
|
+
Napi::Value GetButtonText(const Napi::CallbackInfo& info) {
|
|
118
|
+
Napi::Env env = info.Env();
|
|
119
|
+
|
|
120
|
+
if (info.Length() < 1 || !info[0].IsObject()) {
|
|
121
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget").ThrowAsJavaScriptException();
|
|
122
|
+
return Napi::String::New(env, "");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
126
|
+
|
|
127
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
128
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
129
|
+
return Napi::String::New(env, "");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
133
|
+
GtkWidget* button = widgetExt.Data();
|
|
134
|
+
|
|
135
|
+
const gchar* text = gtk_button_get_label(GTK_BUTTON(button));
|
|
136
|
+
return Napi::String::New(env, text ? text : "");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Napi::Object InitButton(Napi::Env env, Napi::Object exports) {
|
|
140
|
+
exports.Set("createButton", Napi::Function::New(env, CreateButton));
|
|
141
|
+
exports.Set("connectClick", Napi::Function::New(env, ConnectClick));
|
|
142
|
+
exports.Set("setButtonText", Napi::Function::New(env, SetButtonText));
|
|
143
|
+
exports.Set("getButtonText", Napi::Function::New(env, GetButtonText));
|
|
144
|
+
|
|
145
|
+
return exports;
|
|
146
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <gtk/gtk.h>
|
|
3
|
+
|
|
4
|
+
// Función para inicializar GTK
|
|
5
|
+
Napi::Value InitGtk(const Napi::CallbackInfo& info) {
|
|
6
|
+
Napi::Env env = info.Env();
|
|
7
|
+
|
|
8
|
+
static bool initialized = false;
|
|
9
|
+
if (!initialized) {
|
|
10
|
+
gtk_init(0, NULL);
|
|
11
|
+
initialized = true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return Napi::Boolean::New(env, true);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Función para ejecutar el loop de eventos de GTK
|
|
18
|
+
Napi::Value RunGtk(const Napi::CallbackInfo& info) {
|
|
19
|
+
Napi::Env env = info.Env();
|
|
20
|
+
|
|
21
|
+
gtk_main();
|
|
22
|
+
|
|
23
|
+
return Napi::Boolean::New(env, true);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Función para salir del loop de eventos de GTK
|
|
27
|
+
Napi::Value QuitGtk(const Napi::CallbackInfo& info) {
|
|
28
|
+
Napi::Env env = info.Env();
|
|
29
|
+
|
|
30
|
+
gtk_main_quit();
|
|
31
|
+
|
|
32
|
+
return Napi::Boolean::New(env, true);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Función para crear una ventana
|
|
36
|
+
Napi::Value CreateWindow(const Napi::CallbackInfo& info) {
|
|
37
|
+
Napi::Env env = info.Env();
|
|
38
|
+
|
|
39
|
+
std::string title = "Ventana";
|
|
40
|
+
gint width = 400;
|
|
41
|
+
gint height = 300;
|
|
42
|
+
|
|
43
|
+
if (info.Length() > 0 && info[0].IsString()) {
|
|
44
|
+
title = info[0].As<Napi::String>().Utf8Value();
|
|
45
|
+
}
|
|
46
|
+
if (info.Length() > 1 && info[1].IsNumber()) {
|
|
47
|
+
width = info[1].As<Napi::Number>().Int32Value();
|
|
48
|
+
}
|
|
49
|
+
if (info.Length() > 2 && info[2].IsNumber()) {
|
|
50
|
+
height = info[2].As<Napi::Number>().Int32Value();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
54
|
+
gtk_window_set_title(GTK_WINDOW(window), title.c_str());
|
|
55
|
+
gtk_window_set_default_size(GTK_WINDOW(window), width, height);
|
|
56
|
+
|
|
57
|
+
// Conectar el evento destroy para salir del programa
|
|
58
|
+
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
|
59
|
+
|
|
60
|
+
// Convertir el widget a External para pasarlo a JavaScript
|
|
61
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
62
|
+
obj.Set("widget", Napi::External<GtkWidget>::New(env, window));
|
|
63
|
+
|
|
64
|
+
return obj;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Función para mostrar todos los widgets en una ventana
|
|
68
|
+
Napi::Value ShowAll(const Napi::CallbackInfo& info) {
|
|
69
|
+
Napi::Env env = info.Env();
|
|
70
|
+
|
|
71
|
+
if (info.Length() < 1 || !info[0].IsObject()) {
|
|
72
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget").ThrowAsJavaScriptException();
|
|
73
|
+
return Napi::Boolean::New(env, false);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
77
|
+
|
|
78
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
79
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
80
|
+
return Napi::Boolean::New(env, false);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
84
|
+
GtkWidget* window = widgetExt.Data();
|
|
85
|
+
|
|
86
|
+
gtk_widget_show_all(window);
|
|
87
|
+
|
|
88
|
+
return Napi::Boolean::New(env, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Función para agregar un widget a una ventana
|
|
92
|
+
Napi::Value AddToWindow(const Napi::CallbackInfo& info) {
|
|
93
|
+
Napi::Env env = info.Env();
|
|
94
|
+
|
|
95
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsObject()) {
|
|
96
|
+
Napi::TypeError::New(env, "Se requieren dos objetos widget").ThrowAsJavaScriptException();
|
|
97
|
+
return Napi::Boolean::New(env, false);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Napi::Object windowObj = info[0].As<Napi::Object>();
|
|
101
|
+
Napi::Object widgetObj = info[1].As<Napi::Object>();
|
|
102
|
+
|
|
103
|
+
if (!windowObj.HasOwnProperty("widget") || !widgetObj.HasOwnProperty("widget")) {
|
|
104
|
+
Napi::TypeError::New(env, "Ambos objetos deben contener widgets válidos").ThrowAsJavaScriptException();
|
|
105
|
+
return Napi::Boolean::New(env, false);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Napi::External<GtkWidget> windowExt = windowObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
109
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
110
|
+
|
|
111
|
+
GtkWidget* window = windowExt.Data();
|
|
112
|
+
GtkWidget* widget = widgetExt.Data();
|
|
113
|
+
|
|
114
|
+
gtk_container_add(GTK_CONTAINER(window), widget);
|
|
115
|
+
|
|
116
|
+
return Napi::Boolean::New(env, true);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Función principal que define el módulo
|
|
120
|
+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
121
|
+
// Inicializar GTK
|
|
122
|
+
exports.Set("init", Napi::Function::New(env, InitGtk));
|
|
123
|
+
exports.Set("run", Napi::Function::New(env, RunGtk));
|
|
124
|
+
exports.Set("quit", Napi::Function::New(env, QuitGtk));
|
|
125
|
+
|
|
126
|
+
// Funciones de ventana
|
|
127
|
+
exports.Set("createWindow", Napi::Function::New(env, CreateWindow));
|
|
128
|
+
exports.Set("showAll", Napi::Function::New(env, ShowAll));
|
|
129
|
+
exports.Set("addToWindow", Napi::Function::New(env, AddToWindow));
|
|
130
|
+
|
|
131
|
+
// Inicializar las clases
|
|
132
|
+
extern Napi::Object InitButton(Napi::Env env, Napi::Object exports);
|
|
133
|
+
InitButton(env, exports);
|
|
134
|
+
|
|
135
|
+
// Inicializar el widget Label
|
|
136
|
+
extern Napi::Object InitLabel(Napi::Env env, Napi::Object exports);
|
|
137
|
+
InitLabel(env, exports);
|
|
138
|
+
|
|
139
|
+
// Inicializar el widget Box
|
|
140
|
+
extern Napi::Object InitBox(Napi::Env env, Napi::Object exports);
|
|
141
|
+
InitBox(env, exports);
|
|
142
|
+
|
|
143
|
+
// Inicializar el widget Scroll
|
|
144
|
+
extern Napi::Object InitScroll(Napi::Env env, Napi::Object exports);
|
|
145
|
+
InitScroll(env, exports);
|
|
146
|
+
|
|
147
|
+
return exports;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
NODE_API_MODULE(gtk3_node, Init)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Widget Box
|
|
2
|
+
|
|
3
|
+
El widget Box es parte de la colección de widgets para la extensión GTK3 para Node.js. Proporciona contenedores lineales (horizontales o verticales) para organizar otros widgets.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Contenedor lineal horizontal o vertical
|
|
8
|
+
- Soporta adición de múltiples widgets
|
|
9
|
+
- Compatible con el principio DRY
|
|
10
|
+
- Fácil integración con otros widgets
|
|
11
|
+
|
|
12
|
+
## API
|
|
13
|
+
|
|
14
|
+
### Constructor
|
|
15
|
+
- `new Box(orientacion)` - Crea un nuevo contenedor con la orientación especificada ('horizontal' o 'vertical')
|
|
16
|
+
|
|
17
|
+
### Métodos
|
|
18
|
+
- `add(widget)` - Agrega un widget al contenedor
|
|
19
|
+
|
|
20
|
+
## Ejemplo de Uso
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
const { Box, Label, Window, init, run } = require('../../index.js');
|
|
24
|
+
|
|
25
|
+
init();
|
|
26
|
+
const window = new Window('Ejemplo Box', 400, 300);
|
|
27
|
+
|
|
28
|
+
const box = new Box('vertical');
|
|
29
|
+
const label1 = new Label('Etiqueta 1');
|
|
30
|
+
const label2 = new Label('Etiqueta 2');
|
|
31
|
+
|
|
32
|
+
box.add(label1);
|
|
33
|
+
box.add(label2);
|
|
34
|
+
window.add(box);
|
|
35
|
+
window.show();
|
|
36
|
+
|
|
37
|
+
run();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Principio DRY
|
|
41
|
+
|
|
42
|
+
Este widget sigue el principio DRY (Don't Repeat Yourself) al reutilizar patrones comunes de implementación de widgets en la extensión GTK3 para Node.js.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <gtk/gtk.h>
|
|
3
|
+
|
|
4
|
+
// Estructura para almacenar datos del box
|
|
5
|
+
struct BoxData {
|
|
6
|
+
GtkWidget* box;
|
|
7
|
+
Napi::Env env;
|
|
8
|
+
|
|
9
|
+
BoxData(Napi::Env e) : box(nullptr), env(e) {}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Constructor de box
|
|
13
|
+
Napi::Value CreateBox(const Napi::CallbackInfo& info) {
|
|
14
|
+
Napi::Env env = info.Env();
|
|
15
|
+
|
|
16
|
+
GtkOrientation orientation_enum = GTK_ORIENTATION_HORIZONTAL; // Por defecto horizontal
|
|
17
|
+
if (info.Length() > 0 && info[0].IsString()) {
|
|
18
|
+
std::string orientation = info[0].As<Napi::String>().Utf8Value();
|
|
19
|
+
if (orientation == "vertical" || orientation == "VERTICAL") {
|
|
20
|
+
orientation_enum = GTK_ORIENTATION_VERTICAL;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
GtkWidget* box = gtk_box_new(orientation_enum, 5); // 5 pixels de espaciado
|
|
25
|
+
|
|
26
|
+
// Crear estructura de datos para el box
|
|
27
|
+
BoxData* box_data = new BoxData(env);
|
|
28
|
+
box_data->box = box;
|
|
29
|
+
|
|
30
|
+
// Guardar la estructura en los datos del widget
|
|
31
|
+
g_object_set_data_full(G_OBJECT(box), "box_data", box_data,
|
|
32
|
+
GDestroyNotify([](gpointer data) {
|
|
33
|
+
BoxData* box_data = static_cast<BoxData*>(data);
|
|
34
|
+
delete box_data;
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
// Convertir el widget a External para pasarlo a JavaScript
|
|
38
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
39
|
+
obj.Set("widget", Napi::External<GtkWidget>::New(env, box));
|
|
40
|
+
|
|
41
|
+
return obj;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Función para agregar un widget al box
|
|
45
|
+
Napi::Value AddToBox(const Napi::CallbackInfo& info) {
|
|
46
|
+
Napi::Env env = info.Env();
|
|
47
|
+
|
|
48
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsObject()) {
|
|
49
|
+
Napi::TypeError::New(env, "Se requieren dos objetos widget").ThrowAsJavaScriptException();
|
|
50
|
+
return Napi::Boolean::New(env, false);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Napi::Object containerObj = info[0].As<Napi::Object>();
|
|
54
|
+
Napi::Object widgetObj = info[1].As<Napi::Object>();
|
|
55
|
+
|
|
56
|
+
if (!containerObj.HasOwnProperty("widget") || !widgetObj.HasOwnProperty("widget")) {
|
|
57
|
+
Napi::TypeError::New(env, "Ambos objetos deben contener widgets válidos").ThrowAsJavaScriptException();
|
|
58
|
+
return Napi::Boolean::New(env, false);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Napi::External<GtkWidget> containerExt = containerObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
62
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
63
|
+
|
|
64
|
+
GtkWidget* container = containerExt.Data();
|
|
65
|
+
GtkWidget* widget = widgetExt.Data();
|
|
66
|
+
|
|
67
|
+
gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
|
|
68
|
+
|
|
69
|
+
return Napi::Boolean::New(env, true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Napi::Object InitBox(Napi::Env env, Napi::Object exports) {
|
|
73
|
+
exports.Set("createBox", Napi::Function::New(env, CreateBox));
|
|
74
|
+
exports.Set("addToBox", Napi::Function::New(env, AddToBox));
|
|
75
|
+
|
|
76
|
+
return exports;
|
|
77
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Widget Label
|
|
2
|
+
|
|
3
|
+
El widget Label es parte de la colección de widgets para la extensión GTK3 para Node.js. Proporciona una forma sencilla de mostrar texto estático en la interfaz de usuario.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Muestra texto estático en la interfaz
|
|
8
|
+
- Soporta texto multilínea
|
|
9
|
+
- Compatible con el principio DRY
|
|
10
|
+
- Fácil integración con otros widgets
|
|
11
|
+
|
|
12
|
+
## API
|
|
13
|
+
|
|
14
|
+
### Constructor
|
|
15
|
+
- `new Label(texto)` - Crea una nueva etiqueta con el texto especificado
|
|
16
|
+
|
|
17
|
+
### Propiedades
|
|
18
|
+
- `text` - El texto mostrado en la etiqueta (getter/setter)
|
|
19
|
+
|
|
20
|
+
### Métodos
|
|
21
|
+
- `setText(texto)` - Establece el texto de la etiqueta
|
|
22
|
+
- `getText()` - Obtiene el texto actual de la etiqueta
|
|
23
|
+
|
|
24
|
+
## Ejemplo de Uso
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const { Label, Window, init, run } = require('../../index.js');
|
|
28
|
+
|
|
29
|
+
init();
|
|
30
|
+
const window = new Window('Ejemplo Label', 300, 200);
|
|
31
|
+
|
|
32
|
+
const label = new Label('Hola Mundo!');
|
|
33
|
+
window.add(label);
|
|
34
|
+
window.show();
|
|
35
|
+
|
|
36
|
+
run();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Principio DRY
|
|
40
|
+
|
|
41
|
+
Este widget sigue el principio DRY (Don't Repeat Yourself) al reutilizar patrones comunes de implementación de widgets en la extensión GTK3 para Node.js.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <gtk/gtk.h>
|
|
3
|
+
|
|
4
|
+
// Estructura para almacenar datos del label
|
|
5
|
+
struct LabelData {
|
|
6
|
+
GtkWidget* label;
|
|
7
|
+
Napi::Env env;
|
|
8
|
+
|
|
9
|
+
LabelData(Napi::Env e) : label(nullptr), env(e) {}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Constructor de label
|
|
13
|
+
Napi::Value CreateLabel(const Napi::CallbackInfo& info) {
|
|
14
|
+
Napi::Env env = info.Env();
|
|
15
|
+
|
|
16
|
+
std::string text = "";
|
|
17
|
+
if (info.Length() > 0 && info[0].IsString()) {
|
|
18
|
+
text = info[0].As<Napi::String>().Utf8Value();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
GtkWidget* label = gtk_label_new(text.c_str());
|
|
22
|
+
|
|
23
|
+
// Crear estructura de datos para el label
|
|
24
|
+
LabelData* lbl_data = new LabelData(env);
|
|
25
|
+
lbl_data->label = label;
|
|
26
|
+
|
|
27
|
+
// Guardar la estructura en los datos del widget
|
|
28
|
+
g_object_set_data_full(G_OBJECT(label), "label_data", lbl_data,
|
|
29
|
+
GDestroyNotify([](gpointer data) {
|
|
30
|
+
LabelData* lbl_data = static_cast<LabelData*>(data);
|
|
31
|
+
delete lbl_data;
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
// Convertir el widget a External para pasarlo a JavaScript
|
|
35
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
36
|
+
obj.Set("widget", Napi::External<GtkWidget>::New(env, label));
|
|
37
|
+
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Función para establecer el texto del label
|
|
42
|
+
Napi::Value SetLabelText(const Napi::CallbackInfo& info) {
|
|
43
|
+
Napi::Env env = info.Env();
|
|
44
|
+
|
|
45
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsString()) {
|
|
46
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget y un texto").ThrowAsJavaScriptException();
|
|
47
|
+
return Napi::Boolean::New(env, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
51
|
+
std::string newText = info[1].As<Napi::String>().Utf8Value();
|
|
52
|
+
|
|
53
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
54
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
55
|
+
return Napi::Boolean::New(env, false);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
59
|
+
GtkWidget* label = widgetExt.Data();
|
|
60
|
+
|
|
61
|
+
gtk_label_set_text(GTK_LABEL(label), newText.c_str());
|
|
62
|
+
|
|
63
|
+
return Napi::Boolean::New(env, true);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Función para obtener el texto del label
|
|
67
|
+
Napi::Value GetLabelText(const Napi::CallbackInfo& info) {
|
|
68
|
+
Napi::Env env = info.Env();
|
|
69
|
+
|
|
70
|
+
if (info.Length() < 1 || !info[0].IsObject()) {
|
|
71
|
+
Napi::TypeError::New(env, "Se requiere un objeto widget").ThrowAsJavaScriptException();
|
|
72
|
+
return Napi::String::New(env, "");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Napi::Object widgetObj = info[0].As<Napi::Object>();
|
|
76
|
+
|
|
77
|
+
if (!widgetObj.HasOwnProperty("widget")) {
|
|
78
|
+
Napi::TypeError::New(env, "El objeto no contiene un widget válido").ThrowAsJavaScriptException();
|
|
79
|
+
return Napi::String::New(env, "");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
83
|
+
GtkWidget* label = widgetExt.Data();
|
|
84
|
+
|
|
85
|
+
const gchar* text = gtk_label_get_text(GTK_LABEL(label));
|
|
86
|
+
return Napi::String::New(env, text ? text : "");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
Napi::Object InitLabel(Napi::Env env, Napi::Object exports) {
|
|
90
|
+
exports.Set("createLabel", Napi::Function::New(env, CreateLabel));
|
|
91
|
+
exports.Set("setLabelText", Napi::Function::New(env, SetLabelText));
|
|
92
|
+
exports.Set("getLabelText", Napi::Function::New(env, GetLabelText));
|
|
93
|
+
|
|
94
|
+
return exports;
|
|
95
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Widget Scroll
|
|
2
|
+
|
|
3
|
+
El widget Scroll es parte de la colección de widgets para la extensión GTK3 para Node.js. Proporciona contenedores con barras de desplazamiento para manejar contenido que excede el área visible.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Contenedor con barras de desplazamiento vertical y horizontal
|
|
8
|
+
- Soporta adición de widgets hijos
|
|
9
|
+
- Compatible con el principio DRY
|
|
10
|
+
- Fácil integración con otros widgets
|
|
11
|
+
|
|
12
|
+
## API
|
|
13
|
+
|
|
14
|
+
### Constructor
|
|
15
|
+
- `new Scroll()` - Crea un nuevo contenedor con scroll
|
|
16
|
+
|
|
17
|
+
### Métodos
|
|
18
|
+
- `add(widget)` - Agrega un widget al contenedor con scroll
|
|
19
|
+
|
|
20
|
+
## Ejemplo de Uso
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
const { Scroll, Label, Window, init, run } = require('../../index.js');
|
|
24
|
+
|
|
25
|
+
init();
|
|
26
|
+
const window = new Window('Ejemplo Scroll', 300, 200);
|
|
27
|
+
|
|
28
|
+
const scroll = new Scroll();
|
|
29
|
+
const label = new Label('Contenido largo...');
|
|
30
|
+
|
|
31
|
+
scroll.add(label);
|
|
32
|
+
window.add(scroll);
|
|
33
|
+
window.show();
|
|
34
|
+
|
|
35
|
+
run();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Principio DRY
|
|
39
|
+
|
|
40
|
+
Este widget sigue el principio DRY (Don't Repeat Yourself) al reutilizar patrones comunes de implementación de widgets en la extensión GTK3 para Node.js.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <gtk/gtk.h>
|
|
3
|
+
|
|
4
|
+
// Estructura para almacenar datos del scroll
|
|
5
|
+
struct ScrollData {
|
|
6
|
+
GtkWidget* scroll;
|
|
7
|
+
Napi::Env env;
|
|
8
|
+
|
|
9
|
+
ScrollData(Napi::Env e) : scroll(nullptr), env(e) {}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Constructor de scroll
|
|
13
|
+
Napi::Value CreateScroll(const Napi::CallbackInfo& info) {
|
|
14
|
+
Napi::Env env = info.Env();
|
|
15
|
+
|
|
16
|
+
GtkWidget* scroll = gtk_scrolled_window_new(NULL, NULL);
|
|
17
|
+
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
|
18
|
+
GTK_POLICY_AUTOMATIC,
|
|
19
|
+
GTK_POLICY_AUTOMATIC);
|
|
20
|
+
|
|
21
|
+
// Crear estructura de datos para el scroll
|
|
22
|
+
ScrollData* scroll_data = new ScrollData(env);
|
|
23
|
+
scroll_data->scroll = scroll;
|
|
24
|
+
|
|
25
|
+
// Guardar la estructura en los datos del widget
|
|
26
|
+
g_object_set_data_full(G_OBJECT(scroll), "scroll_data", scroll_data,
|
|
27
|
+
GDestroyNotify([](gpointer data) {
|
|
28
|
+
ScrollData* scroll_data = static_cast<ScrollData*>(data);
|
|
29
|
+
delete scroll_data;
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
// Convertir el widget a External para pasarlo a JavaScript
|
|
33
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
34
|
+
obj.Set("widget", Napi::External<GtkWidget>::New(env, scroll));
|
|
35
|
+
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Función para agregar un widget al scroll
|
|
40
|
+
Napi::Value AddToScroll(const Napi::CallbackInfo& info) {
|
|
41
|
+
Napi::Env env = info.Env();
|
|
42
|
+
|
|
43
|
+
if (info.Length() < 2 || !info[0].IsObject() || !info[1].IsObject()) {
|
|
44
|
+
Napi::TypeError::New(env, "Se requieren dos objetos widget").ThrowAsJavaScriptException();
|
|
45
|
+
return Napi::Boolean::New(env, false);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Napi::Object containerObj = info[0].As<Napi::Object>();
|
|
49
|
+
Napi::Object widgetObj = info[1].As<Napi::Object>();
|
|
50
|
+
|
|
51
|
+
if (!containerObj.HasOwnProperty("widget") || !widgetObj.HasOwnProperty("widget")) {
|
|
52
|
+
Napi::TypeError::New(env, "Ambos objetos deben contener widgets válidos").ThrowAsJavaScriptException();
|
|
53
|
+
return Napi::Boolean::New(env, false);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Napi::External<GtkWidget> containerExt = containerObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
57
|
+
Napi::External<GtkWidget> widgetExt = widgetObj.Get("widget").As<Napi::External<GtkWidget>>();
|
|
58
|
+
|
|
59
|
+
GtkWidget* container = containerExt.Data();
|
|
60
|
+
GtkWidget* widget = widgetExt.Data();
|
|
61
|
+
|
|
62
|
+
gtk_container_add(GTK_CONTAINER(container), widget);
|
|
63
|
+
|
|
64
|
+
return Napi::Boolean::New(env, true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Napi::Object InitScroll(Napi::Env env, Napi::Object exports) {
|
|
68
|
+
exports.Set("createScroll", Napi::Function::New(env, CreateScroll));
|
|
69
|
+
exports.Set("addToScroll", Napi::Function::New(env, AddToScroll));
|
|
70
|
+
|
|
71
|
+
return exports;
|
|
72
|
+
}
|