gtk3-node 1.0.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -10,6 +10,8 @@
10
10
  - Widget Label para mostrar texto estático
11
11
  - Widget Box para layouts horizontales y verticales
12
12
  - Widget Scroll para contenedores con barras de desplazamiento
13
+ - Widget Entry para entrada de texto simple
14
+ - Widget StringGrid para tablas bidimensionales de datos
13
15
  - Estructura modular para futuras expansiones
14
16
  - Ejemplos organizados por niveles de complejidad
15
17
  - Principio DRY aplicado en la arquitectura
package/CHECKLIST.md CHANGED
@@ -42,13 +42,36 @@
42
42
  - [x] Documentación completa
43
43
  - [x] Ejemplos funcionales
44
44
 
45
- ## Widgets Pendientes
45
+ ### Entry
46
+ - [x] Creación de campos de texto simples
47
+ - [x] Soporte para entrada de texto
48
+ - [x] Lectura de texto ingresado
49
+ - [x] Escritura de texto programática
50
+ - [x] Documentación completa
51
+ - [x] Ejemplos funcionales
46
52
 
47
- ### Entry
48
- - [ ] Campo de texto para entrada simple
53
+ ### StringGrid
54
+ - [x] Creación de tablas bidimensionales
55
+ - [x] Soporte para filas y columnas
56
+ - [x] Establecimiento de encabezados
57
+ - [x] Agregar filas de datos
58
+ - [x] Modificación de celdas
59
+ - [x] Edición interactiva de celdas
60
+ - [x] Selección de filas
61
+ - [x] Callbacks de eventos
62
+ - [x] Documentación completa
63
+ - [x] Ejemplos funcionales
49
64
 
50
- ### TextView
51
- - [ ] Área de texto multilinea
65
+ ### TextView
66
+ - [x] Área de texto multilinea para entradas más largas
67
+ - [x] Soporte para texto largo y desplazamiento
68
+ - [x] Lectura y escritura de texto
69
+ - [x] Añadir texto al contenido existente
70
+ - [x] Insertar texto en posiciones específicas
71
+ - [x] Documentación completa
72
+ - [x] Ejemplos funcionales
73
+
74
+ ## Widgets Pendientes
52
75
 
53
76
  ### ❌ CheckButton
54
77
  - [ ] Casilla de verificación
@@ -70,7 +93,7 @@
70
93
 
71
94
  ## Estado General
72
95
 
73
- - **Total Widgets Implementados:** 4/12
74
- - **Estado de la Extensión:** Funcional para casos básicos
96
+ - **Total Widgets Implementados:** 6/12
97
+ - **Estado de la Extensión:** Funcional para casos básicos e intermedios
75
98
  - **Compatibilidad:** GTK3, Linux
76
99
  - **Principio DRY:** Aplicado en toda la arquitectura
package/binding.gyp ADDED
@@ -0,0 +1,59 @@
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
+ "widgets/entry/entry.cpp",
12
+ "widgets/stringgrid/stringgrid.cpp",
13
+ "widgets/textview/textview.cpp"
14
+ ],
15
+ "include_dirs": [
16
+ "<!@(node -p \"require('node-addon-api').include\")",
17
+ "/usr/include/gtk-3.0",
18
+ "/usr/include/glib-2.0",
19
+ "/usr/lib/x86_64-linux-gnu/glib-2.0/include",
20
+ "/usr/include/pango-1.0",
21
+ "/usr/include/harfbuzz",
22
+ "/usr/include/freetype2",
23
+ "/usr/include/libpng16",
24
+ "/usr/include/libmount",
25
+ "/usr/include/blkid",
26
+ "/usr/include/fribidi",
27
+ "/usr/include/cairo",
28
+ "/usr/include/pixman-1",
29
+ "/usr/include/gdk-pixbuf-2.0",
30
+ "/usr/include/x86_64-linux-gnu",
31
+ "/usr/include/gio-unix-2.0",
32
+ "/usr/include/atk-1.0",
33
+ "/usr/include/at-spi2-atk/2.0",
34
+ "/usr/include/at-spi-2.0",
35
+ "/usr/include/dbus-1.0",
36
+ "/usr/lib/x86_64-linux-gnu/dbus-1.0/include"
37
+ ],
38
+ "libraries": [
39
+ "-lgtk-3",
40
+ "-lgobject-2.0",
41
+ "-lglib-2.0",
42
+ "-lgdk-3",
43
+ "-lpango-1.0",
44
+ "-lcairo",
45
+ "-lgdk_pixbuf-2.0",
46
+ "-latk-1.0"
47
+ ],
48
+ "cflags": [
49
+ "-std=c++17"
50
+ ],
51
+ "cflags_cc": [
52
+ "-std=c++17"
53
+ ],
54
+ "defines": [
55
+ "NAPI_DISABLE_CPP_EXCEPTIONS"
56
+ ]
57
+ }
58
+ ]
59
+ }
@@ -6,6 +6,8 @@ Este directorio contiene ejemplos complejos que demuestran el uso combinado de m
6
6
 
