Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License, version 3, as 00007 // published by the Free Software Foundation. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License along 00015 // with this program. If not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 #include <lib/config.h> 00019 #include <libexplain/gettimeofday.h> 00020 00021 #include <lib/program_card/functor/image/pixbuf.h> 00022 00023 #include <canola/calculator/gnome.h> 00024 #include <canola/window/card_reader.h> 00025 00026 00027 window_card_reader::~window_card_reader() 00028 { 00029 } 00030 00031 00032 window_card_reader::window_card_reader(calculator_gnome *a_dst) : 00033 dst(*a_dst), 00034 pixels_per_second(100), 00035 pixels_per_instruction(1), 00036 current_address(0), 00037 current_card_number(0), 00038 currently_moving_left(false), 00039 current_card_started(0) 00040 { 00041 set_transient_for(*a_dst); 00042 set_decorated(false); 00043 Glib::RefPtr<Gdk::Visual> vp = get_screen()->get_rgba_visual(); 00044 if (vp) 00045 { 00046 set_app_paintable(); 00047 gtk_widget_set_visual(Gtk::Widget::gobj(), vp->gobj()); 00048 } 00049 else 00050 { 00051 fprintf(stderr, "%s: %d: transparency not available\n", __FILE__, 00052 __LINE__); 00053 } 00054 add(layout); 00055 } 00056 00057 00058 window_card_reader::pointer 00059 window_card_reader::create(calculator_gnome *a_dst) 00060 { 00061 return pointer(new window_card_reader(a_dst)); 00062 } 00063 00064 00065 static double 00066 get_time_of_day(void) 00067 { 00068 timeval result; 00069 explain_gettimeofday_or_die(&result, 0); 00070 return (result.tv_usec * 1e-6 + result.tv_sec); 00071 } 00072 00073 00074 static int 00075 get_position_x(int card_num) 00076 { 00077 return (card_num * 30); 00078 } 00079 00080 00081 static int 00082 get_position_y(int card_num) 00083 { 00084 return (card_num * 10); 00085 } 00086 00087 00088 bool 00089 window_card_reader::start(const std::string &src, bool binary) 00090 { 00091 // 00092 // Load the card set into the proxy. We use a proxy for two 00093 // reasons: 00094 // 1. We have to dole out the instrinctions on at a time, as the 00095 // animation progresses, so as to emulate the reading of the 00096 // opcode by the original optical reader. 00097 // 2. We have to store them as a "program" even in the case where 00098 // the cards are a data set for one of the General Function card 00099 // sets. 00100 // 00101 dst.program_mode_set(calculator::program_mode_learn); 00102 dst.clear_program(); 00103 if (!dst.load_program(src, binary)) 00104 return false; 00105 00106 // 00107 // Now that we have the program, turn it into a set of images in pixbufs. 00108 // It is these pixbufs that can be displayed by Gtk::Image wigdets. 00109 // 00110 double dpi = get_screen()->get_resolution(); 00111 card_pixbufs.clear(); 00112 program_card_functor_image_pixbuf::pointer ffs = 00113 program_card_functor_image_pixbuf::create(card_pixbufs, dpi); 00114 ffs->set_disassemble(true); 00115 dst.program_card_walk(*ffs); 00116 ffs.reset(); 00117 if (card_pixbufs.empty()) 00118 return false; 00119 00120 // 00121 // Calculate how fast the card will have to travel under the 00122 // simulated optical reader at the top of the window. 00123 // 00124 pixels_per_second = card_pixbufs[0]->get_height() / 4.; 00125 pixels_per_instruction = card_pixbufs[0]->get_height() / 40; 00126 assert(pixels_per_instruction >= 1); 00127 00128 // 00129 // For each of the pixbufs, create a Gtk::Image widget to display 00130 // it. We have to do this in reverse, so that the first card is the 00131 // last widget, and comes out on top of the visable stack of cards. 00132 // 00133 card_image_widgets.clear(); 00134 for (size_t j = 0; j < card_pixbufs.size(); ++j) 00135 { 00136 size_t jj = card_pixbufs.size() - 1 - j; 00137 pixbuf_ptr_t pp = card_pixbufs[jj]; 00138 assert(pp); 00139 if (pp) 00140 { 00141 gtk_image_ptr_t p(new Gtk::Image(pp)); 00142 card_image_widgets.push_back(p); 00143 layout.put(*p, get_position_x(jj), get_position_y(jj)); 00144 } 00145 } 00146 00147 // 00148 // Show the window, and its card images, to the user. 00149 // 00150 assert(card_image_widgets.size() == card_pixbufs.size()); 00151 if (is_composited()) 00152 { 00153 layout.hide(); 00154 show(); 00155 Gdk::RGBA glass; 00156 glass.set_rgba(1., 1., 1., 0.); 00157 assert(get_window()); 00158 get_window()->set_background(glass); 00159 } 00160 show_all_children(); 00161 00162 current_card_number = 0; 00163 currently_moving_left = false; 00164 current_card_started = get_time_of_day(); 00165 current_address = 1; 00166 00167 // 00168 // Start the animation timer running. 00169 // 00170 animation_timer = 00171 Glib::signal_timeout().connect 00172 ( 00173 sigc::mem_fun(*this, &window_card_reader::on_animation_timer), 00174 1000 / 24 00175 ); 00176 return true; 00177 } 00178 00179 00180 bool 00181 window_card_reader::empty(void) 00182 const 00183 { 00184 return card_image_widgets.empty(); 00185 } 00186 00187 00188 bool 00189 window_card_reader::on_animation_timer(void) 00190 { 00191 if (current_card_number >= card_image_widgets.size()) 00192 { 00193 done(); 00194 return false; 00195 } 00196 00197 int card_height = card_pixbufs[0]->get_height(); 00198 double now = get_time_of_day(); 00199 double t = now - current_card_started; 00200 int jj = card_image_widgets.size() - 1 - current_card_number; 00201 if (currently_moving_left) 00202 { 00203 int x0 = get_position_x(current_card_number); 00204 int y = get_position_y(current_card_number); 00205 int x = x0 - t * pixels_per_second; 00206 if (x <= 0) 00207 { 00208 x = 0; 00209 currently_moving_left = false; 00210 current_card_started = now; 00211 } 00212 layout.move(*card_image_widgets[jj], x, y); 00213 } 00214 else 00215 { 00216 int x = 0; 00217 int y0 = get_position_y(current_card_number); 00218 int yz = -card_height; 00219 int y = y0 - t * pixels_per_second; 00220 layout.move(*card_image_widgets[jj], x, y); 00221 if (y < 0) 00222 { 00223 int new_addr = -y / pixels_per_instruction; 00224 if (new_addr < 40) 00225 { 00226 new_addr += current_card_number * 40; 00227 ++new_addr; 00228 while (current_address <= new_addr) 00229 { 00230 dst.forward(current_address); 00231 ++current_address; 00232 } 00233 } 00234 } 00235 if (y < yz) 00236 { 00237 assert((current_address % 40) == 1); 00238 ++current_card_number; 00239 currently_moving_left = true; 00240 current_card_started = now; 00241 } 00242 } 00243 return true; 00244 } 00245 00246 00247 void 00248 window_card_reader::done(void) 00249 { 00250 // 00251 // No need for the time any more. 00252 // 00253 animation_timer.disconnect(); 00254 00255 // 00256 // Hide the window. 00257 // 00258 hide(); 00259 00260 // 00261 // Remove the image widgets from the layout. 00262 // 00263 while (!card_image_widgets.empty()) 00264 { 00265 gtk_image_ptr_t wp = card_image_widgets.back(); 00266 card_image_widgets.pop_back(); 00267 layout.remove(*wp); 00268 } 00269 00270 // 00271 // Free the card images. 00272 // 00273 card_pixbufs.clear(); 00274 } 00275 00276 00277 bool 00278 window_card_reader::is_busy(void) 00279 { 00280 return animation_timer.connected(); 00281 }