~joel-auterson/ubuntu/maverick/shotwell/menu_rename

« back to all changes in this revision

Viewing changes to src/Dialogs.vala

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-05-26 14:29:53 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100526142953-fr4n1vvex23wq29j
Tags: 0.5.90-0ubuntu1
* New upstream release
* debian/control:
  - Build-depend on libraw-dev, libgexiv2-dev
  - Build-depend on liblaunchpad-integration-dev
  - Bump build-depend version of libgtk2.0-dev
  - Add BZR link
* debian/patches/01_lpi.patch:
  - Add Launchpad integration
* debian/patches/vala_0.8.0.patch:
  - Applied upstream
* debian/watch:
  - Watch for unstable releases

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright 2009 Yorba Foundation
 
1
/* Copyright 2009-2010 Yorba Foundation
2
2
 *
3
3
 * This software is licensed under the GNU LGPL (version 2.1 or later).
4
4
 * See the COPYING file in this distribution. 
7
7
namespace ExportUI {
8
8
private static File current_export_dir = null;
9
9
 
10
 
public File? choose_file(File current_file) {
 
10
public File? choose_file(string current_file_basename) {
11
11
    if (current_export_dir == null)
12
12
        current_export_dir = File.new_for_path(Environment.get_home_dir());
13
13
        
16
16
        Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT, null);
17
17
    chooser.set_do_overwrite_confirmation(true);
18
18
    chooser.set_current_folder(current_export_dir.get_path());
19
 
    chooser.set_current_name(current_file.get_basename());
 
19
    chooser.set_current_name(current_file_basename);
20
20
 
21
21
    File file = null;
22
22
    if (chooser.run() == Gtk.ResponseType.ACCEPT) {
49
49
    return dir;
50
50
}
51
51
 
52
 
public void export_photos(File folder, Gee.Collection<TransformablePhoto> photos) {
 
52
public void export_photos(File folder, Gee.Collection<TransformablePhoto> photos,
 
53
    Scaling scaling, Jpeg.Quality quality, PhotoFileFormat format) {
53
54
    ProgressDialog dialog = null;
54
55
    Cancellable cancellable = null;
55
56
    if (photos.size > 2) {
63
64
    int failed = 0;
64
65
    bool replace_all = false;
65
66
    foreach (TransformablePhoto photo in photos) {
66
 
        string basename = photo.get_file().get_basename();
 
67
        string basename = photo.get_export_basename(format);
67
68
        File dest = folder.get_child(basename);
68
69
        
69
70
        if (!replace_all && dest.query_exists(null)) {
104
105
            break;
105
106
        
106
107
        try {
107
 
            photo.export(dest, Scaling.for_original(), Jpeg.Quality.HIGH);
 
108
            photo.export(dest, scaling, quality, format);
108
109
        } catch (Error err) {
109
110
            failed++;
 
111
 
 
112
            Gtk.ResponseType response = run_export_error_dialog(dest, true);
 
113
            
 
114
            if (response == Gtk.ResponseType.CANCEL)
 
115
                break;
110
116
        }
111
117
        
112
118
        if (dialog != null) {
119
125
        dialog.close();
120
126
    
121
127
    AppWindow.get_instance().set_normal_cursor();
122
 
    
123
 
    if (failed > 0) {
124
 
        string msg = ngettext("Unable to export the photo due to a file error.",
125
 
            "Unable to export %d photos due to file errors.", failed).printf(failed);
126
 
        AppWindow.error_message(msg);
 
128
}
 
129
}
 
130
 
 
131
public Gtk.ResponseType run_export_error_dialog(File dest, bool photos_remaining = false) {
 
132
    string message = _("Unable to export the following photo due to a file error.\n\n") +
 
133
        dest.get_path();
 
134
 
 
135
    Gtk.ResponseType response = Gtk.ResponseType.NONE;
 
136
 
 
137
    if (photos_remaining) {
 
138
        message += _("\n\nWould you like to continue exporting?");
 
139
        response = AppWindow.affirm_cancel_question(message, _("Con_tinue"));
 
140
    } else {
 
141
        AppWindow.error_message(message);
127
142
    }
128
 
}
 
143
 
 
144
    return response;
129
145
}
130
146
 
131
147
 
133
149
    public const int DEFAULT_SCALE = 1200;
134
150
    public const ScaleConstraint DEFAULT_CONSTRAINT = ScaleConstraint.DIMENSIONS;
135
151
    public const Jpeg.Quality DEFAULT_QUALITY = Jpeg.Quality.HIGH;
 
152
    public const PhotoFileFormat DEFAULT_FORMAT = PhotoFileFormat.JFIF;
136
153
    
137
154
    public const ScaleConstraint[] CONSTRAINT_ARRAY = { ScaleConstraint.ORIGINAL,
138
155
        ScaleConstraint.DIMENSIONS, ScaleConstraint.WIDTH, ScaleConstraint.HEIGHT };
147
164
    private Gtk.Table table = new Gtk.Table(0, 0, false);
148
165
    private Gtk.ComboBox quality_combo;
149
166
    private Gtk.ComboBox constraint_combo;
 
167
    private Gtk.ComboBox format_combo;
150
168
    private Gtk.Entry pixels_entry;
151
169
    private Gtk.Widget ok_button;
152
170
    private bool in_insert = false;
153
171
    
154
 
    public ExportDialog(string title, int default_scale = DEFAULT_SCALE, 
155
 
        ScaleConstraint default_constraint = DEFAULT_CONSTRAINT, 
156
 
        Jpeg.Quality default_quality = DEFAULT_QUALITY) {
 
172
    public ExportDialog(string title) {
157
173
        this.title = title;
158
174
        has_separator = false;
159
175
        allow_grow = false;
160
 
        
161
 
        // use defaults for controls
162
 
        current_scale = default_scale;
163
 
        current_constraint = default_constraint;
164
 
        current_quality = default_quality;
165
 
        
166
 
        // prepare controls
 
176
 
167
177
        quality_combo = new Gtk.ComboBox.text();
168
178
        int ctr = 0;
169
179
        foreach (Jpeg.Quality quality in QUALITY_ARRAY) {
182
192
            ctr++;
183
193
        }
184
194
 
 
195
        format_combo = new Gtk.ComboBox.text();
 
196
        foreach (PhotoFileFormat format in PhotoFileFormat.get_writable()) {
 
197
            format_combo.append_text(format.get_properties().get_user_visible_name());
 
198
        }
 
199
 
185
200
        pixels_entry = new Gtk.Entry();
186
201
        pixels_entry.set_max_length(6);
187
202
        pixels_entry.set_size_request(60, -1);
189
204
        
190
205
        // register after preparation to avoid signals during init
191
206
        constraint_combo.changed += on_constraint_changed;
 
207
        format_combo.changed += on_format_changed;
192
208
        pixels_entry.changed += on_pixels_changed;
193
209
        pixels_entry.insert_text += on_pixels_insert_text;
194
210
        pixels_entry.activate += on_activate;
195
211
 
196
 
        // layout controls 
197
 
        add_label(_("_Quality:"), 0, 0, quality_combo);
198
 
        add_control(quality_combo, 1, 0);
 
212
        // layout controls
 
213
        add_label(_("_Format:"), 0, 0, format_combo);
 
214
        add_control(format_combo, 1, 0);
 
215
 
 
216
        add_label(_("_Quality:"), 0, 1, quality_combo);
 
217
        add_control(quality_combo, 1, 1);
199
218
        
200
 
        add_label(_("_Scaling constraint:"), 0, 1, constraint_combo);
201
 
        add_control(constraint_combo, 1, 1);
 
219
        add_label(_("_Scaling constraint:"), 0, 2, constraint_combo);
 
220
        add_control(constraint_combo, 1, 2);
202
221
 
203
222
        Gtk.Label pixels_label = new Gtk.Label.with_mnemonic(_(" _pixels"));
204
223
        pixels_label.set_mnemonic_widget(pixels_entry);
206
225
        Gtk.HBox pixels_box = new Gtk.HBox(false, 0);
207
226
        pixels_box.pack_start(pixels_entry, false, false, 0);
208
227
        pixels_box.pack_end(pixels_label, false, false, 0);
209
 
        add_control(pixels_box, 1, 2);
 
228
        add_control(pixels_box, 1, 3);
210
229
        
211
230
        ((Gtk.VBox) get_content_area()).add(table);
212
231
        
224
243
 
225
244
        ok_button.grab_focus();
226
245
    }
227
 
    
228
 
    public bool execute(out int scale, out ScaleConstraint constraint, out Jpeg.Quality quality) {
 
246
    // unlike other parameters, which should be persisted across dialog executions, format
 
247
    // must be set each time the dialog is executed, so that the format displayed in the
 
248
    // format combo box matches the format of the backing photo -- this is why it's passed
 
249
    // qualified as ref and not as out
 
250
    public bool execute(out int scale, out ScaleConstraint constraint, out Jpeg.Quality quality,
 
251
        ref PhotoFileFormat user_format) {
229
252
        show_all();
 
253
                
 
254
        if (!user_format.can_write())
 
255
            user_format = PhotoFileFormat.get_system_default_format();
 
256
                
 
257
        int ctr = 0;
 
258
        foreach (PhotoFileFormat format in PhotoFileFormat.get_writable()) {
 
259
            if (format == user_format)
 
260
                format_combo.set_active(ctr);           
 
261
            ctr++;
 
262
        }
 
263
        on_format_changed();
230
264
 
231
265
        bool ok = (run() == Gtk.ResponseType.OK);
232
266
        if (ok) {
244
278
            assert(index >= 0);
245
279
            quality = QUALITY_ARRAY[index];
246
280
            current_quality = quality;
 
281
 
 
282
            index = format_combo.get_active();
 
283
            assert(index >= 0);
 
284
            user_format = PhotoFileFormat.get_writable()[index];
247
285
        }
248
286
        
249
287
        destroy();
275
313
    }
276
314
    
277
315
    private void on_constraint_changed() {
278
 
        bool original = (CONSTRAINT_ARRAY[constraint_combo.get_active()] == ScaleConstraint.ORIGINAL);
 
316
        bool original = CONSTRAINT_ARRAY[constraint_combo.get_active()] == ScaleConstraint.ORIGINAL;
 
317
        bool jpeg = format_combo.get_active_text() ==
 
318
            PhotoFileFormat.JFIF.get_properties().get_user_visible_name();
279
319
        pixels_entry.sensitive = !original;
280
 
        quality_combo.sensitive = !original;
 
320
        quality_combo.sensitive = !original && jpeg;
281
321
        if (original)
282
322
            ok_button.sensitive = true;
283
323
        else
284
324
            on_pixels_changed();
285
325
    }
 
326
 
 
327
    private void on_format_changed() {
 
328
        bool original = CONSTRAINT_ARRAY[constraint_combo.get_active()] == ScaleConstraint.ORIGINAL;
 
329
        bool jpeg = format_combo.get_active_text() ==
 
330
            PhotoFileFormat.JFIF.get_properties().get_user_visible_name();
 
331
        quality_combo.sensitive = !original && jpeg;
 
332
    }
286
333
    
287
334
    private void on_activate() {
288
335
        response(Gtk.ResponseType.OK);
331
378
        list += "%s\n".printf(failed.get(ctr).identifier);
332
379
    
333
380
    int remaining = failed.size - REPORT_FAILURE_COUNT;
334
 
    if (remaining > 0) {
335
 
        string appendage = (ngettext("%d more photo not imported.\n",
336
 
            "%d more photos not imported.\n", remaining)).printf(remaining);
337
 
        list += appendage;
338
 
    }
 
381
    if (remaining > 0)
 
382
        list += _("(and %d more)\n").printf(remaining);
339
383
    
340
384
    return list;
341
385
}
368
412
            message += "\n";
369
413
        
370
414
        string already_imported_message =
371
 
            (ngettext("1 photo already in library was not imported.\n",
372
 
            "%d photos already in library were not imported.\n",
 
415
            (ngettext("1 photo already in library was not imported:\n",
 
416
            "%d photos already in library were not imported:\n",
373
417
            manifest.already_imported.size)).printf(manifest.already_imported.size);
374
418
 
375
419
        message += already_imported_message;
383
427
            message += "\n";
384
428
        
385
429
        string failed_message =
386
 
            (ngettext("1 photo failed to import due to a file or hardware error.\n",
387
 
                "%d photos failed to import due to a file or hardware error.\n",
 
430
            (ngettext("1 photo failed to import due to a file or hardware error:\n",
 
431
                "%d photos failed to import due to a file or hardware error:\n",
388
432
                manifest.failed.size)).printf(manifest.failed.size);
389
433
 
390
434
        message += failed_message;
398
442
            message += "\n";
399
443
        
400
444
        string camera_failed_message =
401
 
            ngettext("1 photo failed to import due to a camera error.\n",
402
 
                "%d photos failed to import due to a camera error.\n",
 
445
            ngettext("1 photo failed to import due to a camera error:\n",
 
446
                "%d photos failed to import due to a camera error:\n",
403
447
                manifest.camera_failed.size).printf(manifest.camera_failed.size);
404
448
            
405
449
        message += camera_failed_message;
412
456
        if (list && message.length > 0)
413
457
            message += "\n";
414
458
        
415
 
        string skipped_photos_message = (ngettext("1 unsupported photo skipped.\n",
416
 
            "%d unsupported photos skipped.\n", manifest.skipped_photos.size)).printf(
 
459
        string skipped_photos_message = (ngettext("1 unsupported photo skipped:\n",
 
460
            "%d unsupported photos skipped:\n", manifest.skipped_photos.size)).printf(
417
461
            manifest.skipped_photos.size);
418
462
 
419
463
        message += skipped_photos_message;
426
470
        if (list && message.length > 0)
427
471
            message += "\n";
428
472
        
429
 
        string skipped_files_message = (ngettext("1 non-image file skipped.",
430
 
            "%d non-image files skipped.", manifest.skipped_files.size)).printf(
 
473
        string skipped_files_message = (ngettext("1 non-image file skipped.\n",
 
474
            "%d non-image files skipped.\n", manifest.skipped_files.size)).printf(
431
475
            manifest.skipped_files.size);
432
476
 
433
477
        message += skipped_files_message;
437
481
        if (list && message.length > 0)
438
482
            message += "\n";
439
483
        
440
 
        string aborted_message = (ngettext("1 photo skipped due to user cancel.\n",
441
 
            "%d photos skipped due to user cancel.\n", manifest.aborted.size)).printf(
 
484
        string aborted_message = (ngettext("1 photo skipped due to user cancel:\n",
 
485
            "%d photos skipped due to user cancel:\n", manifest.aborted.size)).printf(
442
486
            manifest.aborted.size);
443
487
 
444
488
        message += aborted_message;
480
524
}
481
525
}
482
526
 
483
 
public abstract class TextEntryDialog : Gtk.Dialog {
 
527
public abstract class TextEntryDialogMediator {
 
528
    private TextEntryDialog dialog;
 
529
 
 
530
    public TextEntryDialogMediator(string title, string label, string? initial_text = null) {
 
531
        Gtk.Builder builder = AppWindow.create_builder();
 
532
        dialog = builder.get_object("text_entry_dialog1") as TextEntryDialog;
 
533
        dialog.set_builder(builder);
 
534
        dialog.setup(on_modify_validate, title, label, initial_text);
 
535
    }
 
536
    
 
537
    protected virtual bool on_modify_validate(string text) {
 
538
        return true;
 
539
    }
 
540
 
 
541
    protected string? _execute() {
 
542
        return dialog.execute();
 
543
    }
 
544
}
 
545
 
 
546
public class TextEntryDialog : Gtk.Dialog {
 
547
    public delegate bool OnModifyValidateType(string text);
 
548
 
 
549
    private OnModifyValidateType on_modify_validate;
484
550
    private Gtk.Entry entry;
485
 
 
486
 
    public TextEntryDialog(string title, string label, string? initial_text = null) {
487
 
        set_modal(true);
488
 
 
489
 
        add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
490
 
                    Gtk.STOCK_OK, Gtk.ResponseType.OK);
 
551
    private Gtk.Builder builder;
 
552
    
 
553
    public void set_builder(Gtk.Builder builder) {
 
554
        this.builder = builder;
 
555
    }
 
556
 
 
557
    public void setup(OnModifyValidateType? modify_validate, string title, string label, 
 
558
        string? initial_text) {
491
559
        set_title(title);
492
 
 
493
 
        Gtk.Label name_label = new Gtk.Label(label);
494
 
        entry = new Gtk.Entry();
495
 
 
496
 
        if (initial_text != null)
497
 
            entry.set_text(initial_text);
498
 
 
499
 
        entry.set_activates_default(true);
500
 
        entry.changed += on_entry_changed;
501
 
 
502
 
        Gtk.HBox query = new Gtk.HBox(false, 0);
503
 
        query.pack_start(name_label, false, false, 3);
504
 
        query.pack_start(entry, false, false, 3);
 
560
        set_parent_window(AppWindow.get_instance().get_parent_window());
 
561
        on_modify_validate = modify_validate;
 
562
 
 
563
        Gtk.Label name_label = builder.get_object("label") as Gtk.Label;
 
564
        name_label.set_text(label);
 
565
 
 
566
        entry = builder.get_object("entry") as Gtk.Entry;
 
567
        entry.set_text(initial_text != null ? initial_text : "");
 
568
        entry.grab_focus();
505
569
 
506
570
        set_default_response(Gtk.ResponseType.OK);
507
 
 
508
 
        vbox.pack_start(query, true, false, 6);
509
571
    }
510
572
 
511
 
    protected string? _execute() {
 
573
    public string? execute() {
512
574
        string? text = null;
513
575
        
514
576
        // validate entry to start with
515
577
        set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
516
 
 
 
578
        
517
579
        show_all();
518
580
        
519
 
        for (;;) {
520
 
            if (run() != Gtk.ResponseType.OK)
521
 
                break;
522
 
            
 
581
        if (run() == Gtk.ResponseType.OK)
523
582
            text = entry.get_text();
524
 
            if (on_ok_validate(text))
525
 
                break;
526
 
            
527
 
            text = null;
528
 
        }
529
583
        
530
584
        destroy();
531
585
        
532
586
        return text;
533
587
    }
534
588
    
535
 
    private void on_entry_changed() {
 
589
    public void on_entry_changed() {
536
590
        set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
537
591
    }
538
 
    
539
 
    protected virtual bool on_modify_validate(string text) {
540
 
        return true;
541
 
    }
542
 
    
543
 
    protected virtual bool on_ok_validate(string text) {
544
 
        return true;
545
 
    }
546
592
}
547
593
 
548
 
public class EventRenameDialog : TextEntryDialog {
 
594
public class EventRenameDialog : TextEntryDialogMediator {
549
595
    public EventRenameDialog(string? event_name) {
550
596
        base (_("Rename Event"), _("Name:"), event_name);
551
597
    }
552
 
    
553
 
    public string? execute() {
 
598
 
 
599
    public virtual string? execute() {
554
600
        return _execute();
555
601
    }
556
602
}
557
603
 
 
604
public class PhotoRenameDialog : TextEntryDialogMediator {
 
605
    public PhotoRenameDialog(string? photo_name) {
 
606
        base (_("Rename Photo"), _("Name:"), photo_name);
 
607
    }
 
608
 
 
609
    public virtual string? execute() {
 
610
        return _execute().strip();
 
611
    }
 
612
}
 
613
 
558
614
// Returns: Gtk.ResponseType.YES (trash photos), Gtk.ResponseType.NO (only remove photos) and
559
615
// Gtk.ResponseType.CANCEL.
560
 
public Gtk.ResponseType remove_photos_dialog(Gtk.Window owner, int count) {
 
616
public Gtk.ResponseType empty_trash_dialog(Gtk.Window owner, int count) {
561
617
    string msg = ngettext(
562
618
        "This will remove the photo from your Shotwell library.  Would you also like to move the file to your desktop trash?\n\nThis action cannot be undone.",
563
 
        "This will remove the selected photos from your Shotwell library.  Would you also like to move the files to your desktop trash?\n\nThis action cannot be undone.",
564
 
        count);
 
619
        "This will remove %d photos from your Shotwell library.  Would you also like to move the files to your desktop trash?\n\nThis action cannot be undone.",
 
620
        count).printf(count);
565
621
    string trash_action = ngettext("_Trash File", "_Trash Files", count);
566
622
    
567
623
    Gtk.MessageDialog dialog = new Gtk.MessageDialog(owner, Gtk.DialogFlags.MODAL,
568
624
        Gtk.MessageType.WARNING, Gtk.ButtonsType.CANCEL, "%s", msg);
569
625
    dialog.add_button(_("Only _Remove"), Gtk.ResponseType.NO);
570
626
    dialog.add_button(trash_action, Gtk.ResponseType.YES);
571
 
    dialog.title = _("Remove");
 
627
    dialog.title = _("Empty Trash");
572
628
    
573
629
    Gtk.ResponseType result = (Gtk.ResponseType) dialog.run();
574
630
    
722
778
 
723
779
        set_modal(true);
724
780
        set_resizable(false);
 
781
        has_separator = false;
725
782
        set_transient_for(AppWindow.get_instance());
726
783
 
727
784
        add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
1011
1068
    dialog.destroy();
1012
1069
}
1013
1070
 
1014
 
public class AddTagsDialog : TextEntryDialog {
 
1071
 
 
1072
 
 
1073
public class AddTagsDialog : TextEntryDialogMediator {
1015
1074
    public AddTagsDialog() {
1016
1075
        base (Resources.ADD_TAGS_TITLE, _("Tags (separated by commas):"));
1017
1076
    }
1018
 
    
 
1077
 
1019
1078
    public string[]? execute() {
1020
1079
        string? text = _execute();
1021
1080
        if (text == null)
1025
1084
        // that Tag.prep_tag_names won't return a zero-length array (and it never returns null)
1026
1085
        return Tag.prep_tag_names(text.split(","));
1027
1086
    }
1028
 
    
 
1087
 
1029
1088
    protected override bool on_modify_validate(string text) {
1030
1089
        // Can't simply call Tag.prep_tag_names().length because of this bug:
1031
 
        // https://bugzilla.gnome.org/show_bug.cgi?id=609440
 
1090
        // https://bugzilla.gnome.org/show_bug.cgi?id=602208
1032
1091
        string[] names = Tag.prep_tag_names(text.split(","));
1033
1092
        
1034
1093
        return names.length > 0;
1035
1094
    }
1036
1095
}
1037
1096
 
1038
 
public class RenameTagDialog : TextEntryDialog {
 
1097
public class RenameTagDialog : TextEntryDialogMediator {
1039
1098
    private string current_name;
1040
1099
    
1041
1100
    public RenameTagDialog(string current_name) {
1061
1120
    }
1062
1121
}
1063
1122
 
1064
 
public class ModifyTagsDialog : TextEntryDialog {
 
1123
public class ModifyTagsDialog : TextEntryDialogMediator {
1065
1124
    public ModifyTagsDialog(string[]? current_tags) {
1066
 
        base (Resources.MODIFY_TAGS_LABEL, _("Tags (separated by commas):"), get_initial_text(current_tags));
 
1125
        base (Resources.MODIFY_TAGS_LABEL, _("Tags (separated by commas):"), 
 
1126
            get_initial_text(current_tags));
1067
1127
    }
1068
1128
    
1069
1129
    private static string? get_initial_text(string[]? tags) {
1104
1164
        Gtk.Widget ok_button = add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK);
1105
1165
        set_title(_("Welcome!"));
1106
1166
        set_resizable(false);
 
1167
        has_separator = false;
1107
1168
        set_type_hint(Gdk.WindowTypeHint.DIALOG);
1108
1169
        set_transient_for(owner);
1109
1170
 
1139
1200
        hide_button = new Gtk.CheckButton.with_mnemonic(_("_Don't show this message again"));
1140
1201
        hide_button.set_active(true);
1141
1202
        content.pack_start(hide_button, false, false, 6);
1142
 
 
1143
 
        content.set_border_width(12);
1144
 
 
1145
 
        vbox.pack_start(content, false, false, 0);
 
1203
        
 
1204
        Gtk.Alignment alignment = new Gtk.Alignment(0, 0, 0, 0);
 
1205
        alignment.set_padding(12, 0, 12, 12);
 
1206
        alignment.add(content);
 
1207
 
 
1208
        vbox.pack_start(alignment, false, false, 0);
1146
1209
 
1147
1210
        ok_button.grab_focus();
1148
1211
    }
1162
1225
    }
1163
1226
}
1164
1227
 
 
1228
public class PreferencesDialog {
 
1229
    private Gtk.Dialog dialog;
 
1230
    private Gtk.Builder builder;
 
1231
    private Gtk.Adjustment bg_color_adjustment;
 
1232
    private bool display_borders;
 
1233
    
 
1234
    public PreferencesDialog() {
 
1235
        builder = AppWindow.create_builder();
 
1236
 
 
1237
        dialog = builder.get_object("preferences_dialog") as Gtk.Dialog;
 
1238
        dialog.set_parent_window(AppWindow.get_instance().get_parent_window());
 
1239
        
 
1240
        bg_color_adjustment = builder.get_object("bg_color_adjustment") as Gtk.Adjustment;
 
1241
        bg_color_adjustment.set_value(bg_color_adjustment.get_upper() - 
 
1242
            Config.get_instance().get_bg_color().red);
 
1243
        bg_color_adjustment.value_changed += on_value_changed;
 
1244
 
 
1245
        Gtk.CheckButton display_borders_button = 
 
1246
            builder.get_object("display_borders") as Gtk.CheckButton;
 
1247
        display_borders = Config.get_instance().get_display_borders();
 
1248
        display_borders_button.set_active(display_borders);
 
1249
        display_borders_button.toggled += on_display_borders_toggled;
 
1250
    }
 
1251
    
 
1252
    public void execute() {
 
1253
        dialog.show_all();
 
1254
 
 
1255
        if (dialog.run() == Gtk.ResponseType.CLOSE)
 
1256
            Config.get_instance().commit_bg_color();
 
1257
 
 
1258
        dialog.destroy();
 
1259
    }
 
1260
    
 
1261
    private void on_value_changed() {
 
1262
        set_background_color(bg_color_adjustment.get_upper() - bg_color_adjustment.get_value());
 
1263
    }
 
1264
 
 
1265
    private void set_background_color(double bg_color_value) {
 
1266
        Config.get_instance().set_bg_color(to_grayscale((uint16) bg_color_value));
 
1267
    }
 
1268
 
 
1269
    private Gdk.Color to_grayscale(uint16 color_value) {
 
1270
        Gdk.Color color = Gdk.Color();
 
1271
        
 
1272
        color.red = color_value;
 
1273
        color.green = color_value;
 
1274
        color.blue = color_value;
 
1275
        
 
1276
        return color;
 
1277
    }
 
1278
    
 
1279
    private void on_display_borders_toggled() {
 
1280
        display_borders = !display_borders;
 
1281
        Config.get_instance().set_display_borders(display_borders);
 
1282
    }
 
1283
}