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