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 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.0.0",
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,10 @@
1
+ #ifndef BOX_H
2
+ #define BOX_H
3
+
4
+ #include <napi.h>
5
+ #include <gtk/gtk.h>
6
+
7
+ // Función para inicializar el widget Box
8
+ Napi::Object InitBox(Napi::Env env, Napi::Object exports);
9
+
10
+ #endif // BOX_H
@@ -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,10 @@
1
+ #ifndef LABEL_H
2
+ #define LABEL_H
3
+
4
+ #include <napi.h>
5
+ #include <gtk/gtk.h>
6
+
7
+ // Función para inicializar el widget Label
8
+ Napi::Object InitLabel(Napi::Env env, Napi::Object exports);
9
+
10
+ #endif // LABEL_H
@@ -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
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef SCROLL_H
2
+ #define SCROLL_H
3
+
4
+ #include <napi.h>
5
+ #include <gtk/gtk.h>
6
+
7
+ // Función para inicializar el widget Scroll
8
+ Napi::Object InitScroll(Napi::Env env, Napi::Object exports);
9
+
10
+ #endif // SCROLL_H