1 /* aicon.cc
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2019 Ralf Hoffmann.
4  * You can contact me at: ralf@boomerangsworld.de
5  *   or http://www.boomerangsworld.de/worker
6  *
7  * This program 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 2 of the License, or
10  * (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  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "aguix.h"
23 #include "aicon.hh"
24 #include <iostream>
25 
AIcon(AGUIX * aguix,Drawable d,const int * pixels,size_t pixels_length)26 AIcon::AIcon( AGUIX *aguix,
27               Drawable d,
28               const int *pixels,
29               size_t pixels_length ) :
30     m_aguix( aguix ),
31     m_d( d ),
32     m_w( 0 ),
33     m_h( 0 ),
34     m_scale_factor( 0 ),
35     m_aguix_color_instance( -1 ),
36     m_current_fg( -1 ),
37     m_current_bg( -1 )
38 {
39     if ( pixels_length < 3 ) {
40         std::cerr << "Invalid pixels field" << std::endl;
41         return;
42     }
43 
44     size_t w = pixels[0];
45     size_t h = pixels[1];
46 
47     if ( w * h + 2 != pixels_length ) {
48         std::cerr << "Invalid pixels field" << std::endl;
49         return;
50     }
51 
52     m_w = w;
53     m_h = h;
54 
55     for ( size_t p = 0; p < w * h; p++ ) {
56         m_pixels.push_back( pixels[ 2 + p ] );
57     }
58 
59     update( 1, 0, true );
60 }
61 
~AIcon()62 AIcon::~AIcon()
63 {
64     cleanPixmapCache();
65 }
66 
update(Drawable d,int fg,int bg,bool force)67 void AIcon::update( Drawable d, int fg, int bg, bool force )
68 {
69     if ( m_d != d ) {
70         m_d = d;
71         force = true;
72     }
73 
74     update( fg, bg, force );
75 }
76 
update(int fg,int bg,bool force)77 void AIcon::update( int fg, int bg, bool force )
78 {
79     if ( m_d == 0 ) return;
80 
81     if ( m_w < 1 || m_h < 1 ) return;
82 
83     if ( ! force &&
84          m_current_fg == fg &&
85          m_current_bg == bg &&
86          m_aguix_color_instance == m_aguix->getCurrentUserColorInstance() ) {
87         return;
88     }
89 
90     auto id = std::make_pair( fg, bg );
91 
92     if ( m_aguix_color_instance != m_aguix->getCurrentUserColorInstance() ) {
93         // remove cache
94         cleanPixmapCache();
95     }
96 
97     bool skip_update = false;
98 
99     if ( m_pixmap_cache.count( id ) > 0 ) {
100         if ( ! force ) {
101             skip_update = true;
102         } else {
103             m_aguix->freePixmap( m_pixmap_cache[id] );
104             m_pixmap_cache.erase( id );
105         }
106     }
107 
108     if ( ! skip_update ) {
109         size_t factor = 1;
110         if ( m_scale_factor > 1 ) {
111             factor = m_scale_factor;
112         }
113 
114         Pixmap pixmap = m_aguix->createPixmap( m_d, m_w * factor, m_h * factor );
115 
116         if ( pixmap != 0 ) {
117             AGUIX::col_values_t fg_values = m_aguix->getColorInfo( fg );
118             AGUIX::col_values_t bg_values = m_aguix->getColorInfo( bg );
119 
120             for ( size_t y = 0; y < m_h * factor; y++ ) {
121                 for ( size_t x = 0; x < m_w * factor; x++ ) {
122                     int c = m_pixels.at( ( y / factor ) * m_w + x / factor );
123 
124                     AGUIX::col_values_t color = m_aguix->blend( bg_values,
125                                                                 fg_values,
126                                                                 c );
127 
128                     AGUIXColor acol = m_aguix->getColor( color );
129 
130                     m_aguix->setFG( acol );
131 
132                     m_aguix->DrawPoint( pixmap, x, y );
133                 }
134             }
135 
136             m_pixmap_cache[id] = pixmap;
137         }
138     }
139 
140     m_current_fg = fg;
141     m_current_bg = bg;
142     m_aguix_color_instance = m_aguix->getCurrentUserColorInstance();
143 }
144 
draw(Drawable d,int x,int y)145 void AIcon::draw( Drawable d,
146                   int x, int y )
147 {
148     try {
149         Pixmap pixmap = m_pixmap_cache.at( std::make_pair( m_current_fg,
150                                                            m_current_bg ) );
151 
152         size_t factor = 1;
153         if ( m_scale_factor > 1 ) {
154             factor = m_scale_factor;
155         }
156 
157         m_aguix->copyArea( pixmap,
158                            d,
159                            0, 0,
160                            m_w * factor, m_h * factor,
161                            x, y );
162     } catch (...) {
163     }
164 }
165 
w() const166 size_t AIcon::w() const
167 {
168     return m_w;
169 }
170 
h() const171 size_t AIcon::h() const
172 {
173     return m_h;
174 }
175 
setScale(size_t factor)176 void AIcon::setScale( size_t factor )
177 {
178     m_scale_factor = factor;
179 }
180 
drawable() const181 Drawable AIcon::drawable() const
182 {
183     return m_d;
184 }
185 
cleanPixmapCache()186 void AIcon::cleanPixmapCache()
187 {
188     for ( auto it : m_pixmap_cache ) {
189         m_aguix->freePixmap( it.second );
190     }
191     m_pixmap_cache.clear();
192 }
193