1 /** -*- C++ -*-
2  *
3  *  This file is part of RawTherapee.
4  *
5  *  Copyright (c) 2020 Alberto Griggio <alberto.griggio@gmail.com>
6  *
7  *  RawTherapee is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  RawTherapee is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "dateentry.h"
22 #include "rtimage.h"
23 #include "options.h"
24 #include <time.h>
25 #include <iostream>
26 #include <iomanip>
27 #include <sstream>
28 
29 
DateEntry()30 DateEntry::DateEntry(): Gtk::HBox()
31 {
32     entry_ = Gtk::manage(new Gtk::Entry());
33     entry_->property_width_chars() = 1;
34     entry_->property_xalign() = 1;
35     entry_->add_events(Gdk::FOCUS_CHANGE_MASK);
36     pack_start(*entry_, Gtk::PACK_EXPAND_WIDGET, 0);
37     pack_start(*Gtk::manage(button_ = new Gtk::Button()), 0, 0);
38     button_->add(*Gtk::manage(new RTImage("expander-open-small.png")));
39     button_->add_events(Gdk::BUTTON_PRESS_MASK);
40     button_->signal_button_press_event().connect_notify(sigc::mem_fun(this, &DateEntry::on_button));
41     entry_->signal_activate().connect(sigc::mem_fun(this, &DateEntry::on_enter));
42     const auto on_focus_out =
43         [this](GdkEventFocus *) -> bool
44         {
45             on_enter();
46             return false;
47         };
48     entry_->signal_focus_out_event().connect(sigc::slot<bool, GdkEventFocus *>(on_focus_out));
49     dialog_ = nullptr;
50     calendar_ = nullptr;
51 }
52 
53 
~DateEntry()54 DateEntry::~DateEntry()
55 {
56     if (dialog_) {
57         delete dialog_;
58     }
59 }
60 
61 
on_button(const GdkEventButton * evt)62 void DateEntry::on_button(const GdkEventButton *evt)
63 {
64     int pos_x = evt->x_root - evt->x;
65     int pos_y = evt->y_root - evt->y;
66 
67     auto ea = entry_->get_allocation();
68     pos_x -= ea.get_width();
69     pos_y += ea.get_height();
70 
71     int x_win = pos_x;
72     int y_win = pos_y;
73 
74     auto top = get_toplevel();
75     Gtk::Window *win = top ? dynamic_cast<Gtk::Window *>(top) : nullptr;
76     dialog_ = new Gtk::Dialog("", Gtk::DIALOG_MODAL);
77     if (win) {
78         dialog_->set_transient_for(*win);
79     }
80     dialog_->property_skip_taskbar_hint() = true;
81     dialog_->property_skip_pager_hint() = true;
82     dialog_->set_decorated(false);
83 
84     dialog_->move(x_win, y_win);
85 
86     calendar_ = Gtk::manage(new Gtk::Calendar());
87     dialog_->get_vbox()->pack_start(*calendar_, 0, 0);
88 
89     //calendar_->set_date(date_);
90     calendar_->select_month(int(date_.get_month())-1, date_.get_year());
91     calendar_->select_day(date_.get_day());
92 
93     dialog_->signal_button_press_event().connect(sigc::mem_fun(this, &DateEntry::on_date_selected));
94     dialog_->get_action_area()->set_size_request(-1, 0);
95 
96     dialog_->show_all();
97     dialog_->run();
98 }
99 
100 
on_date_selected(const GdkEventButton * evt)101 bool DateEntry::on_date_selected(const GdkEventButton *evt)
102 {
103     calendar_->get_date(date_);
104     set_date(date_);
105     dialog_->hide();
106     delete dialog_;
107     dialog_ = nullptr;
108     sig_date_changed_.emit();
109     return false;
110 }
111 
112 
set_date(const Glib::Date & date)113 void DateEntry::set_date(const Glib::Date &date)
114 {
115     date_ = date;
116     entry_->set_text(date_.format_string(options.dateFormat));
117 }
118 
119 
on_enter()120 void DateEntry::on_enter()
121 {
122     struct tm t;
123     memset(&t, 0, sizeof(struct tm));
124     std::string val = entry_->get_text();
125     std::string fmt = options.dateFormat;
126     std::istringstream s(val);
127     try {
128         if (s >> std::get_time(&t, fmt.c_str())) {
129             Glib::Date d(t.tm_mday, Glib::Date::Month(t.tm_mon+1), 1900 + t.tm_year);
130             if (d.valid()) {
131                 set_date(d);
132             } else {
133                 set_date(date_);
134             }
135         } else {
136             set_date(date_);
137         }
138     } catch (std::istream::failure &err) {
139         set_date(date_);
140     }
141 }
142