home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / toollib_2 / Examples / Click / Builds / c / main
Encoding:
Text File  |  1996-06-13  |  9.3 KB  |  333 lines

  1. /*** Click ***/
  2. /* A demonstration of Toolbox programming using OSLib
  3.  * (c) Paul Field/Andrew Ellis 1995
  4.  *
  5.  * Shell application by Paul Field
  6.  * Window handling/object handling by Andrew Ellis
  7.  */
  8.  
  9. /* Notes:
  10.  *
  11.  * OSLib refers to toolbox events as 'actions' and, for consistancy, we follow
  12.  * this convention.
  13.  *
  14.  * The NOT_USED(var) macro is used to supress a compiler warnings about 'var'
  15.  * being declared but not being used. This warning occurs when the Acorn compiler
  16.  * features "ah" are enabled. You should activate these features because they
  17.  * enable useful warnings which can indicate bugs in your program.
  18.  */
  19.  
  20. #include <assert.h>
  21. #include <stddef.h>
  22. #include <stdio.h>
  23.  
  24. #include "colourdbox.h"
  25. #include "colourtrans.h"
  26. #include "window.h"
  27.  
  28. #include "allocate.h"
  29. #include "applicatio.h"
  30. #include "exception.h"
  31. #include "nev_toolbox.h"
  32. #include "nev_wimp.h"
  33.  
  34.  
  35.  
  36. typedef enum
  37.  { CIRCLE,
  38.    SQUARE  /* Not supported yet */
  39.  } object_type;
  40.  
  41. typedef struct
  42.  { object_type type;
  43.    os_colour colour;
  44.    int x, y;
  45.  } object;
  46.  
  47.  
  48. /* The size (e.g. radius, width) of our objects */
  49. #define OBJECTSIZE 32
  50.  
  51.  
  52. /* The maximum number of objects we can have in our window. If we exceed this
  53.  * number we won't add any more objects because we haven't allocated enough
  54.  * memory for our array. We could either 'return' and not do anything, report
  55.  * an error saying that we can't add any more objects or we could re-allocate
  56.  * the memory to allow for the extra objects. If we did this we could keep
  57.  * on adding objects until we ran out of memory
  58.  */
  59. #define MAXNUMOBJECTS 128
  60.  
  61.  
  62. /* When we check to see if an object overlaps a region of screen being
  63.  * redrawn, or request that a particular region be redrawn, we add in a
  64.  * small border around the object concerned for safety, to avoid numerical
  65.  * rounding errors which could otherwise results in small overlaps etc being
  66.  * missed. This is the width of that border strip in os graphics units.
  67.  */
  68. #define BORDER 8
  69.  
  70.  
  71. /* The number of objects current in our array of objects */
  72. static int num_objects;
  73.  
  74. /* A pointer to the array of objects */
  75. static object *objects;
  76.  
  77. /* This holds the currently selected colour */
  78. static os_colour current_colour;
  79.  
  80.  
  81.  
  82. static void circle_fill(int x, int y, unsigned radius)
  83.  { os_plot(os_MOVE_TO, x, y);
  84.    os_plot(os_PLOT_CIRCLE + os_PLOT_BY, radius, 0);
  85.  }
  86.  
  87.  
  88.  
  89.  
  90. /* The following three routines are not yet used in this program */
  91. #if 0
  92. static void circle_outline(int x, int y, unsigned radius)
  93.  { os_plot(os_MOVE_TO, x, y);
  94.    os_plot(os_PLOT_CIRCLE_OUTLINE + os_PLOT_BY, radius, 0);
  95.  }
  96.  
  97.  
  98.  
  99.  
  100. static void rectangle_outline(int x, int y, unsigned width, unsigned height)
  101.  { os_plot(os_MOVE_TO, x, y);
  102.    os_plot(os_PLOT_SOLID + os_PLOT_BY, width, 0);
  103.    os_plot(os_PLOT_SOLID + os_PLOT_BY, 0, height);
  104.    os_plot(os_PLOT_SOLID + os_PLOT_BY, -width, 0);
  105.    os_plot(os_PLOT_SOLID + os_PLOT_BY, 0, -height);
  106.  }
  107.  
  108.  
  109.  
  110.  
  111. static void rectangle_fill(int x, int y, unsigned width, unsigned height)
  112.  { os_plot(os_MOVE_TO, x, y);
  113.    os_plot(os_PLOT_RECTANGLE + os_PLOT_BY, width, height);
  114.  }
  115. #endif
  116.  
  117.  
  118.  
  119.  
  120. static void force_redraw_object(const object *obj, toolbox_o viewer_id)
  121. /* This function forces the area of window where the object 'obj' is to be
  122.  * redrawn. If we didn't do this after adding obj, it wouldn't be displayed
  123.  * in the window until a redraw occured perhaps due to another window
  124.  * being dragged over the window.
  125.  */
  126.  { os_box box;
  127.  
  128.    box.x0 = obj->x-OBJECTSIZE-BORDER;
  129.    box.x1 = obj->x+OBJECTSIZE+BORDER;
  130.    box.y0 = obj->y-OBJECTSIZE-BORDER;
  131.    box.y1 = obj->y+OBJECTSIZE+BORDER;
  132.  
  133.    window_force_redraw(0,viewer_id,&box);
  134.  }
  135.  
  136.  
  137.  
  138.  
  139.  
  140. static nevent_result object_set_colour(bits action_code, toolbox_action *action, toolbox_block *id_block, void *handle)
  141. /* This function is called when the user sets the colour which future objects will be */
  142.  {
  143.   /* There's a bug in OSLib v5.1: the colourdbox_action_colour_selected is not defined properly (it has an extra 'flags' field).
  144.    * To get around we 'bodge' the transformation from a toolbox_action to a colourdbox_action_colour_selected.
  145.    * The line we *should* use is:
  146.    *      colourdbox_action_colour_selected *colour_action = (colourdbox_action_colour_selected *)action->data.reserved;
  147.    */
  148.   colourdbox_action_colour_selected *colour_action = (colourdbox_action_colour_selected *)&action->flags;
  149.  
  150.   /* This assert should fail if the program is compiled with a 'fixed' version of OSLib.
  151.    * When it fails, we can remove it and replace the 'bodge' above with the correct code
  152.    */
  153.   assert(offsetof(colourdbox_action_colour_selected, colour) == 4);
  154.  
  155.   NOT_USED(handle);
  156.   NOT_USED(action_code);
  157.   NOT_USED(action);
  158.   NOT_USED(id_block);
  159.  
  160.   current_colour = colour_action->colour;
  161.  
  162.   return nevent_HANDLED;
  163. }
  164.  
  165.  
  166.  
  167.  
  168. static void draw_object(const object *obj, const unsigned origin_x, const unsigned origin_y)
  169. /* This function draws an object. (origin_x, origin_y) is where the origin of the window would appear
  170.  * on the screen (it might be a coordinate that is off of the edge of the screen)
  171.  */
  172.  { unsigned screen_x, screen_y;
  173.  
  174.    /* Work out the x and y positions in the window */
  175.    screen_x = obj->x + origin_x;
  176.    screen_y = obj->y + origin_y;
  177.  
  178.    colourtrans_set_gcol(obj->colour, 0, os_ACTION_OVERWRITE, NULL);
  179.  
  180.    switch (obj->type)
  181.     { case CIRCLE:
  182.         circle_fill(screen_x, screen_y, OBJECTSIZE);
  183.         break;
  184.     }
  185.  }
  186.  
  187.  
  188.  
  189.  
  190. static nevent_result object_add_object_handler(wimp_event_no event_code, wimp_block *event, toolbox_block *id_block, void *handle)
  191. /* This function responds to mouse clicks and adds an object where the click occured */
  192. /* The type of object added depends on which button was clicked (currently only circles are added) */
  193.  { wimp_window_state state;
  194.    unsigned origin_x, origin_y;
  195.  
  196.    NOT_USED(handle);
  197.    NOT_USED(event_code);
  198.  
  199.    /* Calculate where the work area origin is on screen (or off screen) */
  200.    /* We need the work area origin so we can convert between the coordinates
  201.     * of the mouse click (in screen coordinates) and the work area coordinates
  202.     * where we want to add the shape
  203.     */
  204.    state.w = event->pointer.w;
  205.    wimp_get_window_state(&state);
  206.  
  207.    origin_x = state.visible.x0 - state.xscroll;
  208.    origin_y = state.visible.y1 - state.yscroll;
  209.  
  210.  
  211.    /* Check there's enough room in the objects array for a new object */
  212.    if (num_objects < MAXNUMOBJECTS)
  213.     { /* If the select button was pressed then we add our object*/
  214.       if (event->pointer.buttons & wimp_CLICK_SELECT)
  215.        { objects[num_objects].type   = CIRCLE;
  216.          objects[num_objects].x      = event->pointer.pos.x - origin_x;
  217.          objects[num_objects].y      = event->pointer.pos.y - origin_y;
  218.          objects[num_objects].colour = current_colour;
  219.  
  220.          /* Make sure the object appears in the window */
  221.          force_redraw_object(objects+num_objects, id_block->this_obj);
  222.  
  223.          /* Increase num_objects because there's now one more object */
  224.          num_objects++;
  225.        }
  226.     }
  227.    else
  228.     { /* 'beep' if we can't add any more objects */
  229.       os_bell();
  230.     }
  231.  
  232.    return nevent_HANDLED;
  233.  }
  234.  
  235.  
  236.  
  237.  
  238. static nevent_result viewer_redraw(wimp_event_no event_code, wimp_block *event, toolbox_block *id_block, void *handle)
  239. /* This function redraws the window when the wimp requests us to do so */
  240.  { bool more;
  241.    int  origin_x;
  242.    int  origin_y;
  243.  
  244.    assert(event_code == wimp_REDRAW_WINDOW_REQUEST);
  245.    NOT_USED(event_code);
  246.    NOT_USED(event);
  247.    NOT_USED(handle);
  248.  
  249.    more = wimp_redraw_window(&event->redraw);
  250.  
  251.    /* Calculate where the work area origin is on screen (or off screen) */
  252.    origin_x = event->redraw.box.x0 - event->redraw.xscroll;
  253.    origin_y = event->redraw.box.y1 - event->redraw.yscroll;
  254.  
  255.    try
  256.     { while (more)
  257.        { unsigned object_idx;
  258.  
  259.          for (object_idx = 0; object_idx < num_objects; object_idx++)
  260.           { draw_object(&objects[object_idx], origin_x, origin_y);
  261.           }
  262.          more = wimp_get_rectangle(&event->redraw);
  263.        }
  264.     }
  265.    catch
  266.     { /* If there's an error during redraw then we could run into an infinite loop
  267.        * if the error report window covers up the window and so causes another redraw and another error.
  268.        * To avoid this happening, we hide the window
  269.        */
  270.       toolbox_hide_object(0, id_block->this_obj);
  271.       throw();
  272.     }
  273.    catch_end
  274.  
  275.    return nevent_HANDLED;
  276.  }
  277.  
  278.  
  279.  
  280.  
  281. static void click_initialise(int argc, char *argv[])
  282.  { toolbox_o viewer_id;
  283.  
  284.    NOT_USED(argc);
  285.    NOT_USED(argv);
  286.  
  287. #ifndef NDEBUG
  288.    /* Redirect error stream */
  289.    freopen("pipe:$.debug", "w", stderr);
  290. #endif
  291.  
  292.    nevent_wimp_initialise();
  293.  
  294.    /* Allocate some memory for the object array */
  295.    objects = memory_allocate(MAXNUMOBJECTS * sizeof(object));
  296.  
  297.    viewer_id = toolbox_create_object(0, (toolbox_id)"Viewer");
  298.    nevent_wimp_register_handler(viewer_id, wimp_REDRAW_WINDOW_REQUEST, viewer_redraw,             NULL);
  299.    nevent_wimp_register_handler(viewer_id, wimp_MOUSE_CLICK,           object_add_object_handler, NULL);
  300.    nevent_toolbox_register_handler(nevent_ALL_OBJECTS, action_COLOUR_DBOX_COLOUR_SELECTED, object_set_colour, NULL);
  301.  }
  302.  
  303.  
  304.  
  305.  
  306. /* Respond to all actions and messages */
  307. static const int toolbox_actions[] =
  308.  { 0x44ec0,
  309.    0x829c2,
  310.    0x82a91,
  311.    0
  312.  };
  313.  
  314.  
  315. #if 0
  316. /* no messages, so NULL is used in the this_application struture */
  317. static const int wimp_messages[] =
  318.  {
  319.  };
  320. #endif
  321.  
  322.  
  323. /* The variable which the application system required */
  324. application this_application =
  325.  { "<Click$Dir>",
  326.    310,
  327.    toolbox_actions,
  328.    NULL, /*wimp_messages,*/
  329.    3,
  330.    click_initialise,
  331.    NULL
  332.  };
  333.