home *** CD-ROM | disk | FTP | other *** search
- /*** viewer.c ***/
- /* A viewer is a window containing a picture.
- * Viewers automatically construct themselves when the user loads a picture
- * into this program
- * (c) Paul Field 1995
- */
-
- #include "viewer.h"
-
- #include <assert.h>
- #include "scale.h"
- #include "window.h"
-
- #include "allocate.h"
- #include "exception.h"
- #include "nev_message.h"
- #include "nev_toolbox.h"
- #include "nev_wimp.h"
- #include "picture.h"
-
-
- /* Actions associated with the viewer window */
- enum { action_VIEWER_CLOSED = 0x100 };
-
-
-
- /* The 'state' of a viewer object */
- typedef struct viewer_str
- { picture *pic;
- unsigned scale; /* sprite scale as a percentage */
-
- #ifndef NDEBUG
- unsigned *debug_id; /* Should always == &viewer_debug_id */
- #endif
- }viewer;
-
-
-
- /* Debugging code for validating viewer objects */
- /* This is a useful technique for ensuring that the handle you recieve in an event handler
- * (or get from the client handle of a toolbox object) isn't rubbish
- * (for example, if you've set the handler up wrong).
- * The idea is that you set up a unique code in the data structure, which you initialise
- * when the structure is created and blank when the structure is detroyed. Whenever you use
- * the structure you check the pointer.
- * The 'unique code' is generated by having a variable (viewer_debug_id) and using it's address
- * as the code.
- */
- #ifndef NDEBUG
- /* Used as a 'magic code' for verifying that an object is a viewer */
- static unsigned viewer_debug_id;
-
- static void viewer_validate(const viewer *v)
- { assert(v != NULL);
- assert(v->debug_id == &viewer_debug_id);
- }
- #else
- # define viewer_validate(v)
- #endif
-
-
-
-
- static void viewer_set_extent(const viewer *v, toolbox_o viewer_id)
- { os_box new_extent;
- unsigned width;
- unsigned height;
- wimp_window_state state;
-
- picture_size(v->pic, &width, &height);
-
- new_extent.x0 = 0;
- new_extent.y0 = 0;
- new_extent.x1 = (width * v->scale)/100;
- new_extent.y1 = (height * v->scale)/100;
-
- window_set_extent(0, viewer_id, &new_extent);
-
- /* Setting the extent doesn't change the window's on-screen extent
- * so we need to re-open the window to force the extent to change on-screen.
- * The toolbox window should return an 'about to be shown' action even though
- * we don't catch it because otherwise the area of the screen that would
- * have been covered by the window (before the extent was changed) will be redrawn
- * (Maybe there's a better way of doing this ?)
- */
- state.w = window_get_wimp_handle(0, viewer_id);
- wimp_get_window_state(&state);
- wimp_open_window((wimp_open *)&state);
- }
-
-
-
-
- static nevent_result viewer_fill_scale(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
- { viewer *v;
-
- assert(action_code == action_SCALE_ABOUT_TO_BE_SHOWN);
- NOT_USED(action_code);
- NOT_USED(action);
- NOT_USED(handle);
-
- v = toolbox_get_client_handle(0, id_block->ancestor_obj);
- viewer_validate(v);
- scale_set_value(0, id_block->this_obj, v->scale);
- return nevent_HANDLED;
- }
-
-
-
-
- static nevent_result viewer_set_scale(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
- { scale_action_apply_factor *apply_action = (scale_action_apply_factor *)action->data.reserved;
- viewer *v;
- os_box extent;
- toolbox_o viewer_id;
-
- assert(action_code == action_SCALE_APPLY_FACTOR);
- NOT_USED(action_code);
- NOT_USED(handle);
-
- viewer_id = id_block->ancestor_obj;
- v = toolbox_get_client_handle(0, viewer_id);
- viewer_validate(v);
-
- if (v->scale != apply_action->percent)
- { v->scale = apply_action->percent;
- viewer_set_extent(v, viewer_id);
-
- window_get_extent(0, viewer_id, &extent);
- window_force_redraw(0, viewer_id, &extent);
- }
-
- return nevent_HANDLED;
- }
-
-
-
-
- static nevent_result viewer_redraw(wimp_event_no event_code, wimp_block *event, toolbox_block *id_block, void *handle)
- { const viewer *v = handle;
- bool more;
- int origin_x;
- int origin_y;
-
- viewer_validate(v);
- assert(event_code == wimp_REDRAW_WINDOW_REQUEST);
- NOT_USED(event_code);
-
- more = wimp_redraw_window(&event->redraw);
-
- /* Calculate where the work area origin is on screen (or off screen) */
- origin_x = event->redraw.box.x0 - event->redraw.xscroll;
- origin_y = event->redraw.box.y1 - event->redraw.yscroll;
-
- try
- { /* Repeatedly ask the Wimp for an area of window to redraw and then plot the sprite */
- while (more)
- { picture_draw(v->pic, origin_x, origin_y, v->scale, &event->redraw.clip);
- more = wimp_get_rectangle(&event->redraw);
- }
- }
- catch
- { /* If there's an error during redraw then we could run into an infinite loop
- * if the error report window covers up the window and so causes another redraw and another error.
- * To avoid this happening, we hide the window (which destroys it because viewer_destroy() will be
- * called by the toolbox).
- */
- toolbox_hide_object(0, id_block->this_obj);
- throw();
- }
- catch_end
-
- return nevent_HANDLED;
- }
-
-
-
-
- static nevent_result viewer_destroy(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
- { viewer *v;
-
- assert(action_code == action_VIEWER_CLOSED);
- NOT_USED(action_code);
- NOT_USED(action);
- NOT_USED(handle);
-
- v = toolbox_get_client_handle(0, id_block->this_obj);
- viewer_validate(v);
-
- #ifndef NDEBUG
- v->debug_id = NULL;
- #endif
- nevent_wimp_deregister_handler(id_block->this_obj, wimp_REDRAW_WINDOW_REQUEST, viewer_redraw, v);
- picture_destroy(v->pic);
- memory_free(v);
-
- return nevent_HANDLED;
- }
-
-
-
- static void viewer_create(const char *file_name)
- { viewer *new_viewer;
- volatile toolbox_o viewer_id = toolbox_NULL_OBJECT;
-
- assert(file_name != NULL);
-
- new_viewer = memory_allocate(sizeof(viewer));
- new_viewer->pic = NULL; /* OK to destroy NULL picture */
-
- try
- { new_viewer->pic = picture_create(file_name);
- new_viewer->scale = picture_suggested_scale(new_viewer->pic);
- #ifndef NDEBUG
- new_viewer->debug_id = &viewer_debug_id;
- #endif
-
- /* Create viewer window on screen */
- viewer_id = toolbox_create_object(0, (toolbox_id)"Viewer");
- toolbox_set_client_handle(0, viewer_id, new_viewer);
- window_set_title(0, viewer_id, file_name);
- viewer_set_extent(new_viewer, viewer_id);
- nevent_wimp_register_handler(viewer_id, wimp_REDRAW_WINDOW_REQUEST, viewer_redraw, new_viewer);
- }
- catch
- { if (viewer_id != toolbox_NULL_OBJECT)
- { toolbox_delete_object(0, viewer_id);
- }
- picture_destroy(new_viewer->pic);
- memory_free(new_viewer);
- throw();
- }
- catch_end
- }
-
-
-
- static nevent_result data_load(wimp_message *message, void *handle)
- { /* repond to request to load sprite by creating a viewer */
-
- assert(message->action == message_DATA_LOAD || message->action == message_DATA_OPEN);
- NOT_USED(handle);
-
- if (picture_supported_file_type(message->data.data_xfer.file_type))
- { /* Send message to indicate that we're going to handle the load */
- message->action = message_DATA_LOAD_ACK;
- message->your_ref = message->my_ref;
- wimp_send_message(wimp_USER_MESSAGE, message, message->sender);
-
- viewer_create(message->data.data_xfer.file_name);
-
- return nevent_HANDLED;
- }
- return nevent_NOT_HANDLED;
- }
-
-
-
- void viewer_initialise(void)
- { nevent_message_register_handler(message_DATA_LOAD, data_load, NULL);
- nevent_message_register_handler(message_DATA_OPEN, data_load, NULL);
-
- nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_SCALE_ABOUT_TO_BE_SHOWN, viewer_fill_scale, NULL);
- nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_SCALE_APPLY_FACTOR, viewer_set_scale, NULL);
- nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_VIEWER_CLOSED, viewer_destroy, NULL);
- }
-