7
7
  - `ejemplo_completo.js` - Ejemplo con botón y 35 labels organizadas en layouts horizontales y verticales
8
8
  - `ejemplo_scroll.js` - Ejemplo con Scroll, Labels y Buttons en la misma ventana
9
+ - `ejemplo_stringgrid_completo.js` - Ejemplo completo del StringGrid con todas sus capacidades
10
+ - `ejemplo_textview.js` - Ejemplo del widget TextView
9
11
 
10
12
  ## Objetivo
11
13
 
@@ -0,0 +1,95 @@
1
+ // ejemplo_stringgrid_completo.js - Ejemplo completo del StringGrid con todas sus capacidades
2
+
3
+ const { StringGrid, Entry, Label, Button, Box, Scroll, Window, init, run } = require('../../index.js');
4
+
5
+ // Inicializar GTK
6
+ init();
7
+
8
+ // Crear una ventana
9
+ const ventana = new Window('StringGrid Completo', 900, 700);
10
+
11
+ // Crear un contenedor con scroll
12
+ const scroll = new Scroll();
13
+
14
+ // Crear un layout vertical
15
+ const layout = new Box('vertical');
16
+
17
+ // Crear un StringGrid con 15 filas y 5 columnas
18
+ const grid = new StringGrid(15, 5);
19
+
20
+ // Establecer encabezados
21
+ grid.setHeader(['Nombre', 'Edad', 'Ciudad', 'País', 'Activo']);
22
+
23
+ // Agregar algunas filas de ejemplo
24
+ grid.addRow(['Juan Pérez', '30', 'Madrid', 'España', 'Sí']);
25
+ grid.addRow(['Ana García', '25', 'Barcelona', 'España', 'No']);
26
+ grid.addRow(['Carlos López', '35', 'Buenos Aires', 'Argentina', 'Sí']);
27
+ grid.addRow(['María Rodríguez', '28', 'Ciudad de México', 'México', 'Sí']);
28
+ grid.addRow(['Pedro Fernández', '42', 'Bogotá', 'Colombia', 'No']);
29
+
30
+ // Crear controles para la interacción
31
+ const controlsLayout = new Box('horizontal');
32
+
33
+ const labelInfo = new Label('Información: ');
34
+ const entryInput = new Entry('Texto para celda');
35
+ const buttonUpdate = new Button('Actualizar Celda (0,0)');
36
+ const buttonGetSelected = new Button('Obtener Selección');
37
+ const labelSelection = new Label('Selección: Ninguna');
38
+
39
+ // Variables para almacenar la selección actual
40
+ let selectedRow = -1;
41
+ let selectedCol = -1;
42
+
43
+ // Registrar un callback para cuando se edita una celda
44
+ grid.registerCellEditCallback((info) => {
45
+ console.log(`Celda editada: fila=${info.row}, col=${info.col}, nuevo_valor="${info.newValue}"`);
46
+ labelInfo.text = `Celda (${info.row},${info.col}) actualizada a: "${info.newValue}"`;
47
+ });
48
+
49
+ // Agregar un manejador de eventos al botón de actualizar
50
+ buttonUpdate.onClick(() => {
51
+ const texto = entryInput.text;
52
+ console.log(`Actualizando celda (0,0) con: ${texto}`);
53
+ grid.setCellValue(0, 0, texto);
54
+ labelInfo.text = `Celda (0,0) actualizada a: "${texto}"`;
55
+ });
56
+
57
+ // Agregar un manejador de eventos al botón de obtener selección
58
+ buttonGetSelected.onClick(() => {
59
+ const selection = grid.getSelectedCell();
60
+ selectedRow = selection.row;
61
+ selectedCol = selection.col;
62
+
63
+ if (selection.row !== -1) {
64
+ const cellValue = grid.getCell(selection.row, 0); // Obtener valor de la primera columna
65
+ labelSelection.text = `Fila seleccionada: ${selection.row}, Valor: "${cellValue}"`;
66
+ console.log(`Fila seleccionada: ${selection.row}, Columna: ${selection.col}`);
67
+ } else {
68
+ labelSelection.text = 'Ninguna fila seleccionada';
69
+ }
70
+ });
71
+
72
+ // Agregar widgets al layout de controles
73
+ controlsLayout.add(labelInfo);
74
+ controlsLayout.add(entryInput);
75
+ controlsLayout.add(buttonUpdate);
76
+ controlsLayout.add(buttonGetSelected);
77
+ controlsLayout.add(labelSelection);
78
+
79
+ // Agregar widgets al layout principal
80
+ layout.add(grid);
81
+ layout.add(controlsLayout);
82
+
83
+ // Agregar el layout al contenedor con scroll
84
+ scroll.add(layout);
85
+
86
+ // Agregar el scroll a la ventana
87
+ ventana.add(scroll);
88
+
89
+ // Mostrar la ventana y todos sus contenidos
90
+ ventana.show();
91
+
92
+ console.log('Interfaz con StringGrid completa lista. Abriendo ventana...');
93
+
94
+ // Iniciar el loop de eventos GTK para mostrar la interfaz
95
+ run();
@@ -0,0 +1,65 @@
1
+ // ejemplo_textview.js - Ejemplo del widget TextView
2
+
3
+ const { TextView, Button, Label, Box, Scroll, Window, init, run } = require('../../index.js');
4
+
5
+ // Inicializar GTK
6
+ init();
7
+
8
+ // Crear una ventana
9
+ const ventana = new Window('Ejemplo TextView', 600, 500);
10
+
11
+ // Crear un contenedor con scroll para el TextView
12
+ const scroll = new Scroll();
13
+
14
+ // Crear un TextView con texto inicial
15
+ const textView = new TextView('Hola,\neste es un ejemplo de TextView\ncon múltiples líneas.\n\nPuedes editar este texto directamente.');
16
+
17
+ // Crear controles para interactuar con el TextView
18
+ const controlsLayout = new Box('vertical');
19
+
20
+ const labelInfo = new Label('Usa los botones para interactuar con el TextView');
21
+ const buttonGetText = new Button('Obtener Texto');
22
+ const buttonSetText = new Button('Establecer Texto');
23
+ const buttonAppend = new Button('Añadir Texto');
24
+
25
+ // Agregar manejadores de eventos a los botones
26
+ buttonGetText.onClick(() => {
27
+ const text = textView.text;
28
+ console.log('Texto actual del TextView:', text);
29
+ labelInfo.text = `Caracteres: ${text.length}`;
30
+ });
31
+
32
+ buttonSetText.onClick(() => {
33
+ textView.text = 'Texto completamente nuevo\nEscrito desde JavaScript\nCon múltiples líneas';
34
+ labelInfo.text = 'Texto actualizado';
35
+ });
36
+
37
+ buttonAppend.onClick(() => {
38
+ textView.appendText('\n\nTexto añadido al final');
39
+ labelInfo.text = 'Texto añadido al final';
40
+ });
41
+
42
+ // Agregar widgets al layout de controles
43
+ controlsLayout.add(labelInfo);
44
+ controlsLayout.add(buttonGetText);
45
+ controlsLayout.add(buttonSetText);
46
+ controlsLayout.add(buttonAppend);
47
+
48
+ // Agregar el TextView al contenedor con scroll
49
+ scroll.add(textView);
50
+
51
+ // Crear un layout principal
52
+ const mainLayout = new Box('vertical');
53
+ mainLayout.add(scroll);
54
+ mainLayout.add(controlsLayout);
55
+
56
+ // Agregar el layout principal a la ventana
57
+ ventana.add(mainLayout);
58
+
59
+ // Mostrar la ventana y todos sus contenidos
60
+ ventana.show();
61
+
62
+ console.log('Interfaz con TextView lista. Abriendo ventana...');
63
+
64
+ // Iniciar el loop de eventos GTK para mostrar la interfaz
65
+ run();
@@ -6,6 +6,7 @@ Este directorio contiene ejemplos que muestran el uso combinado de múltiples wi
6
6
 
