gphoto4ruby 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,934 @@
1
+ /**
2
+ *
3
+ * Copyright 2008 neq4 company <http://neq4.com>
4
+ * Author: Sergey Kruk <sergey.kruk@gmail.com>
5
+ *
6
+ * This file is part of GPhoto4Ruby.
7
+ *
8
+ * GPhoto4Ruby is free software: you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation, either
11
+ * version 3 of the License, or (at your option) any later version.
12
+ *
13
+ * GPhoto4Ruby is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with GPhoto4Ruby. If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+ #include "gphoto2camera.h"
24
+
25
+ void camera_mark(GPhoto2Camera *c) {
26
+ }
27
+
28
+ void camera_free(GPhoto2Camera *c) {
29
+ gp_result_check(gp_camera_exit(c->camera, c->context));
30
+ gp_result_check(gp_widget_free(c->config));
31
+ gp_result_check(gp_list_free(c->list));
32
+ gp_result_check(gp_file_free(c->file));
33
+ gp_result_check(gp_camera_free(c->camera));
34
+ free(c->virtFolder);
35
+ free(c->context);
36
+ free(c);
37
+ }
38
+
39
+ VALUE camera_allocate(VALUE klass) {
40
+ GPhoto2Camera *c;
41
+ c = (GPhoto2Camera*) malloc(sizeof(GPhoto2Camera));
42
+ c->virtFolder = (char*) malloc(sizeof(char)*100);
43
+ strcpy(c->virtFolder, "/");
44
+ c->context = gp_context_new();
45
+ gp_result_check(gp_camera_new(&(c->camera)));
46
+ gp_result_check(gp_list_new(&(c->list)));
47
+ gp_result_check(gp_file_new(&(c->file)));
48
+ return Data_Wrap_Struct(klass, camera_mark, camera_free, c);
49
+ }
50
+
51
+ void camera_event_mark(GPhoto2CameraEvent *ce) {
52
+ }
53
+
54
+ void camera_event_free(GPhoto2CameraEvent *ce) {
55
+ free(ce);
56
+ }
57
+
58
+ /*
59
+ * call-seq:
60
+ * GPhoto2::Camera.new(port=nil)
61
+ *
62
+ * Returns camera object. Camera should be connected at a time constructor
63
+ * is called. If there is more than one camera connected through usb ports,
64
+ * port parameter can be passed to specify which camera is addressed with
65
+ * object.
66
+ *
67
+ * Examples:
68
+ *
69
+ * GPhoto2::Camera.new
70
+ * GPhoto2::Capera.new(GPhoto2::Camera.ports[0])
71
+ *
72
+ */
73
+ VALUE camera_initialize(int argc, VALUE *argv, VALUE self) {
74
+ GPhoto2Camera *c;
75
+ VALUE cfgs;
76
+
77
+ Data_Get_Struct(self, GPhoto2Camera, c);
78
+
79
+ switch (argc) {
80
+ case 0:
81
+ break;
82
+ case 1:
83
+ Check_Type(argv[0], T_STRING);
84
+ int portIndex;
85
+ GPPortInfoList *portInfoList;
86
+ GPPortInfo p;
87
+
88
+ gp_result_check(gp_port_info_list_new(&portInfoList));
89
+ gp_result_check(gp_port_info_list_load(portInfoList));
90
+ portIndex = gp_result_check(gp_port_info_list_lookup_path(portInfoList, RSTRING(argv[0])->ptr));
91
+ gp_result_check(gp_port_info_list_get_info(portInfoList, portIndex, &p));
92
+ gp_result_check(gp_camera_set_port_info(c->camera, p));
93
+ break;
94
+ default:
95
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
96
+ return Qnil;
97
+ }
98
+
99
+ gp_result_check(gp_camera_get_config(c->camera, &(c->config), c->context));
100
+ cfgs = rb_hash_new();
101
+ populateWithConfigs(c->config, cfgs);
102
+ rb_iv_set(self, "@configuration", cfgs);
103
+ rb_iv_set(self, "@configs_changed", rb_ary_new());
104
+
105
+ return self;
106
+ }
107
+
108
+ /*
109
+ * call-seq:
110
+ * GPhoto2::Camera.ports => array
111
+ *
112
+ * Returns an array of usb port paths with cameras. Port paths are the same
113
+ * as in <b>gphoto2 --auto-detect</b> output. Assuming that if there are
114
+ * cameras detected with long port paths, then the one with short port path
115
+ * is a duplicate of one of the others.
116
+ *
117
+ * Examples:
118
+ *
119
+ * # with one camera connected
120
+ * GPhoto2::Camera.ports #=> ["usb:"]
121
+ * # with two cameras connected
122
+ * GPhoto2::Camera.ports #=> ["usb:005,004", "usb:005,006"]
123
+ *
124
+ */
125
+ VALUE camera_class_ports(VALUE klass) {
126
+ int i, camsTotal, retVal;
127
+ GPContext *context;
128
+ CameraAbilitiesList *abilList;
129
+ GPPortInfoList *portInfoList;
130
+ CameraList *camList;
131
+ const char *pName = NULL;
132
+ VALUE arr = rb_ary_new();
133
+
134
+ context = gp_context_new();
135
+ retVal = gp_port_info_list_new(&portInfoList);
136
+ if (retVal == GP_OK) {
137
+ retVal = gp_port_info_list_load(portInfoList);
138
+ if (retVal == GP_OK) {
139
+ retVal = gp_abilities_list_new(&abilList);
140
+ if (retVal == GP_OK) {
141
+ retVal = gp_abilities_list_load(abilList, context);
142
+ if (retVal == GP_OK) {
143
+ retVal = gp_list_new(&camList);
144
+ if (retVal == GP_OK) {
145
+ retVal = gp_abilities_list_detect(abilList, portInfoList, camList, context);
146
+ if (retVal == GP_OK) {
147
+ retVal = gp_list_count(camList);
148
+ if (retVal >= GP_OK) {
149
+ camsTotal = retVal;
150
+ for(i = 0; i < camsTotal; i++) {
151
+ retVal = gp_list_get_value(camList, i, &pName);
152
+ if ((retVal == GP_OK) &&
153
+ ((camsTotal == 1) || (strlen(pName) > 4))) {
154
+ rb_ary_push(arr, rb_str_new2(pName));
155
+ }
156
+ }
157
+ }
158
+ }
159
+ gp_list_free(camList);
160
+ }
161
+ }
162
+ gp_abilities_list_free(abilList);
163
+ }
164
+ }
165
+ gp_port_info_list_free(portInfoList);
166
+ }
167
+ free(context);
168
+ if (retVal < GP_OK) {
169
+ rb_raise_gp_result(retVal);
170
+ }
171
+ return arr;
172
+ }
173
+
174
+ /*
175
+ * call-seq:
176
+ * capture(config={}) => camera
177
+ *
178
+ * Sends command to camera to capture image with current or provided
179
+ * configuration. Provided configuration is kept after capture.
180
+ *
181
+ * Examples:
182
+ *
183
+ * c = GPhoto2::Camera.new
184
+ * c.capture
185
+ * c.capture "exptime" => "0.010", "iso" => "400"
186
+ *
187
+ */
188
+ VALUE camera_capture(int argc, VALUE *argv, VALUE self) {
189
+ GPhoto2Camera *c;
190
+
191
+ Data_Get_Struct(self, GPhoto2Camera, c);
192
+
193
+ if (argc == 1) {
194
+ camera_config_merge(self, argv[0]);
195
+ } else if (argc != 0) {
196
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
197
+ return Qnil;
198
+ }
199
+
200
+ gp_result_check(gp_camera_capture(c->camera, GP_CAPTURE_IMAGE, &(c->path), c->context));
201
+ strcpy(c->virtFolder, c->path.folder);
202
+ // printf("captured: %s/%s\n", c->path.folder, c->path.name);
203
+ return self;
204
+ }
205
+
206
+ /*
207
+ * call-seq:
208
+ * save(options={}) => camera
209
+ *
210
+ * Downloads file from camera to hard drive.
211
+ * Available options are:
212
+ * * :file - Name of the file to download from camera. File is expected
213
+ * to be found in current path. If this option is not specified, last
214
+ * captured image is downloaded. If symbols <b>:first</b> or <b>:last</b>
215
+ * are passed, the first or the last file from current camera path is
216
+ * downloaded.
217
+ * * :new_name - New file name to be used when saving file on hard drive.
218
+ * If this option is not specified, camera file system filename is used.
219
+ * * :to_folder - Folder path on hard drive to save downloaded image to.
220
+ * * :type - Type of file to download from camera. Available types are
221
+ * <b>:normal</b> (default) and <b>:preview</b>
222
+ *
223
+ * Examples:
224
+ *
225
+ * c = GPhoto2::Camera.new
226
+ * c.capture.save :type => :preview, => Downloads preview of
227
+ * :new_name => "PREVIEW.JPG" captured image
228
+ * c.save :file => "DSC_0144.JPG", => Downloads specified file
229
+ * :to_folder => "/home/user", to /home/user/xyz.gf.JPG
230
+ * :new_name => "xyz.gf",
231
+ *
232
+ */
233
+ VALUE camera_save(int argc, VALUE *argv, VALUE self) {
234
+ int i, count;
235
+ int newName = 0;
236
+ CameraFileType fileType = GP_FILE_TYPE_NORMAL;
237
+ GPhoto2Camera *c;
238
+ const char *fData, *key, *val, *name;
239
+ char *fPath, *newNameStr, *pchNew, *pchSrc;
240
+ char fName[100], cFileName[100], cFolderName[100];
241
+ unsigned long int fSize;
242
+ int fd;
243
+ VALUE arr, hVal;
244
+
245
+ Data_Get_Struct(self, GPhoto2Camera, c);
246
+
247
+ strcpy(fName, "");
248
+ strcpy(cFileName, c->path.name);
249
+ strcpy(cFolderName, c->path.folder);
250
+
251
+ gp_result_check(gp_filesystem_reset(c->camera->fs));
252
+
253
+ switch(argc) {
254
+ case 0:
255
+ break;
256
+ case 1:
257
+ Check_Type(argv[0], T_HASH);
258
+ arr = rb_funcall(argv[0], rb_intern("keys"), 0);
259
+ for (i = 0; i < RARRAY(arr)->len; i++) {
260
+ switch(TYPE(RARRAY(arr)->ptr[i])) {
261
+ case T_STRING:
262
+ key = RSTRING(RARRAY(arr)->ptr[i])->ptr;
263
+ break;
264
+ case T_SYMBOL:
265
+ key = rb_id2name(rb_to_id(RARRAY(arr)->ptr[i]));
266
+ break;
267
+ default:
268
+ rb_raise(rb_eTypeError, "Not valid key type");
269
+ return Qnil;
270
+ }
271
+ if (strcmp(key, "to_folder") == 0) {
272
+ fPath = RSTRING(rb_hash_aref(argv[0], RARRAY(arr)->ptr[i]))->ptr;
273
+ if (strlen(fPath) > 0) {
274
+ if (fPath[strlen(fPath)] == '/') {
275
+ strcpy(fName, fPath);
276
+ } else {
277
+ strcpy(fName, fPath);
278
+ strcat(fName, "/");
279
+ }
280
+ }
281
+ } else if (strcmp(key, "new_name") == 0) {
282
+ newNameStr = RSTRING(rb_hash_aref(argv[0], RARRAY(arr)->ptr[i]))->ptr;
283
+ if (strlen(newNameStr) > 0) {
284
+ newName = 1;
285
+ }
286
+ } else if (strcmp(key, "type") == 0) {
287
+ hVal = rb_hash_aref(argv[0], RARRAY(arr)->ptr[i]);
288
+ Check_Type(hVal, T_SYMBOL);
289
+ val = rb_id2name(rb_to_id(hVal));
290
+ if (strcmp(val, "normal") == 0) {
291
+ fileType = GP_FILE_TYPE_NORMAL;
292
+ } else if (strcmp(val, "preview") == 0) {
293
+ fileType = GP_FILE_TYPE_PREVIEW;
294
+ }
295
+ } else if (strcmp(key, "file") == 0) {
296
+ hVal = rb_hash_aref(argv[0], RARRAY(arr)->ptr[i]);
297
+ switch(TYPE(hVal)) {
298
+ case T_STRING:
299
+ strcpy(cFolderName, c->virtFolder);
300
+ strcpy(cFileName, RSTRING(hVal)->ptr);
301
+ break;
302
+ case T_SYMBOL:
303
+ val = rb_id2name(rb_to_id(hVal));
304
+ gp_result_check(gp_camera_folder_list_files(c->camera, c->virtFolder, c->list, c->context));
305
+ if (strcmp(val, "first") == 0) {
306
+ count = 0;
307
+ } else if (strcmp(val, "last") == 0) {
308
+ count = gp_result_check(gp_list_count(c->list)) - 1;
309
+ } else {
310
+ count = -1;
311
+ }
312
+ gp_result_check(gp_list_get_name(c->list, count, &name));
313
+ strcpy(cFileName, name);
314
+ break;
315
+ default:
316
+ rb_raise(rb_eTypeError, "Not valid value type");
317
+ return Qnil;
318
+ }
319
+ }
320
+ }
321
+ break;
322
+ default:
323
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
324
+ return Qnil;
325
+ }
326
+
327
+ gp_result_check(gp_camera_file_get(c->camera, cFolderName, cFileName, fileType, c->file, c->context));
328
+ gp_result_check(gp_file_get_data_and_size(c->file, &fData, &fSize));
329
+ if (newName == 1) {
330
+ strcat(fName, newNameStr);
331
+ pchNew = strrchr(newNameStr, '.');
332
+ pchSrc = strrchr(cFileName, '.');
333
+ if (pchNew == NULL) {
334
+ strcat(fName, pchSrc);
335
+ } else if (strcmp(pchNew, pchSrc) != 0) {
336
+ strcat(fName, pchSrc);
337
+ }
338
+ } else {
339
+ strcat(fName, cFileName);
340
+ }
341
+ fd = open(fName, O_CREAT | O_WRONLY, 0644);
342
+ write(fd, fData, fSize);
343
+ close(fd);
344
+ return self;
345
+ }
346
+
347
+ /*
348
+ * call-seq:
349
+ * delete(options={}) => camera
350
+ *
351
+ * Deletes file from camera.
352
+ * Available options are:
353
+ * * :file - Name of the file to delete from camera. File is expected
354
+ * to be found in current path. If this option is not specified, last
355
+ * captured image is deleted.
356
+ *
357
+ * Examples:
358
+ *
359
+ * c = GPhoto2::Camera.new
360
+ * c.capture.save.delete
361
+ * c.delete :file => "DSC_0144.JPG"
362
+ * c.delete :all
363
+ *
364
+ */
365
+ VALUE camera_delete(int argc, VALUE *argv, VALUE self) {
366
+ int i;
367
+ int one = 1;
368
+ GPhoto2Camera *c;
369
+ const char *key;
370
+ char cFileName[100], cFolderName[100];
371
+ VALUE arr;
372
+
373
+ Data_Get_Struct(self, GPhoto2Camera, c);
374
+
375
+ strcpy(cFileName, c->path.name);
376
+ strcpy(cFolderName, c->path.folder);
377
+
378
+ switch(argc) {
379
+ case 0:
380
+ break;
381
+ case 1:
382
+ switch(TYPE(argv[0])) {
383
+ case T_HASH:
384
+ arr = rb_funcall(argv[0], rb_intern("keys"), 0);
385
+ for (i = 0; i < RARRAY(arr)->len; i++) {
386
+ switch(TYPE(RARRAY(arr)->ptr[i])) {
387
+ case T_STRING:
388
+ key = RSTRING(RARRAY(arr)->ptr[i])->ptr;
389
+ break;
390
+ case T_SYMBOL:
391
+ key = rb_id2name(rb_to_id(RARRAY(arr)->ptr[i]));
392
+ break;
393
+ default:
394
+ rb_raise(rb_eTypeError, "Not valid key type");
395
+ return Qnil;
396
+ }
397
+ if (strcmp(key, "file") == 0) {
398
+ strcpy(cFolderName, c->virtFolder);
399
+ strcpy(cFileName, RSTRING(rb_hash_aref(argv[0], RARRAY(arr)->ptr[i]))->ptr);
400
+ }
401
+ }
402
+ break;
403
+ case T_SYMBOL:
404
+ key = rb_id2name(rb_to_id(argv[0]));
405
+ if (strcmp(key, "all") == 0) {
406
+ strcpy(cFolderName, c->virtFolder);
407
+ one = 0;
408
+ }
409
+ break;
410
+ }
411
+ break;
412
+ default:
413
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
414
+ return Qnil;
415
+ }
416
+
417
+ gp_result_check(gp_filesystem_reset(c->camera->fs));
418
+ if (one == 1) {
419
+ gp_result_check(gp_camera_file_delete(c->camera, cFolderName, cFileName, c->context));
420
+ } else {
421
+ gp_result_check(gp_camera_folder_delete_all(c->camera, cFolderName, c->context));
422
+ }
423
+ return self;
424
+ }
425
+
426
+ /*
427
+ * call-seq:
428
+ * config => hash
429
+ *
430
+ * Returns cached hash of adjustable camera configuration with their values.
431
+ *
432
+ * Examples:
433
+ *
434
+ * c = GPhoto2::Camera.new
435
+ * # with Nikon DSC D80
436
+ * c.config.keys #=> ["capturetarget", "imgquality",
437
+ * "imgsize", "whitebalance",
438
+ * "f-number", "focallength",
439
+ * "focusmode", "iso",
440
+ * "exposurebiascompensation",
441
+ * "exptime", "expprogram",
442
+ * "capturemode", "focusmetermode",
443
+ * "exposuremetermode", "flashmode",
444
+ * "burstnumber", "accessmode",
445
+ * "channel", "encryption"]
446
+ *
447
+ */
448
+ VALUE camera_get_config(VALUE self) {
449
+ return rb_iv_get(self, "@configuration");
450
+ }
451
+
452
+ /*
453
+ * call-seq:
454
+ * config_merge(hash) => hash
455
+ *
456
+ * Adjusts camera configuration with given values.
457
+ *
458
+ * Examples:
459
+ *
460
+ * c = GPhoto2::Camera.new
461
+ * # with Nikon DSC D80
462
+ * c.config_merge "f-number" => "f/4", "exptime" => "0.010", "iso" => "200"
463
+ *
464
+ */
465
+ VALUE camera_config_merge(VALUE self, VALUE hash) {
466
+ Check_Type(hash, T_HASH);
467
+
468
+ int i;
469
+ const char *key;
470
+ GPhoto2Camera *c;
471
+ CameraWidgetType widgettype;
472
+ VALUE arr, cfgs, cfg_changed;
473
+
474
+ Data_Get_Struct(self, GPhoto2Camera, c);
475
+
476
+ arr = rb_funcall(hash, rb_intern("keys"), 0);
477
+ cfgs = rb_iv_get(self, "@configuration");
478
+ cfg_changed = rb_iv_get(self, "@configs_changed");
479
+ for (i = 0; i < RARRAY(arr)->len; i++) {
480
+ switch(TYPE(RARRAY(arr)->ptr[i])) {
481
+ case T_STRING:
482
+ key = RSTRING(RARRAY(arr)->ptr[i])->ptr;
483
+ break;
484
+ case T_SYMBOL:
485
+ key = rb_id2name(rb_to_id(RARRAY(arr)->ptr[i]));
486
+ break;
487
+ default:
488
+ rb_raise(rb_eTypeError, "Not valid key type");
489
+ return Qnil;
490
+ }
491
+ if (TYPE(rb_funcall(cfgs, rb_intern("has_key?"), 1, rb_str_new2(key))) == T_TRUE) {
492
+ gp_result_check(gp_widget_get_child_by_name(c->config, key, &(c->childConfig)));
493
+ gp_result_check(gp_widget_get_type(c->childConfig, &widgettype));
494
+ switch (widgettype) {
495
+ case GP_WIDGET_RADIO:
496
+ rb_ary_push(cfg_changed, rb_str_new2(key));
497
+ setRadio(self, c, rb_hash_aref(hash, RARRAY(arr)->ptr[i]), 0);
498
+ break;
499
+ case GP_WIDGET_TEXT:
500
+ rb_ary_push(cfg_changed, rb_str_new2(key));
501
+ setText(self, c, rb_hash_aref(hash, RARRAY(arr)->ptr[i]), 0);
502
+ break;
503
+ case GP_WIDGET_RANGE:
504
+ rb_ary_push(cfg_changed, rb_str_new2(key));
505
+ setRange(self, c, rb_hash_aref(hash, RARRAY(arr)->ptr[i]), 0);
506
+ break;
507
+ case GP_WIDGET_TOGGLE:
508
+ rb_ary_push(cfg_changed, rb_str_new2(key));
509
+ setToggle(self, c, rb_hash_aref(hash, RARRAY(arr)->ptr[i]), 0);
510
+ break;
511
+ default:
512
+ break;
513
+ }
514
+ }
515
+ }
516
+ saveConfigs(self, c);
517
+ return cfgs;
518
+ }
519
+
520
+ /*
521
+ * call-seq:
522
+ * cam[cfg] => float or string
523
+ * cam[cfg, :all] => array
524
+ * cam[cfg, :type] => fixnum
525
+ *
526
+ * Returns current value of specified camera configuration. Configuration name
527
+ * (cfg) can be string or symbol and must be in configs method returned array.
528
+ * Configuration is cached in @configuration instance variable.
529
+ *
530
+ * Possible directives:
531
+ * * <b>:no_cache</b> doesn't use cached configuration value
532
+ * * <b>:all</b> returns an array of allowed values;
533
+ * * <b>:type</b> returns one of available CONFIG_TYPE constats
534
+ *
535
+ * Examples:
536
+ *
537
+ * c = GPhoto2::Camera.new
538
+ * # with Nikon DSC D80
539
+ * c["f-number"] #=> "f/4.5"
540
+ * c[:focallength] #=> 10.5
541
+ * c[:focusmode, :all] #=> ["Manual", "AF-S", "AF-C", "AF-A"]
542
+ * c[:exptime, :type] == GPhoto2::Camera::CONFIG_TYPE_RADIO
543
+ * #=> true
544
+ *
545
+ */
546
+ VALUE camera_get_value(int argc, VALUE *argv, VALUE self) {
547
+ const char *name;
548
+ GPhoto2Camera *c;
549
+ CameraWidgetType widgettype;
550
+ VALUE str, dir;
551
+
552
+ switch (argc) {
553
+ case 1:
554
+ str = argv[0];
555
+ break;
556
+ case 2:
557
+ str = argv[0];
558
+ dir = argv[1];
559
+ Check_Type(dir, T_SYMBOL);
560
+ break;
561
+ default:
562
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 1 or 2)", argc);
563
+ return Qnil;
564
+ }
565
+
566
+ switch (TYPE(str)) {
567
+ case T_STRING:
568
+ name = RSTRING(str)->ptr;
569
+ break;
570
+ case T_SYMBOL:
571
+ name = rb_id2name(rb_to_id(str));
572
+ break;
573
+ default:
574
+ rb_raise(rb_eTypeError, "Not valid parameter type");
575
+ return Qnil;
576
+ }
577
+
578
+ if (argc == 1) {
579
+ return rb_hash_aref(rb_iv_get(self, "@configuration"), rb_str_new2(name));
580
+ } else {
581
+ Data_Get_Struct(self, GPhoto2Camera, c);
582
+
583
+ gp_result_check(gp_widget_get_child_by_name(c->config, name, &(c->childConfig)));
584
+ gp_result_check(gp_widget_get_type(c->childConfig, &widgettype));
585
+ switch (widgettype) {
586
+ case GP_WIDGET_RADIO:
587
+ if (strcmp(rb_id2name(rb_to_id(dir)), "no_cache") == 0) {
588
+ return getRadio(c->childConfig);
589
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
590
+ return listRadio(c->childConfig);
591
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "type") == 0) {
592
+ return INT2FIX(GP_WIDGET_RADIO);
593
+ } else {
594
+ rb_raise(rb_cGPhoto2ConfigurationError, "Unknown directive '%s'", rb_id2name(rb_to_id(dir)));
595
+ return Qnil;
596
+ }
597
+ break;
598
+ case GP_WIDGET_TEXT:
599
+ if (strcmp(rb_id2name(rb_to_id(dir)), "no_cache") == 0) {
600
+ return getText(c->childConfig);
601
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
602
+ return rb_ary_new();
603
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "type") == 0) {
604
+ return INT2FIX(GP_WIDGET_TEXT);
605
+ } else {
606
+ rb_raise(rb_cGPhoto2ConfigurationError, "Unknown directive '%s'", rb_id2name(rb_to_id(dir)));
607
+ return Qnil;
608
+ }
609
+ break;
610
+ case GP_WIDGET_RANGE:
611
+ if (strcmp(rb_id2name(rb_to_id(dir)), "no_cache") == 0) {
612
+ return getRange(c->childConfig);
613
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
614
+ return listRange(c->childConfig);
615
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "type") == 0) {
616
+ return INT2FIX(GP_WIDGET_RANGE);
617
+ } else {
618
+ rb_raise(rb_cGPhoto2ConfigurationError, "Unknown directive '%s'", rb_id2name(rb_to_id(dir)));
619
+ return Qnil;
620
+ }
621
+ break;
622
+ case GP_WIDGET_TOGGLE:
623
+ if (strcmp(rb_id2name(rb_to_id(dir)), "no_cache") == 0) {
624
+ return getToggle(c->childConfig);
625
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "all") == 0) {
626
+ VALUE arr = rb_ary_new();
627
+ rb_ary_push(arr, Qtrue);
628
+ rb_ary_push(arr, Qfalse);
629
+ return arr;
630
+ } else if (strcmp(rb_id2name(rb_to_id(dir)), "type") == 0) {
631
+ return INT2FIX(GP_WIDGET_TOGGLE);
632
+ } else {
633
+ rb_raise(rb_cGPhoto2ConfigurationError, "Unknown directive '%s'", rb_id2name(rb_to_id(dir)));
634
+ return Qnil;
635
+ }
636
+ break;
637
+ default:
638
+ rb_raise(rb_cGPhoto2ConfigurationError, "Not supported yet");
639
+ return Qnil;
640
+ }
641
+ }
642
+ }
643
+
644
+ /*
645
+ * call-seq:
646
+ * cam[cfg] = value => float or string
647
+ *
648
+ * Sets specified camera configuration to specified value if value is allowed.
649
+ *
650
+ * Examples:
651
+ *
652
+ * c = GPhoto2::Camera.new
653
+ * # with Nikon DSC D80
654
+ * c["f-number"] = "f/4.5" #=> "f/4.5"
655
+ * c[:focallength] = 10.5 #=> 10.5
656
+ *
657
+ */
658
+ VALUE camera_set_value(VALUE self, VALUE str, VALUE newVal) {
659
+ const char *name;
660
+ GPhoto2Camera *c;
661
+ CameraWidgetType widgettype;
662
+ VALUE cfg_changed;
663
+
664
+ switch (TYPE(str)) {
665
+ case T_STRING:
666
+ name = RSTRING(str)->ptr;
667
+ break;
668
+ case T_SYMBOL:
669
+ name = rb_id2name(rb_to_id(str));
670
+ break;
671
+ default:
672
+ rb_raise(rb_eTypeError, "Not valid parameter type");
673
+ return Qnil;
674
+ }
675
+
676
+ Data_Get_Struct(self, GPhoto2Camera, c);
677
+
678
+ gp_result_check(gp_widget_get_child_by_name(c->config, name, &(c->childConfig)));
679
+ gp_result_check(gp_widget_get_type(c->childConfig, &widgettype));
680
+ switch (widgettype) {
681
+ case GP_WIDGET_RADIO:
682
+ cfg_changed = rb_iv_get(self, "@configs_changed");
683
+ rb_ary_push(cfg_changed, rb_str_new2(name));
684
+ return setRadio(self, c, newVal, 1);
685
+ break;
686
+ case GP_WIDGET_TEXT:
687
+ cfg_changed = rb_iv_get(self, "@configs_changed");
688
+ rb_ary_push(cfg_changed, rb_str_new2(name));
689
+ return setText(self, c, newVal, 1);
690
+ break;
691
+ case GP_WIDGET_RANGE:
692
+ cfg_changed = rb_iv_get(self, "@configs_changed");
693
+ rb_ary_push(cfg_changed, rb_str_new2(name));
694
+ return setRange(self, c, newVal, 1);
695
+ break;
696
+ case GP_WIDGET_TOGGLE:
697
+ cfg_changed = rb_iv_get(self, "@configs_changed");
698
+ rb_ary_push(cfg_changed, rb_str_new2(name));
699
+ return setToggle(self, c, newVal, 1);
700
+ break;
701
+ default:
702
+ rb_raise(rb_cGPhoto2ConfigurationError, "Cannot access this setting");
703
+ return Qnil;
704
+ }
705
+ }
706
+
707
+ /*
708
+ * call-seq:
709
+ * folder => string
710
+ *
711
+ * Returns current camera path. When image is captured, folder changes to
712
+ * path where files are saved on camera.
713
+ *
714
+ * Examples:
715
+ *
716
+ * c = GPhoto2::Camera.new
717
+ * # with Nikon DSC D80
718
+ * c.folder #=> "/"
719
+ * c.capture
720
+ * c.folder #=> "/store_00010001/DCIM/100NCD80"
721
+ *
722
+ */
723
+ VALUE camera_folder(VALUE self) {
724
+ GPhoto2Camera *c;
725
+
726
+ Data_Get_Struct(self, GPhoto2Camera, c);
727
+
728
+ return rb_str_new2(c->virtFolder);
729
+ }
730
+
731
+ /*
732
+ * call-seq:
733
+ * subfolders => array
734
+ *
735
+ * Returns an array of subfolder names in current camera path.
736
+ *
737
+ * Examples:
738
+ *
739
+ * c = GPhoto2::Camera.new
740
+ * # with Nikon DSC D80
741
+ * c.folder #=> "/"
742
+ * c.subfolders #=> ["special", "store_00010001"]
743
+ *
744
+ */
745
+ VALUE camera_subfolders(VALUE self) {
746
+ int i, count;
747
+ const char *name;
748
+ GPhoto2Camera *c;
749
+ VALUE arr;
750
+
751
+ Data_Get_Struct(self, GPhoto2Camera, c);
752
+
753
+ gp_result_check(gp_camera_folder_list_folders(c->camera, c->virtFolder, c->list, c->context));
754
+ count = gp_result_check(gp_list_count(c->list));
755
+ arr = rb_ary_new();
756
+ for (i = 0; i < count; i++) {
757
+ gp_result_check(gp_list_get_name(c->list, i, &name));
758
+ rb_ary_push(arr, rb_str_new2(name));
759
+ }
760
+ return arr;
761
+ }
762
+
763
+ /*
764
+ * call-seq:
765
+ * files => array
766
+ *
767
+ * Returns an array of file names in current camera path.
768
+ *
769
+ * Examples:
770
+ *
771
+ * c = GPhoto2::Camera.new
772
+ * # with Nikon DSC D80
773
+ * c.folder #=> "/"
774
+ * c.files #=> []
775
+ * c.capture
776
+ * c.files #=> ["DSC_0001.JPG", "DSC_0002.JPG",
777
+ * "DSC_0003.JPG", ... ]
778
+ *
779
+ */
780
+ VALUE camera_files(VALUE self) {
781
+ int i, count;
782
+ const char *name;
783
+ GPhoto2Camera *c;
784
+ VALUE arr;
785
+
786
+ Data_Get_Struct(self, GPhoto2Camera, c);
787
+
788
+ gp_result_check(gp_filesystem_reset(c->camera->fs));
789
+ gp_result_check(gp_camera_folder_list_files(c->camera, c->virtFolder, c->list, c->context));
790
+ count = gp_result_check(gp_list_count(c->list));
791
+ arr = rb_ary_new();
792
+ for (i = 0; i < count; i++) {
793
+ gp_result_check(gp_list_get_name(c->list, i, &name));
794
+ rb_ary_push(arr, rb_str_new2(name));
795
+ }
796
+ return arr;
797
+ }
798
+
799
+ /*
800
+ * call-seq:
801
+ * folder_up => camera
802
+ *
803
+ * Changes current camera path one level up.
804
+ *
805
+ * Examples:
806
+ *
807
+ * c = GPhoto2::Camera.new
808
+ * # with Nikon DSC D80
809
+ * c.folder #=> "/"
810
+ * c.capture
811
+ * c.folder #=> "/store_00010001/DCIM/100NCD80"
812
+ * c.folder_up
813
+ * c.folder #=> "/store_00010001/DCIM"
814
+ * c.folder_up.folder_up #=> "/"
815
+ *
816
+ */
817
+ VALUE camera_folder_up(VALUE self) {
818
+ char *pch;
819
+ GPhoto2Camera *c;
820
+
821
+ Data_Get_Struct(self, GPhoto2Camera, c);
822
+
823
+ pch = strrchr(c->virtFolder, '/');
824
+ if ((pch - c->virtFolder) == 0) {
825
+ c->virtFolder[1] = '\0';
826
+ } else {
827
+ c->virtFolder[pch - c->virtFolder] = '\0';
828
+ }
829
+
830
+ return self;
831
+ }
832
+
833
+ /*
834
+ * call-seq:
835
+ * folder_down(name) => camera
836
+ *
837
+ * Changes current camera path one level down into subfolder with
838
+ * specified name.
839
+ *
840
+ * Examples:
841
+ *
842
+ * c = GPhoto2::Camera.new
843
+ * # with Nikon DSC D80
844
+ * c.folder #=> "/"
845
+ * c.folder_down "store_00010001"
846
+ * c.folder #=> "/store_00010001"
847
+ * c.folder_down("DCIM").folder_down("100NCD80")
848
+ * c.folder #=> "/store_00010001/DCIM/100NCD80"
849
+ *
850
+ */
851
+ VALUE camera_folder_down(VALUE self, VALUE folder) {
852
+ Check_Type(folder, T_STRING);
853
+
854
+ const char *name;
855
+ int index;
856
+ GPhoto2Camera *c;
857
+
858
+ Data_Get_Struct(self, GPhoto2Camera, c);
859
+
860
+ name = RSTRING(folder)->ptr;
861
+ gp_result_check(gp_camera_folder_list_folders(c->camera, c->virtFolder, c->list, c->context));
862
+ gp_result_check(gp_list_find_by_name(c->list, &index, name));
863
+ if (strlen(c->virtFolder) > 1) {
864
+ strcat(c->virtFolder, "/");
865
+ }
866
+ strcat(c->virtFolder, name);
867
+ return self;
868
+ }
869
+
870
+ /*
871
+ * call-seq:
872
+ * wait(timeout=2000) => camera event
873
+ *
874
+ * Waits for an event from camera for specified amount of milliseconds.
875
+ * Returns an instance of GPhoto2::CameraEvent. When capturing image manually
876
+ * with camera connected through USB, images are not saved on memory card
877
+ * until you call this method. During tests EVENT_TYPE_FILE_ADDED event
878
+ * was always followed by EVENT_TYPE_UNKNOWN. So in the case of
879
+ * EVENT_TYPE_FILE_ADDED or EVENT_TYPE_FOLDER_ADDED, an extra call is made
880
+ * with 100ms timeout which result is ignored.
881
+ *
882
+ * When image is captured manually and then event is caught, camera virtual
883
+ * folder is changed to the one where files are saved.
884
+ *
885
+ * Examples:
886
+ *
887
+ * c = GPhoto2::Camera.new
888
+ * # capture the image manually
889
+ * evt = c.wait
890
+ * evt.type #=> "file added"
891
+ * evt.type == GPhoto2::CameraEvent::EVENT_TYPE_FILE_ADDED
892
+ * #=> true
893
+ * evt.file #=> "DSC_0384.JPG"
894
+ *
895
+ * # do nothing
896
+ * c.wait(1).type #=> "timeout"
897
+ */
898
+ VALUE camera_wait(int argc, VALUE *argv, VALUE self) {
899
+ GPhoto2Camera *c;
900
+ GPhoto2CameraEvent *ce;
901
+ CameraEventType fakeType;
902
+ void *evtData, *fakeData;
903
+ int to;
904
+
905
+ switch (argc) {
906
+ case 0:
907
+ to = 2000;
908
+ break;
909
+ case 1:
910
+ to = FIX2INT(rb_funcall(argv[0], rb_intern("to_i"), 0));
911
+ break;
912
+ default:
913
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for 0 or 1)", argc);
914
+ return Qnil;
915
+ }
916
+
917
+ Data_Get_Struct(self, GPhoto2Camera, c);
918
+ ce = (GPhoto2CameraEvent*) malloc(sizeof(GPhoto2CameraEvent));
919
+
920
+ gp_result_check(gp_camera_wait_for_event(c->camera, to, &(ce->type), &evtData, c->context));
921
+
922
+ switch (ce->type) {
923
+ case GP_EVENT_FILE_ADDED:
924
+ case GP_EVENT_FOLDER_ADDED:
925
+ ce->path = (CameraFilePath*)evtData;
926
+ strcpy(c->virtFolder, ce->path->folder);
927
+ gp_result_check(gp_camera_wait_for_event(c->camera, 100, &fakeType, &fakeData, c->context));
928
+ break;
929
+ default:
930
+ break;
931
+ }
932
+ return Data_Wrap_Struct(rb_cGPhoto2CameraEvent, camera_event_mark, camera_event_free, ce);
933
+ }
934
+