curses 1.2.5 → 1.2.6
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.
- checksums.yaml +4 -4
- data/History.md +12 -0
- data/README.md +1 -1
- data/Rakefile +14 -12
- data/curses.gemspec +1 -1
- data/ext/curses/curses.c +590 -0
- data/ext/curses/extconf.rb +9 -0
- data/lib/curses.rb +73 -0
- data/sample/menu.rb +32 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8cd5188348efc3da97bd7fd52aaf748636da0278c9d08d9b3a8aef9bd124f9
|
4
|
+
data.tar.gz: 98afd30e1daa2bee1a50f2f3f037ffbf503acd2befa84d89ee3fe3f6f0e62e83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5093a94321e82de364022d2e997263659a4ecbd0ce7528fcad780e09bbb08db7c172ee13805b6775d4dd9754e7581eafba50dd363f94aac7e458c9da9ee5af8b
|
7
|
+
data.tar.gz: 8e4e86a0884300c5dcd0c9da5974597eba4adcc0d4bb1ab31e648fdea2689cc50cf2d556e401a30b40a1ca9d9d3e6eedd664c1efaa44192d06dcd893e43d76f5
|
data/History.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
### 1.2.6 / 2019-01-09
|
2
|
+
|
3
|
+
New features:
|
4
|
+
|
5
|
+
* Add Curses::Menu and Curses::Item.
|
6
|
+
|
7
|
+
Bug fixes:
|
8
|
+
|
9
|
+
* Link PDCurses statically to avoid LoadError on mingw.
|
10
|
+
* Use https for documentation link. Pull request #43 by stomar.
|
11
|
+
* Fix typo in example code. Pull request #44 by stomar.
|
12
|
+
|
1
13
|
### 1.2.5 / 2018-10-16
|
2
14
|
|
3
15
|
New features:
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -28,11 +28,11 @@ namespace :build do
|
|
28
28
|
sh "nmake -f vcwin32.mak clean all WIDE=Y DLL=Y"
|
29
29
|
cp %w[pdcurses.dll pdcurses.lib], "../../#{RUBY_PLATFORM}/PDCurses"
|
30
30
|
else
|
31
|
-
sh "make -f mingwin32.mak clean all WIDE=Y DLL=
|
32
|
-
cp "pdcurses.
|
31
|
+
sh "make -f mingwin32.mak clean all WIDE=Y DLL=N"
|
32
|
+
cp "pdcurses.a", "../../x86-mingw32/PDCurses/libpdcurses.a"
|
33
33
|
|
34
|
-
sh "make -f mingwin32.mak clean all _w64=1 WIDE=Y DLL=
|
35
|
-
cp "pdcurses.
|
34
|
+
sh "make -f mingwin32.mak clean all _w64=1 WIDE=Y DLL=N"
|
35
|
+
cp "pdcurses.a", "../../x64-mingw32/PDCurses/libpdcurses.a"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -71,14 +71,16 @@ Rake::ExtensionTask.new(spec.name, spec) do |ext|
|
|
71
71
|
'x64-mingw32' => '--with-curses-lib=' +
|
72
72
|
File.expand_path("vendor/x64-mingw32/PDCurses", __dir__)
|
73
73
|
}
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
if $mswin
|
75
|
+
ext.cross_compiling do |_spec|
|
76
|
+
bin_file = "vendor/#{_spec.platform}/PDCurses/pdcurses.dll"
|
77
|
+
_spec.files += [bin_file]
|
78
|
+
stage_file = "#{ext.tmp_dir}/#{_spec.platform}/stage/#{bin_file}"
|
79
|
+
stage_dir = File.dirname(stage_file)
|
80
|
+
directory stage_dir
|
81
|
+
file stage_file => [stage_dir, bin_file] do
|
82
|
+
cp bin_file, stage_file
|
83
|
+
end
|
82
84
|
end
|
83
85
|
end
|
84
86
|
end
|
data/curses.gemspec
CHANGED
data/ext/curses/curses.c
CHANGED
@@ -51,6 +51,16 @@
|
|
51
51
|
# endif
|
52
52
|
#endif
|
53
53
|
|
54
|
+
#if defined(HAVE_NCURSESW_MENU_H)
|
55
|
+
# include <ncursesw/menu.h>
|
56
|
+
#elif defined(HAVE_NCURSES_MENU_H)
|
57
|
+
# include <ncurses/menu.h>
|
58
|
+
#elif defined(HAVE_CURSES_MENU_H)
|
59
|
+
# include <curses/menu.h>
|
60
|
+
#elif defined(HAVE_MENU_H)
|
61
|
+
# include <menu.h>
|
62
|
+
#endif
|
63
|
+
|
54
64
|
#ifdef HAVE_INIT_COLOR
|
55
65
|
# define USE_COLOR 1
|
56
66
|
#endif
|
@@ -70,12 +80,117 @@ static VALUE cPad;
|
|
70
80
|
#ifdef USE_MOUSE
|
71
81
|
static VALUE cMouseEvent;
|
72
82
|
#endif
|
83
|
+
#ifdef HAVE_MENU
|
84
|
+
static VALUE cItem;
|
85
|
+
static VALUE cMenu;
|
86
|
+
#endif
|
87
|
+
static VALUE eError;
|
88
|
+
static VALUE eSystemError;
|
89
|
+
static VALUE eBadArgumentError;
|
90
|
+
static VALUE ePostedError;
|
91
|
+
static VALUE eConnectedError;
|
92
|
+
static VALUE eBadStateError;
|
93
|
+
static VALUE eNoRoomError;
|
94
|
+
static VALUE eNotPostedError;
|
95
|
+
static VALUE eUnknownCommandError;
|
96
|
+
static VALUE eNoMatchError;
|
97
|
+
static VALUE eNotSelectableError;
|
98
|
+
static VALUE eNotConnectedError;
|
99
|
+
static VALUE eRequestDeniedError;
|
100
|
+
static VALUE eInvalidFieldError;
|
101
|
+
static VALUE eCurrentError;
|
73
102
|
|
74
103
|
static VALUE rb_stdscr;
|
75
104
|
|
76
105
|
static rb_encoding *keyboard_encoding;
|
77
106
|
static rb_encoding *terminal_encoding;
|
78
107
|
|
108
|
+
#ifndef E_OK
|
109
|
+
#define E_OK 0
|
110
|
+
#endif
|
111
|
+
|
112
|
+
static void
|
113
|
+
check_curses_error(int error)
|
114
|
+
{
|
115
|
+
switch (error) {
|
116
|
+
case E_OK:
|
117
|
+
break;
|
118
|
+
#ifdef E_SYSTEM_ERROR
|
119
|
+
case E_SYSTEM_ERROR:
|
120
|
+
rb_raise(eSystemError, "A system error occurred");
|
121
|
+
break;
|
122
|
+
#endif
|
123
|
+
#ifdef E_BAD_ARGUMENT
|
124
|
+
case E_BAD_ARGUMENT:
|
125
|
+
rb_raise(eBadArgumentError, "Incorrect or out-of-range argument");
|
126
|
+
break;
|
127
|
+
#endif
|
128
|
+
#ifdef E_POSTED
|
129
|
+
case E_POSTED:
|
130
|
+
rb_raise(ePostedError, "The menu has already been posted");
|
131
|
+
break;
|
132
|
+
#endif
|
133
|
+
#ifdef E_CONNECTED
|
134
|
+
case E_CONNECTED:
|
135
|
+
rb_raise(eConnectedError, "The field is already connected to a form");
|
136
|
+
break;
|
137
|
+
#endif
|
138
|
+
#ifdef E_BAD_STATE
|
139
|
+
case E_BAD_STATE:
|
140
|
+
rb_raise(eBadStateError, "Called from an initialization or termination function");
|
141
|
+
break;
|
142
|
+
#endif
|
143
|
+
#ifdef E_NO_ROOM
|
144
|
+
case E_NO_ROOM:
|
145
|
+
rb_raise(eNoRoomError, "Form is too large for its window");
|
146
|
+
break;
|
147
|
+
#endif
|
148
|
+
#ifdef E_NOT_POSTED
|
149
|
+
case E_NOT_POSTED:
|
150
|
+
rb_raise(eNotPostedError, "The menu has not been posted");
|
151
|
+
break;
|
152
|
+
#endif
|
153
|
+
#ifdef E_UNKNOWN_COMMAND
|
154
|
+
case E_UNKNOWN_COMMAND:
|
155
|
+
rb_raise(eUnknownCommandError, "Unknown command");
|
156
|
+
break;
|
157
|
+
#endif
|
158
|
+
#ifdef E_NO_MATCH
|
159
|
+
case E_NO_MATCH:
|
160
|
+
rb_raise(eNoMatchError, "Character failed to match");
|
161
|
+
break;
|
162
|
+
#endif
|
163
|
+
#ifdef E_NOT_SELECTABLE
|
164
|
+
case E_NOT_SELECTABLE:
|
165
|
+
rb_raise(eNotSelectableError, "The designated item cannot be selected");
|
166
|
+
break;
|
167
|
+
#endif
|
168
|
+
#ifdef E_NOT_CONNECTED
|
169
|
+
case E_NOT_CONNECTED:
|
170
|
+
rb_raise(eNotConnectedError, "No fields or items are connected");
|
171
|
+
break;
|
172
|
+
#endif
|
173
|
+
#ifdef E_REQUEST_DENIED
|
174
|
+
case E_REQUEST_DENIED:
|
175
|
+
rb_raise(eRequestDeniedError, "The request could not be processed");
|
176
|
+
break;
|
177
|
+
#endif
|
178
|
+
#ifdef E_INVALID_FIELD
|
179
|
+
case E_INVALID_FIELD:
|
180
|
+
rb_raise(eInvalidFieldError, "Contents of a field is not valid");
|
181
|
+
break;
|
182
|
+
#endif
|
183
|
+
#ifdef E_CURRENT
|
184
|
+
case E_CURRENT:
|
185
|
+
rb_raise(eCurrentError, "The field is the current field");
|
186
|
+
break;
|
187
|
+
#endif
|
188
|
+
default:
|
189
|
+
rb_raise(eError, "Unknown error");
|
190
|
+
break;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
79
194
|
struct windata {
|
80
195
|
WINDOW *window;
|
81
196
|
};
|
@@ -2899,6 +3014,420 @@ pad_noutrefresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow,
|
|
2899
3014
|
}
|
2900
3015
|
#endif /* HAVE_NEWPAD */
|
2901
3016
|
|
3017
|
+
#ifdef HAVE_MENU
|
3018
|
+
/*--------------------------- class Item ----------------------------*/
|
3019
|
+
|
3020
|
+
struct itemdata {
|
3021
|
+
ITEM *item;
|
3022
|
+
};
|
3023
|
+
|
3024
|
+
static void
|
3025
|
+
no_item(void)
|
3026
|
+
{
|
3027
|
+
rb_raise(rb_eRuntimeError, "already deleted item");
|
3028
|
+
}
|
3029
|
+
|
3030
|
+
#define GetITEM(obj, itemp) do {\
|
3031
|
+
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\
|
3032
|
+
rb_raise(rb_eSecurityError, "Insecure: operation on untainted item");\
|
3033
|
+
TypedData_Get_Struct((obj), struct itemdata, &itemdata_type, (itemp));\
|
3034
|
+
if ((itemp)->item == 0) no_item();\
|
3035
|
+
} while (0)
|
3036
|
+
|
3037
|
+
static void
|
3038
|
+
item_free(void *p)
|
3039
|
+
{
|
3040
|
+
struct itemdata *itemp = p;
|
3041
|
+
if (itemp->item) free_item(itemp->item);
|
3042
|
+
itemp->item = 0;
|
3043
|
+
xfree(itemp);
|
3044
|
+
}
|
3045
|
+
|
3046
|
+
static size_t
|
3047
|
+
item_memsize(const void *p)
|
3048
|
+
{
|
3049
|
+
const struct itemdata *itemp = p;
|
3050
|
+
size_t size = sizeof(*itemp);
|
3051
|
+
if (!itemp) return 0;
|
3052
|
+
if (itemp->item) size += sizeof(itemp->item);
|
3053
|
+
return size;
|
3054
|
+
}
|
3055
|
+
|
3056
|
+
static const rb_data_type_t itemdata_type = {
|
3057
|
+
"itemdata",
|
3058
|
+
{0, item_free, item_memsize,}
|
3059
|
+
};
|
3060
|
+
|
3061
|
+
/* returns a Curses::Item object */
|
3062
|
+
static VALUE
|
3063
|
+
item_s_allocate(VALUE class)
|
3064
|
+
{
|
3065
|
+
struct itemdata *itemp;
|
3066
|
+
|
3067
|
+
return TypedData_Make_Struct(class, struct itemdata, &itemdata_type, itemp);
|
3068
|
+
}
|
3069
|
+
|
3070
|
+
/*
|
3071
|
+
* Document-method: Curses::Item.new
|
3072
|
+
*
|
3073
|
+
* call-seq:
|
3074
|
+
* new(name, description)
|
3075
|
+
*
|
3076
|
+
* Construct a new Curses::Item.
|
3077
|
+
*/
|
3078
|
+
static VALUE
|
3079
|
+
item_initialize(VALUE obj, VALUE name, VALUE description)
|
3080
|
+
{
|
3081
|
+
struct itemdata *itemp;
|
3082
|
+
|
3083
|
+
curses_init_screen();
|
3084
|
+
TypedData_Get_Struct(obj, struct itemdata, &itemdata_type, itemp);
|
3085
|
+
if (itemp->item) {
|
3086
|
+
rb_raise(rb_eRuntimeError, "already initialized item");
|
3087
|
+
}
|
3088
|
+
name = rb_str_export_to_enc(name, terminal_encoding);
|
3089
|
+
description = rb_str_export_to_enc(description, terminal_encoding);
|
3090
|
+
itemp->item = new_item(StringValueCStr(name),
|
3091
|
+
StringValueCStr(description));
|
3092
|
+
if (itemp->item == NULL) {
|
3093
|
+
check_curses_error(errno);
|
3094
|
+
}
|
3095
|
+
|
3096
|
+
return obj;
|
3097
|
+
}
|
3098
|
+
|
3099
|
+
static VALUE
|
3100
|
+
item_new(ITEM *item)
|
3101
|
+
{
|
3102
|
+
VALUE obj = item_s_allocate(cItem);
|
3103
|
+
struct itemdata *itemp;
|
3104
|
+
|
3105
|
+
TypedData_Get_Struct(obj, struct itemdata, &itemdata_type, itemp);
|
3106
|
+
itemp->item = item;
|
3107
|
+
return obj;
|
3108
|
+
}
|
3109
|
+
|
3110
|
+
static VALUE
|
3111
|
+
item_eq(VALUE obj, VALUE other)
|
3112
|
+
{
|
3113
|
+
struct itemdata *item1, *item2;
|
3114
|
+
|
3115
|
+
GetITEM(obj, item1);
|
3116
|
+
GetITEM(other, item2);
|
3117
|
+
return item1->item == item2->item ? Qtrue : Qfalse;
|
3118
|
+
}
|
3119
|
+
|
3120
|
+
static VALUE
|
3121
|
+
item_name_m(VALUE obj)
|
3122
|
+
{
|
3123
|
+
struct itemdata *itemp;
|
3124
|
+
const char *name;
|
3125
|
+
|
3126
|
+
GetITEM(obj, itemp);
|
3127
|
+
name = item_name(itemp->item);
|
3128
|
+
return rb_external_str_new_with_enc(name, strlen(name), terminal_encoding);
|
3129
|
+
}
|
3130
|
+
|
3131
|
+
static VALUE
|
3132
|
+
item_description_m(VALUE obj)
|
3133
|
+
{
|
3134
|
+
struct itemdata *itemp;
|
3135
|
+
const char *desc;
|
3136
|
+
|
3137
|
+
GetITEM(obj, itemp);
|
3138
|
+
desc = item_description(itemp->item);
|
3139
|
+
return rb_external_str_new_with_enc(desc, strlen(desc), terminal_encoding);
|
3140
|
+
}
|
3141
|
+
|
3142
|
+
struct menudata {
|
3143
|
+
MENU *menu;
|
3144
|
+
VALUE items;
|
3145
|
+
};
|
3146
|
+
|
3147
|
+
static void
|
3148
|
+
no_menu(void)
|
3149
|
+
{
|
3150
|
+
rb_raise(rb_eRuntimeError, "already deleted menu");
|
3151
|
+
}
|
3152
|
+
|
3153
|
+
#define GetMENU(obj, menup) do {\
|
3154
|
+
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\
|
3155
|
+
rb_raise(rb_eSecurityError, "Insecure: operation on untainted menu");\
|
3156
|
+
TypedData_Get_Struct((obj), struct menudata, &menudata_type, (menup));\
|
3157
|
+
if ((menup)->menu == 0) no_menu();\
|
3158
|
+
} while (0)
|
3159
|
+
|
3160
|
+
static void
|
3161
|
+
menu_gc_mark(void *p)
|
3162
|
+
{
|
3163
|
+
struct menudata *menup = p;
|
3164
|
+
|
3165
|
+
rb_gc_mark(menup->items);
|
3166
|
+
}
|
3167
|
+
|
3168
|
+
static void
|
3169
|
+
menu_free(void *p)
|
3170
|
+
{
|
3171
|
+
struct menudata *menup = p;
|
3172
|
+
ITEM **items = menu_items(menup->menu);
|
3173
|
+
if (menup->menu) free_menu(menup->menu);
|
3174
|
+
xfree(items);
|
3175
|
+
menup->menu = 0;
|
3176
|
+
menup->items = Qnil;
|
3177
|
+
xfree(menup);
|
3178
|
+
}
|
3179
|
+
|
3180
|
+
static size_t
|
3181
|
+
menu_memsize(const void *p)
|
3182
|
+
{
|
3183
|
+
const struct menudata *menup = p;
|
3184
|
+
size_t size = sizeof(*menup);
|
3185
|
+
if (!menup) return 0;
|
3186
|
+
if (menup->menu) size += sizeof(menup->menu);
|
3187
|
+
return size;
|
3188
|
+
}
|
3189
|
+
|
3190
|
+
static const rb_data_type_t menudata_type = {
|
3191
|
+
"menudata",
|
3192
|
+
{menu_gc_mark, menu_free, menu_memsize,}
|
3193
|
+
};
|
3194
|
+
|
3195
|
+
/* returns a Curses::Menu object */
|
3196
|
+
static VALUE
|
3197
|
+
menu_s_allocate(VALUE class)
|
3198
|
+
{
|
3199
|
+
struct menudata *menup;
|
3200
|
+
|
3201
|
+
return TypedData_Make_Struct(class, struct menudata, &menudata_type, menup);
|
3202
|
+
}
|
3203
|
+
|
3204
|
+
/*
|
3205
|
+
* Document-method: Curses::Menu.new
|
3206
|
+
*
|
3207
|
+
* call-seq:
|
3208
|
+
* new(name, description)
|
3209
|
+
*
|
3210
|
+
* Construct a new Curses::Menu.
|
3211
|
+
*/
|
3212
|
+
static VALUE
|
3213
|
+
menu_initialize(VALUE obj, VALUE items)
|
3214
|
+
{
|
3215
|
+
struct menudata *menup;
|
3216
|
+
ITEM **menu_items;
|
3217
|
+
int i;
|
3218
|
+
|
3219
|
+
Check_Type(items, T_ARRAY);
|
3220
|
+
curses_init_screen();
|
3221
|
+
TypedData_Get_Struct(obj, struct menudata, &menudata_type, menup);
|
3222
|
+
if (menup->menu) {
|
3223
|
+
rb_raise(rb_eRuntimeError, "already initialized menu");
|
3224
|
+
}
|
3225
|
+
menu_items = ALLOC_N(ITEM *, RARRAY_LEN(items) + 1);
|
3226
|
+
for (i = 0; i < RARRAY_LEN(items); i++) {
|
3227
|
+
struct itemdata *itemp;
|
3228
|
+
|
3229
|
+
GetITEM(RARRAY_AREF(items, i), itemp);
|
3230
|
+
menu_items[i] = itemp->item;
|
3231
|
+
}
|
3232
|
+
menu_items[RARRAY_LEN(items)] = NULL;
|
3233
|
+
menup->menu = new_menu(menu_items);
|
3234
|
+
if (menup->menu == NULL) {
|
3235
|
+
check_curses_error(errno);
|
3236
|
+
}
|
3237
|
+
menup->items = rb_ary_dup(items);
|
3238
|
+
|
3239
|
+
return obj;
|
3240
|
+
}
|
3241
|
+
|
3242
|
+
/*
|
3243
|
+
* Document-method: Curses::Menu#post
|
3244
|
+
*
|
3245
|
+
* call-seq:
|
3246
|
+
* post
|
3247
|
+
*
|
3248
|
+
* Post the menu.
|
3249
|
+
*/
|
3250
|
+
static VALUE
|
3251
|
+
menu_post(VALUE obj)
|
3252
|
+
{
|
3253
|
+
struct menudata *menup;
|
3254
|
+
int error;
|
3255
|
+
|
3256
|
+
GetMENU(obj, menup);
|
3257
|
+
error = post_menu(menup->menu);
|
3258
|
+
check_curses_error(error);
|
3259
|
+
|
3260
|
+
return obj;
|
3261
|
+
}
|
3262
|
+
|
3263
|
+
/*
|
3264
|
+
* Document-method: Curses::Menu#unpost
|
3265
|
+
*
|
3266
|
+
* call-seq:
|
3267
|
+
* unpost
|
3268
|
+
*
|
3269
|
+
* Unpost the menu.
|
3270
|
+
*/
|
3271
|
+
static VALUE
|
3272
|
+
menu_unpost(VALUE obj)
|
3273
|
+
{
|
3274
|
+
struct menudata *menup;
|
3275
|
+
int error;
|
3276
|
+
|
3277
|
+
GetMENU(obj, menup);
|
3278
|
+
error = unpost_menu(menup->menu);
|
3279
|
+
check_curses_error(error);
|
3280
|
+
|
3281
|
+
return obj;
|
3282
|
+
}
|
3283
|
+
|
3284
|
+
/*
|
3285
|
+
* Document-method: Curses::Menu#driver
|
3286
|
+
*
|
3287
|
+
* call-seq:
|
3288
|
+
* driver(command)
|
3289
|
+
*
|
3290
|
+
* Perform the command on the menu.
|
3291
|
+
*/
|
3292
|
+
static VALUE
|
3293
|
+
menu_driver_m(VALUE obj, VALUE command)
|
3294
|
+
{
|
3295
|
+
struct menudata *menup;
|
3296
|
+
int error;
|
3297
|
+
|
3298
|
+
GetMENU(obj, menup);
|
3299
|
+
error = menu_driver(menup->menu, NUM2INT(command));
|
3300
|
+
check_curses_error(error);
|
3301
|
+
|
3302
|
+
return obj;
|
3303
|
+
}
|
3304
|
+
|
3305
|
+
/*
|
3306
|
+
* Document-method: Curses::Menu#item_count
|
3307
|
+
*
|
3308
|
+
* call-seq:
|
3309
|
+
* item_count
|
3310
|
+
*
|
3311
|
+
* Returns the count of items in the menu.
|
3312
|
+
*/
|
3313
|
+
static VALUE
|
3314
|
+
menu_item_count(VALUE obj)
|
3315
|
+
{
|
3316
|
+
struct menudata *menup;
|
3317
|
+
|
3318
|
+
GetMENU(obj, menup);
|
3319
|
+
return INT2NUM(item_count(menup->menu));
|
3320
|
+
}
|
3321
|
+
|
3322
|
+
/*
|
3323
|
+
* Document-method: Curses::Menu#items
|
3324
|
+
*
|
3325
|
+
* call-seq:
|
3326
|
+
* items
|
3327
|
+
*
|
3328
|
+
* Returns the items of the menu.
|
3329
|
+
*/
|
3330
|
+
static VALUE
|
3331
|
+
menu_get_items(VALUE obj)
|
3332
|
+
{
|
3333
|
+
struct menudata *menup;
|
3334
|
+
ITEM **items;
|
3335
|
+
int count, i;
|
3336
|
+
VALUE ary;
|
3337
|
+
|
3338
|
+
GetMENU(obj, menup);
|
3339
|
+
items = menu_items(menup->menu);
|
3340
|
+
if (items == NULL) {
|
3341
|
+
return Qnil;
|
3342
|
+
}
|
3343
|
+
count = item_count(menup->menu);
|
3344
|
+
ary = rb_ary_new();
|
3345
|
+
for (i = 0; i < count; i++) {
|
3346
|
+
rb_ary_push(ary, item_new(items[i]));
|
3347
|
+
}
|
3348
|
+
return ary;
|
3349
|
+
}
|
3350
|
+
|
3351
|
+
/*
|
3352
|
+
* Document-method: Curses::Menu#items=
|
3353
|
+
*
|
3354
|
+
* call-seq:
|
3355
|
+
* items=(items)
|
3356
|
+
*
|
3357
|
+
* Returns the items of the menu.
|
3358
|
+
*/
|
3359
|
+
static VALUE
|
3360
|
+
menu_set_items(VALUE obj, VALUE items)
|
3361
|
+
{
|
3362
|
+
struct menudata *menup;
|
3363
|
+
ITEM **old_items, **new_items;
|
3364
|
+
int i, error;
|
3365
|
+
|
3366
|
+
Check_Type(items, T_ARRAY);
|
3367
|
+
GetMENU(obj, menup);
|
3368
|
+
old_items = menu_items(menup->menu);
|
3369
|
+
new_items = ALLOC_N(ITEM*, RARRAY_LEN(items) + 1);
|
3370
|
+
for (i = 0; i < RARRAY_LEN(items); i++) {
|
3371
|
+
struct itemdata *itemp;
|
3372
|
+
GetITEM(RARRAY_AREF(items, i), itemp);
|
3373
|
+
new_items[i] = itemp->item;
|
3374
|
+
}
|
3375
|
+
new_items[RARRAY_LEN(items)] = NULL;
|
3376
|
+
error = set_menu_items(menup->menu, new_items);
|
3377
|
+
if (error != E_OK) {
|
3378
|
+
xfree(new_items);
|
3379
|
+
check_curses_error(error);
|
3380
|
+
return items;
|
3381
|
+
}
|
3382
|
+
xfree(old_items);
|
3383
|
+
menup->items = rb_ary_dup(items);
|
3384
|
+
return items;
|
3385
|
+
}
|
3386
|
+
|
3387
|
+
/*
|
3388
|
+
* Document-method: Curses::Menu#current_item
|
3389
|
+
*
|
3390
|
+
* call-seq:
|
3391
|
+
* current_item
|
3392
|
+
*
|
3393
|
+
* Returns the current item.
|
3394
|
+
*/
|
3395
|
+
static VALUE
|
3396
|
+
menu_get_current_item(VALUE obj)
|
3397
|
+
{
|
3398
|
+
struct menudata *menup;
|
3399
|
+
ITEM *item;
|
3400
|
+
|
3401
|
+
GetMENU(obj, menup);
|
3402
|
+
item = current_item(menup->menu);
|
3403
|
+
if (item == NULL) {
|
3404
|
+
return Qnil;
|
3405
|
+
}
|
3406
|
+
return item_new(item);
|
3407
|
+
}
|
3408
|
+
|
3409
|
+
/*
|
3410
|
+
* Document-method: Curses::Menu#current_item=
|
3411
|
+
*
|
3412
|
+
* call-seq:
|
3413
|
+
* current_item=(item)
|
3414
|
+
*
|
3415
|
+
* Sets the current item.
|
3416
|
+
*/
|
3417
|
+
static VALUE
|
3418
|
+
menu_set_current_item(VALUE obj, VALUE item)
|
3419
|
+
{
|
3420
|
+
struct menudata *menup;
|
3421
|
+
struct itemdata *itemp;
|
3422
|
+
|
3423
|
+
GetMENU(obj, menup);
|
3424
|
+
GetITEM(item, itemp);
|
3425
|
+
set_current_item(menup->menu, itemp->item);
|
3426
|
+
return item;
|
3427
|
+
}
|
3428
|
+
|
3429
|
+
#endif /* HAVE_MENU */
|
3430
|
+
|
2902
3431
|
/*
|
2903
3432
|
* Document-method: Curses.keyboard_encoding
|
2904
3433
|
* call-seq: Curses.keyboard_encoding
|
@@ -3444,6 +3973,47 @@ Init_curses(void)
|
|
3444
3973
|
rb_undef_method(cPad, "subwin");
|
3445
3974
|
#endif
|
3446
3975
|
|
3976
|
+
#ifdef HAVE_MENU
|
3977
|
+
cItem = rb_define_class_under(mCurses, "Item", rb_cData);
|
3978
|
+
rb_define_alloc_func(cItem, item_s_allocate);
|
3979
|
+
rb_define_method(cItem, "initialize", item_initialize, 2);
|
3980
|
+
rb_define_method(cItem, "==", item_eq, 1);
|
3981
|
+
rb_define_method(cItem, "name", item_name_m, 0);
|
3982
|
+
rb_define_method(cItem, "description", item_description_m, 0);
|
3983
|
+
|
3984
|
+
cMenu = rb_define_class_under(mCurses, "Menu", rb_cData);
|
3985
|
+
rb_define_alloc_func(cMenu, menu_s_allocate);
|
3986
|
+
rb_define_method(cMenu, "initialize", menu_initialize, 1);
|
3987
|
+
rb_define_method(cMenu, "post", menu_post, 0);
|
3988
|
+
rb_define_method(cMenu, "unpost", menu_unpost, 0);
|
3989
|
+
rb_define_method(cMenu, "driver", menu_driver_m, 1);
|
3990
|
+
rb_define_method(cMenu, "item_count", menu_item_count, 0);
|
3991
|
+
rb_define_method(cMenu, "items", menu_get_items, 0);
|
3992
|
+
rb_define_method(cMenu, "items=", menu_set_items, 1);
|
3993
|
+
rb_define_method(cMenu, "current_item", menu_get_current_item, 0);
|
3994
|
+
rb_define_method(cMenu, "current_item=", menu_set_current_item, 1);
|
3995
|
+
#endif
|
3996
|
+
|
3997
|
+
#define rb_curses_define_error(c) do { \
|
3998
|
+
e##c = rb_define_class_under(mCurses, #c, eError); \
|
3999
|
+
} while (0)
|
4000
|
+
|
4001
|
+
eError = rb_define_class_under(mCurses, "Error", rb_eStandardError);
|
4002
|
+
rb_curses_define_error(SystemError);
|
4003
|
+
rb_curses_define_error(BadArgumentError);
|
4004
|
+
rb_curses_define_error(PostedError);
|
4005
|
+
rb_curses_define_error(ConnectedError);
|
4006
|
+
rb_curses_define_error(BadStateError);
|
4007
|
+
rb_curses_define_error(NoRoomError);
|
4008
|
+
rb_curses_define_error(NotPostedError);
|
4009
|
+
rb_curses_define_error(UnknownCommandError);
|
4010
|
+
rb_curses_define_error(NoMatchError);
|
4011
|
+
rb_curses_define_error(NotSelectableError);
|
4012
|
+
rb_curses_define_error(NotConnectedError);
|
4013
|
+
rb_curses_define_error(RequestDeniedError);
|
4014
|
+
rb_curses_define_error(InvalidFieldError);
|
4015
|
+
rb_curses_define_error(CurrentError);
|
4016
|
+
|
3447
4017
|
#define rb_curses_define_const(c) rb_define_const(mCurses,#c,CHTYPE2NUM(c))
|
3448
4018
|
|
3449
4019
|
#ifdef USE_COLOR
|
@@ -4910,5 +5480,25 @@ Init_curses(void)
|
|
4910
5480
|
rb_curses_define_const(PDC_KEY_MODIFIER_ALT);
|
4911
5481
|
rb_curses_define_const(PDC_KEY_MODIFIER_NUMLOCK);
|
4912
5482
|
#endif
|
5483
|
+
|
5484
|
+
#ifdef HAVE_MENU
|
5485
|
+
rb_curses_define_const(REQ_LEFT_ITEM);
|
5486
|
+
rb_curses_define_const(REQ_RIGHT_ITEM);
|
5487
|
+
rb_curses_define_const(REQ_UP_ITEM);
|
5488
|
+
rb_curses_define_const(REQ_DOWN_ITEM);
|
5489
|
+
rb_curses_define_const(REQ_SCR_ULINE);
|
5490
|
+
rb_curses_define_const(REQ_SCR_DLINE);
|
5491
|
+
rb_curses_define_const(REQ_SCR_DPAGE);
|
5492
|
+
rb_curses_define_const(REQ_SCR_UPAGE);
|
5493
|
+
rb_curses_define_const(REQ_FIRST_ITEM);
|
5494
|
+
rb_curses_define_const(REQ_LAST_ITEM);
|
5495
|
+
rb_curses_define_const(REQ_NEXT_ITEM);
|
5496
|
+
rb_curses_define_const(REQ_PREV_ITEM);
|
5497
|
+
rb_curses_define_const(REQ_TOGGLE_ITEM);
|
5498
|
+
rb_curses_define_const(REQ_CLEAR_PATTERN);
|
5499
|
+
rb_curses_define_const(REQ_BACK_PATTERN);
|
5500
|
+
rb_curses_define_const(REQ_NEXT_MATCH);
|
5501
|
+
rb_curses_define_const(REQ_PREV_MATCH);
|
5502
|
+
#endif
|
4913
5503
|
#undef rb_curses_define_const
|
4914
5504
|
}
|
data/ext/curses/extconf.rb
CHANGED
@@ -141,6 +141,15 @@ if header_library
|
|
141
141
|
$defs << '-DPDC_DLL_BUILD'
|
142
142
|
end
|
143
143
|
|
144
|
+
if (have_header("ncursesw/menu.h") ||
|
145
|
+
have_header("ncurses/menu.h") ||
|
146
|
+
have_header("curses/menu.h") ||
|
147
|
+
have_header("menu.h")) &&
|
148
|
+
(have_library("menuw", "new_menu") ||
|
149
|
+
have_library("menu", "new_menu"))
|
150
|
+
$defs << '-DHAVE_MENU'
|
151
|
+
end
|
152
|
+
|
144
153
|
if RUBY_VERSION >= '2.1'
|
145
154
|
create_header
|
146
155
|
create_makefile("curses")
|
data/lib/curses.rb
CHANGED
@@ -21,3 +21,76 @@ end
|
|
21
21
|
if pdcurses_bundled
|
22
22
|
Curses.keyboard_encoding = Encoding::UTF_8
|
23
23
|
end
|
24
|
+
|
25
|
+
if defined?(Curses::Menu)
|
26
|
+
class Curses::Menu
|
27
|
+
def left_item
|
28
|
+
driver(Curses::REQ_LEFT_ITEM)
|
29
|
+
end
|
30
|
+
|
31
|
+
def right_item
|
32
|
+
driver(Curses::REQ_RIGHT_ITEM)
|
33
|
+
end
|
34
|
+
|
35
|
+
def up_item
|
36
|
+
driver(Curses::REQ_UP_ITEM)
|
37
|
+
end
|
38
|
+
|
39
|
+
def down_item
|
40
|
+
driver(Curses::REQ_DOWN_ITEM)
|
41
|
+
end
|
42
|
+
|
43
|
+
def scroll_up_line
|
44
|
+
driver(Curses::REQ_SCR_ULINE)
|
45
|
+
end
|
46
|
+
|
47
|
+
def scroll_down_line
|
48
|
+
driver(Curses::REQ_SCR_DLINE)
|
49
|
+
end
|
50
|
+
|
51
|
+
def scroll_up_page
|
52
|
+
driver(Curses::REQ_SCR_UPAGE)
|
53
|
+
end
|
54
|
+
|
55
|
+
def scroll_down_page
|
56
|
+
driver(Curses::REQ_SCR_DPAGE)
|
57
|
+
end
|
58
|
+
|
59
|
+
def first_item
|
60
|
+
driver(Curses::REQ_FIRST_ITEM)
|
61
|
+
end
|
62
|
+
|
63
|
+
def last_item
|
64
|
+
driver(Curses::REQ_LAST_ITEM)
|
65
|
+
end
|
66
|
+
|
67
|
+
def next_item
|
68
|
+
driver(Curses::REQ_NEXT_ITEM)
|
69
|
+
end
|
70
|
+
|
71
|
+
def prev_item
|
72
|
+
driver(Curses::REQ_PREV_ITEM)
|
73
|
+
end
|
74
|
+
|
75
|
+
def toggle_item
|
76
|
+
driver(Curses::REQ_TOGGLE_ITEM)
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear_pattern
|
80
|
+
driver(Curses::REQ_CLEAR_PATTERN)
|
81
|
+
end
|
82
|
+
|
83
|
+
def back_pattern
|
84
|
+
driver(Curses::REQ_BACK_PATTERN)
|
85
|
+
end
|
86
|
+
|
87
|
+
def next_match
|
88
|
+
driver(Curses::REQ_NEXT_MATCH)
|
89
|
+
end
|
90
|
+
|
91
|
+
def prev_match
|
92
|
+
driver(Curses::REQ_PREV_MATCH)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
data/sample/menu.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "curses"
|
2
|
+
|
3
|
+
Curses.init_screen
|
4
|
+
Curses.cbreak
|
5
|
+
Curses.noecho
|
6
|
+
Curses.stdscr.keypad = true
|
7
|
+
at_exit do
|
8
|
+
Curses.cloes_screen
|
9
|
+
end
|
10
|
+
|
11
|
+
menu = Curses::Menu.new([
|
12
|
+
Curses::Item.new("Apple", "Red fruit"),
|
13
|
+
Curses::Item.new("Orange", "Orange fruit"),
|
14
|
+
Curses::Item.new("Banana", "Yellow fruit")
|
15
|
+
])
|
16
|
+
menu.post
|
17
|
+
|
18
|
+
while ch = Curses.getch
|
19
|
+
begin
|
20
|
+
case ch
|
21
|
+
when Curses::KEY_UP, ?k
|
22
|
+
menu.up_item
|
23
|
+
when Curses::KEY_DOWN, ?j
|
24
|
+
menu.down_item
|
25
|
+
else
|
26
|
+
break
|
27
|
+
end
|
28
|
+
rescue Curses::RequestDeniedError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
menu.unpost
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curses
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-01-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- ext/curses/extconf.rb
|
79
79
|
- lib/curses.rb
|
80
80
|
- sample/hello.rb
|
81
|
+
- sample/menu.rb
|
81
82
|
- sample/mouse.rb
|
82
83
|
- sample/rain.rb
|
83
84
|
- sample/view.rb
|
@@ -102,8 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
103
|
- !ruby/object:Gem::Version
|
103
104
|
version: '0'
|
104
105
|
requirements: []
|
105
|
-
|
106
|
-
rubygems_version: 2.7.6
|
106
|
+
rubygems_version: 3.0.1
|
107
107
|
signing_key:
|
108
108
|
specification_version: 4
|
109
109
|
summary: A Ruby binding for curses, ncurses, and PDCurses. curses is an extension
|