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 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