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