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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cde762b5d566d153efcb872a949cdd742ee678351642f99ff4142a302792f54
4
- data.tar.gz: 3cacf0b68211f369d99b23592bb3e1035ab8d56f31c64ffb713ae573b30068c9
3
+ metadata.gz: 0c8cd5188348efc3da97bd7fd52aaf748636da0278c9d08d9b3a8aef9bd124f9
4
+ data.tar.gz: 98afd30e1daa2bee1a50f2f3f037ffbf503acd2befa84d89ee3fe3f6f0e62e83
5
5
  SHA512:
6
- metadata.gz: c113a50e510eb659797ce295982c44e8c8d5355eb7ef9506b9d20b7a98ca92053960da5edc333d7b9fb0e9cfa659b4339abb25859d2bda4126227dce8e2ad17b
7
- data.tar.gz: 8fde98598b7c32632bfdab0c0f92564d32088e311754c0c39ec905012ad874718e4a8b69f0953c9ff280de4ef399cb7c874908396a307a77118a72efdea5cb4d
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
@@ -30,7 +30,7 @@ Or
30
30
 
31
31
  ## Documentation
32
32
 
33
- See [http://www.rubydoc.info/gems/curses](http://www.rubydoc.info/gems/curses).
33
+ See [https://www.rubydoc.info/gems/curses](https://www.rubydoc.info/gems/curses).
34
34
 
35
35
  ## Developers
36
36
 
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=Y"
32
- cp "pdcurses.dll", "../../x86-mingw32/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=Y"
35
- cp "pdcurses.dll", "../../x64-mingw32/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
- ext.cross_compiling do |_spec|
75
- bin_file = "vendor/#{_spec.platform}/PDCurses/pdcurses.dll"
76
- _spec.files += [bin_file]
77
- stage_file = "#{ext.tmp_dir}/#{_spec.platform}/stage/#{bin_file}"
78
- stage_dir = File.dirname(stage_file)
79
- directory stage_dir
80
- file stage_file => [stage_dir, bin_file] do
81
- cp bin_file, stage_file
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new { |s|
2
2
  s.name = "curses"
3
- s.version = "1.2.5"
3
+ s.version = "1.2.6"
4
4
  s.author = ["Shugo Maeda", 'Eric Hodel']
5
5
  s.email = ["shugo@ruby-lang.org", 'drbrain@segment7.net']
6
6
  s.homepage = "https://github.com/ruby/curses"
@@ -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
  }
@@ -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")
@@ -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
+
@@ -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.5
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: 2018-10-16 00:00:00.000000000 Z
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
- rubyforge_project:
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