home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / toollib_2 / Examples / GFXView / Builds / c / viewer < prev   
Encoding:
Text File  |  1996-06-13  |  7.8 KB  |  267 lines

  1. /*** viewer.c ***/
  2. /* A viewer is a window containing a picture.
  3.  * Viewers automatically construct themselves when the user loads a picture
  4.  * into this program
  5.  * (c) Paul Field 1995
  6.  */
  7.  
  8. #include "viewer.h"
  9.  
  10. #include <assert.h>
  11. #include "scale.h"
  12. #include "window.h"
  13.  
  14. #include "allocate.h"
  15. #include "exception.h"
  16. #include "nev_message.h"
  17. #include "nev_toolbox.h"
  18. #include "nev_wimp.h"
  19. #include "picture.h"
  20.  
  21.  
  22. /* Actions associated with the viewer window */
  23. enum { action_VIEWER_CLOSED = 0x100 };
  24.  
  25.  
  26.  
  27. /* The 'state' of a viewer object */
  28. typedef struct viewer_str
  29.  { picture         *pic;
  30.    unsigned        scale;        /* sprite scale as a percentage */
  31.  
  32. #ifndef NDEBUG
  33.    unsigned        *debug_id;    /* Should always == &viewer_debug_id */
  34. #endif
  35.  }viewer;
  36.  
  37.  
  38.  
  39. /* Debugging code for validating viewer objects */
  40. /* This is a useful technique for ensuring that the handle you recieve in an event handler
  41.  * (or get from the client handle of a toolbox object) isn't rubbish
  42.  * (for example, if you've set the handler up wrong).
  43.  * The idea is that you set up a unique code in the data structure, which you initialise
  44.  * when the structure is created and blank when the structure is detroyed. Whenever you use
  45.  * the structure you check the pointer.
  46.  * The 'unique code' is generated by having a variable (viewer_debug_id) and using it's address
  47.  * as the code.
  48.  */
  49. #ifndef NDEBUG
  50.   /* Used as a 'magic code' for verifying that an object is a viewer */
  51.   static unsigned viewer_debug_id;
  52.  
  53.   static void viewer_validate(const viewer *v)
  54.    { assert(v != NULL);
  55.      assert(v->debug_id == &viewer_debug_id);
  56.    }
  57. #else
  58. #  define viewer_validate(v)
  59. #endif
  60.  
  61.  
  62.  
  63.  
  64. static void viewer_set_extent(const viewer *v, toolbox_o viewer_id)
  65.  { os_box            new_extent;
  66.    unsigned          width;
  67.    unsigned          height;
  68.    wimp_window_state state;
  69.  
  70.    picture_size(v->pic, &width, &height);
  71.  
  72.    new_extent.x0 = 0;
  73.    new_extent.y0 = 0;
  74.    new_extent.x1 = (width  * v->scale)/100;
  75.    new_extent.y1 = (height * v->scale)/100;
  76.  
  77.    window_set_extent(0, viewer_id, &new_extent);
  78.  
  79.    /* Setting the extent doesn't change the window's on-screen extent
  80.     * so we need to re-open the window to force the extent to change on-screen.
  81.     * The toolbox window should return an 'about to be shown' action even though
  82.     * we don't catch it because otherwise the area of the screen that would
  83.     * have been covered by the window (before the extent was changed) will be redrawn
  84.     * (Maybe there's a better way of doing this ?)
  85.     */
  86.    state.w = window_get_wimp_handle(0, viewer_id);
  87.    wimp_get_window_state(&state);
  88.    wimp_open_window((wimp_open *)&state);
  89.  }
  90.  
  91.  
  92.  
  93.  
  94. static nevent_result viewer_fill_scale(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
  95.  { viewer *v;
  96.  
  97.    assert(action_code == action_SCALE_ABOUT_TO_BE_SHOWN);
  98.    NOT_USED(action_code);
  99.    NOT_USED(action);
  100.    NOT_USED(handle);
  101.  
  102.    v = toolbox_get_client_handle(0, id_block->ancestor_obj);
  103.    viewer_validate(v);
  104.    scale_set_value(0, id_block->this_obj, v->scale);
  105.    return nevent_HANDLED;
  106.  }
  107.  
  108.  
  109.  
  110.  
  111. static nevent_result viewer_set_scale(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
  112.  { scale_action_apply_factor *apply_action = (scale_action_apply_factor *)action->data.reserved;
  113.    viewer    *v;
  114.    os_box    extent;
  115.    toolbox_o viewer_id;
  116.  
  117.    assert(action_code == action_SCALE_APPLY_FACTOR);
  118.    NOT_USED(action_code);
  119.    NOT_USED(handle);
  120.  
  121.    viewer_id = id_block->ancestor_obj;
  122.    v = toolbox_get_client_handle(0, viewer_id);
  123.    viewer_validate(v);
  124.  
  125.    if (v->scale != apply_action->percent)
  126.     { v->scale = apply_action->percent;
  127.       viewer_set_extent(v, viewer_id);
  128.  
  129.       window_get_extent(0, viewer_id, &extent);
  130.       window_force_redraw(0, viewer_id, &extent);
  131.     }
  132.  
  133.    return nevent_HANDLED;
  134.  }
  135.  
  136.  
  137.  
  138.  
  139. static nevent_result viewer_redraw(wimp_event_no event_code, wimp_block *event, toolbox_block *id_block, void *handle)
  140.  { const viewer *v = handle;
  141.    bool more;
  142.    int  origin_x;
  143.    int  origin_y;
  144.  
  145.    viewer_validate(v);
  146.    assert(event_code == wimp_REDRAW_WINDOW_REQUEST);
  147.    NOT_USED(event_code);
  148.  
  149.    more = wimp_redraw_window(&event->redraw);
  150.  
  151.    /* Calculate where the work area origin is on screen (or off screen) */
  152.    origin_x = event->redraw.box.x0 - event->redraw.xscroll;
  153.    origin_y = event->redraw.box.y1 - event->redraw.yscroll;
  154.  
  155.    try
  156.     { /* Repeatedly ask the Wimp for an area of window to redraw and then plot the sprite */
  157.       while (more)
  158.        { picture_draw(v->pic, origin_x, origin_y, v->scale, &event->redraw.clip);
  159.          more = wimp_get_rectangle(&event->redraw);
  160.        }
  161.     }
  162.    catch
  163.     { /* If there's an error during redraw then we could run into an infinite loop
  164.        * if the error report window covers up the window and so causes another redraw and another error.
  165.        * To avoid this happening, we hide the window (which destroys it because viewer_destroy() will be
  166.        * called by the toolbox).
  167.        */
  168.       toolbox_hide_object(0, id_block->this_obj);
  169.       throw();
  170.     }
  171.    catch_end
  172.  
  173.    return nevent_HANDLED;
  174.  }
  175.  
  176.  
  177.  
  178.  
  179. static nevent_result viewer_destroy(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
  180.  { viewer *v;
  181.  
  182.    assert(action_code == action_VIEWER_CLOSED);
  183.    NOT_USED(action_code);
  184.    NOT_USED(action);
  185.    NOT_USED(handle);
  186.  
  187.    v = toolbox_get_client_handle(0, id_block->this_obj);
  188.    viewer_validate(v);
  189.  
  190. #ifndef NDEBUG
  191.    v->debug_id = NULL;
  192. #endif
  193.    nevent_wimp_deregister_handler(id_block->this_obj, wimp_REDRAW_WINDOW_REQUEST, viewer_redraw, v);
  194.    picture_destroy(v->pic);
  195.    memory_free(v);
  196.  
  197.    return nevent_HANDLED;
  198.  }
  199.  
  200.  
  201.  
  202. static void viewer_create(const char *file_name)
  203.  { viewer             *new_viewer;
  204.    volatile toolbox_o viewer_id = toolbox_NULL_OBJECT;
  205.  
  206.    assert(file_name != NULL);
  207.  
  208.    new_viewer = memory_allocate(sizeof(viewer));
  209.    new_viewer->pic      = NULL; /* OK to destroy NULL picture */
  210.  
  211.    try
  212.     { new_viewer->pic   = picture_create(file_name);
  213.       new_viewer->scale = picture_suggested_scale(new_viewer->pic);
  214. #ifndef NDEBUG
  215.       new_viewer->debug_id = &viewer_debug_id;
  216. #endif
  217.  
  218.       /* Create viewer window on screen */
  219.       viewer_id = toolbox_create_object(0, (toolbox_id)"Viewer");
  220.       toolbox_set_client_handle(0, viewer_id, new_viewer);
  221.       window_set_title(0, viewer_id, file_name);
  222.       viewer_set_extent(new_viewer, viewer_id);
  223.       nevent_wimp_register_handler(viewer_id, wimp_REDRAW_WINDOW_REQUEST, viewer_redraw, new_viewer);
  224.     }
  225.    catch
  226.     { if (viewer_id != toolbox_NULL_OBJECT)
  227.        { toolbox_delete_object(0, viewer_id);
  228.        }
  229.       picture_destroy(new_viewer->pic);
  230.       memory_free(new_viewer);
  231.       throw();
  232.     }
  233.    catch_end
  234.  }
  235.  
  236.  
  237.  
  238. static nevent_result data_load(wimp_message *message, void *handle)
  239.  { /* repond to request to load sprite by creating a viewer */
  240.  
  241.    assert(message->action == message_DATA_LOAD || message->action == message_DATA_OPEN);
  242.    NOT_USED(handle);
  243.  
  244.    if (picture_supported_file_type(message->data.data_xfer.file_type))
  245.     { /* Send message to indicate that we're going to handle the load */
  246.       message->action   = message_DATA_LOAD_ACK;
  247.       message->your_ref = message->my_ref;
  248.       wimp_send_message(wimp_USER_MESSAGE, message, message->sender);
  249.  
  250.       viewer_create(message->data.data_xfer.file_name);
  251.  
  252.       return nevent_HANDLED;
  253.     }
  254.    return nevent_NOT_HANDLED;
  255.  }
  256.  
  257.  
  258.  
  259. void viewer_initialise(void)
  260.  { nevent_message_register_handler(message_DATA_LOAD, data_load, NULL);
  261.    nevent_message_register_handler(message_DATA_OPEN, data_load, NULL);
  262.  
  263.    nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_SCALE_ABOUT_TO_BE_SHOWN, viewer_fill_scale, NULL);
  264.    nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_SCALE_APPLY_FACTOR,      viewer_set_scale,  NULL);
  265.    nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_VIEWER_CLOSED,           viewer_destroy,    NULL);
  266.  }
  267.