1 /**********************************************************************
2 *
3 * FreeDoko a Doppelkopf-Game
4 *
5 * Copyright (C) 2001 – 2018 by Diether Knof and Borg Enders
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program 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 * You can find this license in the file 'gpl.txt'.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Contact:
24 * Diether Knof dknof@posteo.de
25 *
26 *********************************************************************/
27
28 #include "constants.h"
29
30 #ifdef USE_UI_GTKMM
31
32 #include "background.h"
33
34 #include "../ui.h"
35 #include "../cards.h"
36
37 #include <gtkmm/scrolledwindow.h>
38 #include <gtkmm/image.h>
39 #include <gdkmm/general.h>
40
41 namespace UI_GTKMM_NS {
42
43 namespace {
44 double constexpr dest_width = 100.0;
45 double constexpr dest_height = 100.0;
46 Glib::RefPtr<Gdk::Pixbuf> load_background_image(string path);
47 Glib::RefPtr<Gdk::Pixbuf> scale_if_too_big(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
48 Glib::RefPtr<Gdk::Pixbuf> repeat_if_too_small(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
49 }
50
51
52 /** constructor
53 **/
Background(Preferences & preferences)54 Preferences::Background::Background(Preferences& preferences) :
55 Selection(preferences, ::Preferences::Type::background)
56 {
57 Selection::default_entries = {"table.png"};
58 return ;
59 }
60
61 /** destructor
62 **/
63 Preferences::Background::~Background()
64 = default;
65
66 /** creates all subelements for the cardsorder
67 **/
68 void
init()69 Preferences::Background::init()
70 {
71 Selection::init();
72 container->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
73 }
74
75 /** @return whether the path is valid
76 **/
77 bool
path_valid(string const path) const78 Preferences::Background::path_valid(string const path) const
79 {
80 return is_supported_graphic_file(path);
81 }
82
83 /** add the images to the box
84 **/
85 Gtk::Widget*
create_entry(Entry const entry)86 Preferences::Background::create_entry(Entry const entry)
87 {
88 auto pixbuf = load_background_image(entry.path);
89 if (!pixbuf) {
90 return {};
91 }
92 auto image = Gtk::manage(new Gtk::Image(pixbuf));
93 return image;
94 }
95
96 namespace {
97
98 /** @return pixbuf or nullptr
99 ** If the size is too big, it will be scaled
100 ** If the size is too small, it will be repeated
101 **/
102 Glib::RefPtr<Gdk::Pixbuf>
load_background_image(string const path)103 load_background_image(string const path)
104 {
105 try {
106 auto pixbuf = Gdk::Pixbuf::create_from_file(path);
107 pixbuf = scale_if_too_big(pixbuf);
108 pixbuf = repeat_if_too_small(pixbuf);
109 return pixbuf;
110 } catch (...) {
111 return {};
112 }
113 }
114
115 /** @return pixbuf scaled down, if it is too big
116 **/
117 Glib::RefPtr<Gdk::Pixbuf>
scale_if_too_big(Glib::RefPtr<Gdk::Pixbuf> pixbuf)118 scale_if_too_big(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
119 {
120 if ( pixbuf->get_width() <= dest_width
121 && pixbuf->get_height() <= dest_height) {
122 return pixbuf;
123 }
124 double const scale = min(dest_width / pixbuf->get_width(),
125 dest_height / pixbuf->get_height());
126 pixbuf = pixbuf->scale_simple(scale * pixbuf->get_width(),
127 scale * pixbuf->get_height(),
128 Gdk::INTERP_BILINEAR);
129 return pixbuf;
130 }
131
132 /** @return pixbuf repeated, if it is too small
133 **/
134 Glib::RefPtr<Gdk::Pixbuf>
repeat_if_too_small(Glib::RefPtr<Gdk::Pixbuf> pixbuf)135 repeat_if_too_small(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
136 {
137 if ( pixbuf->get_width() >= 0.6 * dest_width
138 && pixbuf->get_height() >= 0.6 * dest_height) {
139 return pixbuf;
140 }
141 auto image = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24,
142 pixbuf->get_width(),
143 pixbuf->get_height());
144 {
145 auto cr = Cairo::Context::create(image);
146 Gdk::Cairo::set_source_pixbuf(cr, pixbuf, 0, 0);
147 cr->paint();
148 }
149 auto surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24,
150 dest_width, dest_height);
151 {
152 auto cr = Cairo::Context::create(surface);
153 auto background = Cairo::SurfacePattern::create(image);
154 background->set_extend(Cairo::EXTEND_REPEAT);
155 cr->set_source(background);
156 cr->rectangle(0, 0, dest_width, dest_height);
157 cr->fill();
158 }
159
160 return Gdk::Pixbuf::create(surface, 0, 0, dest_width, dest_height);
161 }
162 }
163
164 } // namespace UI_GTKMM_NS
165
166 #endif // #ifdef USE_UI_GTKMM
167