7
7
  - `ejemplo_label.js` - Ejemplo con widget Label y manipulación de texto
8
8
  - `ejemplo_label_boton.js` - Ejemplo con Label y Button en la misma ventana
9
+ - `ejemplo_entry.js` - Ejemplo con Entry, Label y Button en la misma ventana
9
10
 
10
11
  ## Objetivo
11
12
 
@@ -0,0 +1,50 @@
1
+ // ejemplo_entry.js - Ejemplo con Entry, Label y Button en la misma ventana
2
+
3
+ const { Button, Label, Entry, Box, Scroll, Window, init, run } = require('../../index.js');
4
+
5
+ // Inicializar GTK
6
+ init();
7
+
8
+ // Crear una ventana
9
+ const ventana = new Window('Ejemplo Entry, Label y Button', 500, 400);
10
+
11
+ // Crear un contenedor con scroll
12
+ const scroll = new Scroll();
13
+
14
+ // Crear un layout vertical
15
+ const layout = new Box('vertical');
16
+
17
+ // Crear un label para mostrar el texto del entry
18
+ const label = new Label('Ingresa texto en el campo de abajo y haz clic en el botón');
19
+
20
+ // Crear un entry
21
+ const entry = new Entry('Texto inicial...');
22
+
23
+ // Crear un botón
24
+ const boton = new Button('Obtener texto del Entry');
25
+
26
+ // Agregar un manejador de eventos al botón
27
+ boton.onClick(() => {
28
+ const textoEntrada = entry.text;
29
+ console.log('Texto del entry:', textoEntrada);
30
+ label.text = `Texto ingresado: "${textoEntrada}"`;
31
+ });
32
+
33
+ // Agregar widgets al layout
34
+ layout.add(label);
35
+ layout.add(entry);
36
+ layout.add(boton);
37
+
38
+ // Agregar el layout al contenedor con scroll
39
+ scroll.add(layout);
40
+
41
+ // Agregar el scroll a la ventana
42
+ ventana.add(scroll);
43
+
44
+ // Mostrar la ventana y todos sus contenidos
45
+ ventana.show();
46
+
47
+ console.log('Interfaz con Entry, Label y Button lista. Abriendo ventana...');
48
+
49
+ // Iniciar el loop de eventos GTK para mostrar la interfaz
50
+ run();
package/index.js CHANGED
@@ -66,6 +66,88 @@ class Scroll {
66
66
  }
