| 1 | // note: If we will end up using GObject + C++ the result will seem |
|---|
| 2 | // always an horrible hack. We need either a good (for our purposes) |
|---|
| 3 | // C++ interface (or binding) for Poppler and Clutter or to code the |
|---|
| 4 | // whole thing in C using GObjects. |
|---|
| 5 | #include <iostream> |
|---|
| 6 | #include <sstream> |
|---|
| 7 | #include <cmath> |
|---|
| 8 | #include <cstdlib> |
|---|
| 9 | #include <cstring> |
|---|
| 10 | #include <clutter/clutter.h> |
|---|
| 11 | #include <poppler.h> |
|---|
| 12 | #include <libintl.h> |
|---|
| 13 | #define _(String) gettext(String) |
|---|
| 14 | |
|---|
| 15 | #include "document.hh" |
|---|
| 16 | #include "page.hh" |
|---|
| 17 | #include "pdfcube.hh" |
|---|
| 18 | |
|---|
| 19 | using namespace std; |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | void usage() |
|---|
| 23 | { |
|---|
| 24 | cerr << _("pdfcube filename.pdf") << endl; |
|---|
| 25 | exit(1); |
|---|
| 26 | } |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | /* |
|---|
| 30 | static gboolean |
|---|
| 31 | on_page_enter(ClutterActor* actor, ClutterEvent *event, gpointer data) |
|---|
| 32 | { |
|---|
| 33 | double sx, sy; |
|---|
| 34 | clutter_actor_get_scale(actor, &sx, &sy); |
|---|
| 35 | if(sx > 1.0 || sy > 1.0) return FALSE; |
|---|
| 36 | // Code snippet for a static member of the index class, |
|---|
| 37 | // data should point to the index instance, so one can |
|---|
| 38 | // also click on a page and have its number. |
|---|
| 39 | // FIXME: cancel previous animation before starting a new one. |
|---|
| 40 | ClutterTimeline *timeline = clutter_timeline_new(20, 60); |
|---|
| 41 | clutter_timeline_set_loop(timeline, TRUE); |
|---|
| 42 | clutter_timeline_start(timeline); |
|---|
| 43 | ClutterEffectTemplate *effect_template = |
|---|
| 44 | clutter_effect_template_new(timeline, |
|---|
| 45 | clutter_sine_half_func); |
|---|
| 46 | clutter_effect_scale(effect_template, actor, 1.12, 1.12, NULL, NULL); |
|---|
| 47 | g_object_unref(effect_template); |
|---|
| 48 | g_object_unref(timeline); |
|---|
| 49 | return TRUE; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | static gboolean |
|---|
| 53 | on_page_leave(ClutterActor* actor, ClutterEvent *event, gpointer data) |
|---|
| 54 | { |
|---|
| 55 | return TRUE; |
|---|
| 56 | } |
|---|
| 57 | */ |
|---|
| 58 | static gboolean |
|---|
| 59 | on_stage_button_press (ClutterStage *stage, ClutterEvent *event, gpointer data) |
|---|
| 60 | { |
|---|
| 61 | gfloat x, y; |
|---|
| 62 | clutter_event_get_coords (event, &x, &y); |
|---|
| 63 | g_print ("Stage clicked at (%f, %f)\n", x, y); |
|---|
| 64 | // clutter cluttered my first draw, so redraw on click to allow testing. |
|---|
| 65 | // clutter_actor_queue_redraw(CLUTTER_ACTOR(stage)); |
|---|
| 66 | return TRUE; /* Stop further handling of this event. */ |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | /** |
|---|
| 70 | * The index class will contain methods to show all the pages in an |
|---|
| 71 | * index page, to hilight a different page and to restore the selected |
|---|
| 72 | * page in full screen. |
|---|
| 73 | * |
|---|
| 74 | */ |
|---|
| 75 | class index |
|---|
| 76 | { |
|---|
| 77 | // ... |
|---|
| 78 | // 1. animate to index when tab is pressed |
|---|
| 79 | // 2. navigate with the keyboard and/or mouse (see on_page_enter) |
|---|
| 80 | // 3. animate to the single page choosen (clicked or previous on esc) |
|---|
| 81 | // |
|---|
| 82 | }; |
|---|
| 83 | |
|---|
| 84 | /** |
|---|
| 85 | * @brief Abstract animator class. |
|---|
| 86 | * |
|---|
| 87 | * Animations are for transitions between two pages. They start from |
|---|
| 88 | * one page and go to another one. The prepare() method whoud be |
|---|
| 89 | * called before starting and is indended to render the hi resolution |
|---|
| 90 | * version of the needed pages and to setup the scene |
|---|
| 91 | * graph. render(frame) is used to position the actors for the given |
|---|
| 92 | * frame number and unprepare() will free the unneded hi-res versions. |
|---|
| 93 | */ |
|---|
| 94 | class animator |
|---|
| 95 | { |
|---|
| 96 | public: |
|---|
| 97 | virtual ~animator() {} |
|---|
| 98 | |
|---|
| 99 | virtual void |
|---|
| 100 | setup() = 0; |
|---|
| 101 | |
|---|
| 102 | virtual void |
|---|
| 103 | render(int frame) = 0; |
|---|
| 104 | |
|---|
| 105 | virtual void |
|---|
| 106 | tear_down() = 0; |
|---|
| 107 | }; |
|---|
| 108 | |
|---|
| 109 | class replace_animator : public animator |
|---|
| 110 | { |
|---|
| 111 | public: |
|---|
| 112 | replace_animator(pdfcube::document& doc, int page_no) {}; |
|---|
| 113 | void |
|---|
| 114 | setup() {} |
|---|
| 115 | void |
|---|
| 116 | render(int frame) {} |
|---|
| 117 | void |
|---|
| 118 | tear_down() {} |
|---|
| 119 | }; |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | class cube_animator : public animator |
|---|
| 123 | { |
|---|
| 124 | public: |
|---|
| 125 | cube_animator(pdfcube::document& doc, int page_no) {}; |
|---|
| 126 | void |
|---|
| 127 | setup() {} |
|---|
| 128 | void |
|---|
| 129 | render(int frame) {} |
|---|
| 130 | void |
|---|
| 131 | tear_down() {} |
|---|
| 132 | }; |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | /** |
|---|
| 136 | * An animator factory returns an animator for the give page number of |
|---|
| 137 | * a document. |
|---|
| 138 | * |
|---|
| 139 | */ |
|---|
| 140 | class animator_factory |
|---|
| 141 | { |
|---|
| 142 | animator* make_animator(pdfcube::document& doc, int page_no) |
|---|
| 143 | { |
|---|
| 144 | switch(doc.page(page_no).transition_type()) |
|---|
| 145 | { |
|---|
| 146 | case POPPLER_PAGE_TRANSITION_REPLACE: |
|---|
| 147 | return new replace_animator(doc, page_no); |
|---|
| 148 | case POPPLER_PAGE_TRANSITION_BOX: |
|---|
| 149 | return new cube_animator(doc, page_no); |
|---|
| 150 | default: |
|---|
| 151 | return new replace_animator(doc, page_no); |
|---|
| 152 | } |
|---|
| 153 | return NULL; |
|---|
| 154 | } |
|---|
| 155 | }; |
|---|
| 156 | |
|---|
| 157 | // a main to quick-test some clutter api |
|---|
| 158 | int main(int argc, char* argv[]) |
|---|
| 159 | { |
|---|
| 160 | // -------------- |
|---|
| 161 | // Initialization |
|---|
| 162 | // -------------- |
|---|
| 163 | |
|---|
| 164 | pdfcube::app the_app; |
|---|
| 165 | |
|---|
| 166 | the_app.init(&argc, &argv); |
|---|
| 167 | |
|---|
| 168 | the_app.main_loop(); |
|---|
| 169 | |
|---|
| 170 | /* |
|---|
| 171 | // -------------------------- |
|---|
| 172 | // arrange pages in an index |
|---|
| 173 | // TODO: move in an animation |
|---|
| 174 | // -------------------------- |
|---|
| 175 | guint screen_w = 0; |
|---|
| 176 | guint screen_h = 0; |
|---|
| 177 | clutter_stage_fullscreen (CLUTTER_STAGE (stage)); |
|---|
| 178 | clutter_actor_get_size(CLUTTER_ACTOR(stage), &screen_w, &screen_h); |
|---|
| 179 | |
|---|
| 180 | double frows = ::sqrt(doc.n_pages()); |
|---|
| 181 | double fcols = std::ceil(((double)doc.n_pages())/std::floor(frows)); |
|---|
| 182 | |
|---|
| 183 | int cols = std::floor(fcols); |
|---|
| 184 | int rows = frows; |
|---|
| 185 | |
|---|
| 186 | double box_w = ((double)screen_w)/cols; |
|---|
| 187 | double box_h = ((double)screen_h)/rows; |
|---|
| 188 | double min_padding = 6; |
|---|
| 189 | |
|---|
| 190 | for(int ii(0); ii != doc.n_pages(); ++ii) |
|---|
| 191 | { |
|---|
| 192 | int row = ii%cols; |
|---|
| 193 | int col = ii/cols; |
|---|
| 194 | double box_x = ((double)row*screen_w)/cols; |
|---|
| 195 | double box_y = ((double)col*screen_h)/rows; |
|---|
| 196 | |
|---|
| 197 | double aspect = doc.page(ii).aspect_ratio(); |
|---|
| 198 | |
|---|
| 199 | double w = 0.0, h = 0.0; |
|---|
| 200 | |
|---|
| 201 | // Check if our slot ratio is less or more than owr own |
|---|
| 202 | if(box_h > box_w/aspect) |
|---|
| 203 | { |
|---|
| 204 | w = box_w - min_padding*2; |
|---|
| 205 | h = w/aspect; |
|---|
| 206 | } |
|---|
| 207 | else |
|---|
| 208 | { |
|---|
| 209 | h = box_h - min_padding*2; |
|---|
| 210 | w = h*aspect; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | |
|---|
| 214 | //cerr << w << ", " << h << ", " << aspect << endl; |
|---|
| 215 | |
|---|
| 216 | ClutterActor* page = |
|---|
| 217 | CLUTTER_ACTOR(doc.page(ii).actor(pdfcube::page::LOW_RES)); |
|---|
| 218 | clutter_actor_set_size(page, (int)w, (int)h); |
|---|
| 219 | clutter_actor_set_position(page, |
|---|
| 220 | (int)(box_x + box_w/2), |
|---|
| 221 | (int)(box_y + box_h/2)); |
|---|
| 222 | // THIS IS NOT RELATIVE TO ACTOR REAL SIZE, BUT TO ACTOR PERCEIVED SIZE |
|---|
| 223 | clutter_actor_set_anchor_point_from_gravity(page, CLUTTER_GRAVITY_CENTER); |
|---|
| 224 | clutter_group_add_many(CLUTTER_GROUP(stage), page, NULL); |
|---|
| 225 | // Make actor reactive |
|---|
| 226 | clutter_actor_set_reactive(page, TRUE); |
|---|
| 227 | g_signal_connect (page, "enter-event", |
|---|
| 228 | G_CALLBACK (on_page_enter), NULL); |
|---|
| 229 | g_signal_connect (page, "leave-event", |
|---|
| 230 | G_CALLBACK (on_page_leave), NULL); |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | // ------------------------- |
|---|
| 234 | |
|---|
| 235 | // Connect a signal handler to handle mouse clicks and key presses |
|---|
| 236 | // on the stage: |
|---|
| 237 | g_signal_connect (stage, "button-press-event", |
|---|
| 238 | G_CALLBACK (on_stage_button_press), NULL); |
|---|
| 239 | |
|---|
| 240 | |
|---|
| 241 | //clutter_stage_hide_cursor (CLUTTER_STAGE (stage)); |
|---|
| 242 | clutter_actor_show (stage); |
|---|
| 243 | clutter_main (); |
|---|
| 244 | */ |
|---|
| 245 | return 0; |
|---|
| 246 | } |
|---|