curses 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|