67
67
  }
68
68
 
69
+ class Entry {
70
+ constructor(text = "") {
71
+ this.widget = gtk3_native.createEntry(text);
72
+ }
73
+
74
+ set text(content) {
75
+ gtk3_native.setEntryText(this.widget, content);
76
+ }
77
+
78
+ get text() {
79
+ return gtk3_native.getEntryText(this.widget);
80
+ }
81
+
82
+ setText(content) {
83
+ this.text = content;
84
+ }
85
+
86
+ getText() {
87
+ return this.text;
88
+ }
89
+ }
90
+
91
+ class StringGrid {
92
+ constructor(rows = 10, cols = 5) {
93
+ this.widget = gtk3_native.createStringGrid(rows, cols);
94
+ }
95
+
96
+ setCellValue(row, col, value) {
97
+ return gtk3_native.setGridCellValue(this.widget, row, col, value);
98
+ }
99
+
100
+ getCell(row, col) {
101
+ return gtk3_native.getGridCell(this.widget, row, col);
102
+ }
103
+
104
+ setHeader(headers) {
105
+ return gtk3_native.setGridHeader(this.widget, headers);
106
+ }
107
+
108
+ addRow(data) {
109
+ return gtk3_native.addGridRow(this.widget, data);
110
+ }
111
+
112
+ getSelectedCell() {
113
+ return gtk3_native.getSelectedCell(this.widget);
114
+ }
115
+
116
+ registerCellEditCallback(callback) {
117
+ return gtk3_native.registerCellEditCallback(this.widget, callback);
118
+ }
119
+ }
120
+
121
+ class TextView {
122
+ constructor(text = "") {
123
+ this.widget = gtk3_native.createTextView(text);
124
+ }
125
+
126
+ set text(content) {
127
+ gtk3_native.setTextViewText(this.widget, content);
128
+ }
129
+
130
+ get text() {
131
+ return gtk3_native.getTextViewText(this.widget);
132
+ }
133
+
134
+ setText(content) {
135
+ this.text = content;
136
+ }
137
+
138
+ getText() {
139
+ return this.text;
140
+ }
141
+
142
+ appendText(content) {
143
+ return gtk3_native.appendTextViewText(this.widget, content);
144
+ }
145
+
146
+ insertText(position, content) {
147
+ return gtk3_native.insertTextViewText(this.widget, position, content);
148
+ }
149
+ }
150
+
69
151
  class Window {
70
152
  constructor(title = "Ventana", width = 400, height = 300) {
71
153
  this.widget = gtk3_native.createWindow(title, width, height);
@@ -99,6 +181,9 @@ module.exports = {
99
181
  Label,
100
182
  Box,
101
183
  Scroll,
184
+ Entry,
185
+ StringGrid,
186
+ TextView,
102
187
  Window,
103
188
  // Mantener compatibilidad hacia atrás
104
189
  createWindow: gtk3_native.createWindow,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtk3-node",
3
- "version": "1.0.0",
3
+ "version": "1.2.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
+ }