home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / gadget.lha / gadget.doc next >
Text File  |  2008-11-16  |  18KB  |  450 lines

  1. ==========================
  2. amiga/tutorial #220, from crunch, 18234 chars, Thu Dec 12 03:37:17 1985
  3. There is/are comment(s) on this message.
  4. --------------------------
  5. TITLE: Fun with Gadgets
  6.                     PHUN WITH GADGETS - John T. Draper
  7.           ----------------------------------
  8.  
  9.   Feel free to distribute this information onto any network.   Please
  10. check first to avoid duplication.   Would at least like credit for the
  11. 20 hours or so I took in preparing this section.
  12.  
  13.   Gadgets are multi function input "devices" which run under Intuition.  There
  14. are four kinds,  and two flavers.
  15.  
  16. The flavers are:
  17.  
  18. 1) System gadgets - Those created for you when you create a window or screen
  19.  
  20. 2) User gadgets - Those gadgets YOU create and use in your program.   There
  21.    are four kinds of these.
  22.  
  23.  
  24. The four kinds are:
  25.  
  26. 1) Boolean Gadgets - Usually "Yes/no" desisions,  "On/Off" buttons,  and
  27.    other related uses.    They look like rectangles,  with text displayed 
  28.    (Or rendered), within those rectangles.
  29.  
  30. 2) Proportional Gadgets - Those which look like "Sliders" as displayed in
  31.    the "R G B" Controls in the "Preferences" program.   I think Amiga should
  32.    release the source to Preferences,  because It would be a very good example
  33.    program.
  34.  
  35. 3) String gadgets - These allow text entry through the Keyboard.  Text can be
  36.    automatically centered.
  37.  
  38. 4) Integer Gadget - A special form of string gadget that converts numeric text
  39.    input into integers.
  40.  
  41.  
  42. USING GADGETS
  43. -------------
  44.  
  45.   Each gadget has a data structure "Gadget",  which must first be declared
  46. and initialized.   There are several ways to do this.    The easiest way is
  47. to declare and initialize them like this:
  48.  
  49.   
  50. #define BLUE_GADGET 0         /* My own Gadget ID to mean this gadget */
  51. struct Gadget blue_gad = {
  52.    NL, 17,112, 150,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  53.    PROPGADGET,(APTR)&b_img, NL,
  54.    &btxt, NL,(APTR)&b_prop, BLUE_GADGET, NL
  55. };
  56.  
  57.  
  58. #define GREEN_GADGET 1        /* Another personal ID */
  59. struct Gadget green_gad = {
  60.    &blue_gad, 17,97, 120,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  61.    PROPGADGET,(APTR)&g_img, NL,
  62.    >xt, NL,(APTR)&g_prop, GREEN_GADGET, NL
  63. };
  64.  
  65.  
  66. #define RED_GADGET 2          /* And yet another gadget */
  67. struct Gadget red_gad = {
  68.    &green_gad, 17,82, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  69.    PROPGADGET,(APTR)&r_img, NL,
  70.    &rtxt, NL,(APTR)&r_prop, RED_GADGET, NL
  71. };
  72.  
  73.  
  74. #define TEX_GAD 3
  75. struct Gadget tex_gad = {
  76.    &red_gad, 10,10, 150,11, GADGHCOMP, STRINGCENTER | LONGINT,
  77.    STRGADGET, NL, NL,
  78.    NL, NL, (APTR)&TexString, TEX_GAD, NL
  79. };
  80.  
  81.    The #define BLUE_GADGET 0,  etc,  are my own personal numbers that I
  82. want to use to identify these gadgets in my very own personal way.   I am
  83. using them for identification and to take action when the gadget is chosen 
  84. via a C "Switch" statement.
  85.  
  86.    Each "Element" in the structures declared above are separated by commas
  87. (For those not familiar with C),  and will be explained in detail.   In the
  88. above examples are Three Proportional Gadgets,  and a Text Gadget.  A more
  89. detailed description of each of the gadget fields are listed below.   It is
  90. pretty well explained in the Intuition manual.    Just a lack of examples
  91. showing how to build and detect them.
  92.  
  93. -- (NextGadget) First element is the "link" to the next gadget.  Last gadget
  94.    has a Null (NL) for a link.   Note,  the last gadget is on the top.  The
  95.    LAST Gadget should be set to NULL (NL).
  96.  
  97. -- (LeftEdge, TopEdge) - Specifies the LOCATION of the gadget relative to the
  98.    window or screen,  in the above example,  "tex_gad.LeftEdge" has the 
  99.    value of 10.  The last gadget has LeftEdge = 17, TopEdge = 112 as shown
  100.    above.
  101.  
  102. -- (Width, Height) - Specifies the Width and the height of the gadget select
  103.    box.  In the above example,  the height remained the same,  and the Width
  104.    progressively got smaller.  Width = 150, Height = 11 on the last one,
  105.    then Width = 120, then eventually 90, See above.
  106.  
  107. -- (Flags) - Flags that you share with Intuition.to describe the appearance 
  108.    and behavior of the gadget.   GADGHCOMP is a flag that complements all
  109.    of the bits contained within the gadget's select box.
  110.  
  111. -- (Activation) - Other flags that are used to activate certain features of
  112.    the gadget.  GADGIMMEDIATE | RELVERIFY mean that we set BOTH those "Bits".
  113.  
  114. -- (GadgetType) - Describes the type of gadget.   In the example above,
  115.    STRGADGET is one of the four types of gadgets that describe "string" or
  116.    "Text".
  117.  
  118. -- (GadgetRender) - Points to an intuiImage.   This is what gets written onto
  119.    screen or window as the gadget.  In the case where we use the proportional
  120.    gadget, we supply the address of the Image Structure without initializing
  121.    it.   It then gets rendered as a rectangle.
  122.  
  123. -- (SelectRender) - In this example, we put a NULL (NL) in this field.   If
  124.    we wanted, we could put in another image.  This image would be displayed
  125.    during highlighting (When mouse button is pressed in the gadget's select
  126.    box).
  127.  
  128. -- (GadgetText) - A pointer to an "Intuitext" structure that describes any 
  129.    text that might be rendered when the gadget is rendered.
  130.  
  131. -- (MutualExclude) - In this example, we place a NULL (NL).  There are 32
  132.    bits that can be used to "Turn off" other gadgets if this gadget gets
  133.    selected.
  134.  
  135. -- (SpecialInfo) - A pointer to more information about proportional (PropInfo)
  136.    and text (StringInfo).
  137.    gadgets.
  138.  
  139. -- (GadgetID) - User definable ID Field.   It can be used to identify the
  140.    gadget from the gadget pointer.   I use it as an argument to the
  141.    "switch" statement,  because using an address (Or any large number) as
  142.    arguments to the "switch" statement will cause the system to crash.
  143.    It's a bug in the Lattice C compiler.
  144.  
  145. -- (UserData) - A pointer to data that can be of any user definable
  146.    structure or data.
  147.  
  148.    There are other structures needed for gadgets which are "SpecialInfo"
  149. types of structures.   They are: PropInfo, and StringInfo structures.
  150. These describe in detail more information on Proportional structures
  151. and Text structures.   Addresses of these structures will be put in the
  152. "SpecialInfo" field of the gadget structure.   For instance,  in the
  153. example above where the gadgets are declared and initialized, (APTR)&r_img
  154. is used in the "red_gad" declaration.   Where "r_img" is declared as follows:
  155.  
  156. struct Image    r_img, g_img, b_img;
  157.  
  158.    In this particular example,  these are Images used by Intuition.  Sometimes
  159. YOU have to declare your own image.   Other times,  such as in the case above,
  160. Intuition initializes these images.   On first reading of the Intuition manual,
  161. it is not evident that These are initialized.
  162.  
  163.  
  164.  
  165.  
  166. PropInfo Structure:
  167. -------------------
  168.  
  169.    A PropInfo structure contains specific information about a proportional
  170. gadget.   Such as a slider arm,  or a volume control.   
  171.  
  172. -- (flags) - A set of flags like:
  173.  
  174.    AUTOKNOB - If you want to use a generic default knob.   It's essentually
  175.    a rectangle that fills the body of the proportional gadget.   If you set
  176.    this flag,  Intuition will initialize the rest of this structure.
  177.    A piece of code in the Example GAD.C shows where Three proportional
  178.    structures are initialized.   These structures are named:
  179.    "r_prop", "g_prop", and "b_prop".
  180.  
  181. /***************************************************************************
  182.            Must Initialize the Proportional "Specialinfo" before
  183.       opening up the window.   Init Flags,  and position.
  184. ***************************************************************************/
  185.  
  186.    r_prop.Flags = g_prop.Flags = b_prop.Flags = FREEHORIZ | AUTOKNOB;
  187.    r_prop.HorizBody = g_prop.HorizBody = b_prop.HorizBody = 0x1000;
  188.    r_prop.HorizPot = g_prop.HorizPot = b_prop.HorizPot = 0x8000;
  189.  
  190.  
  191.    FREEHORIZ - Set this flag if you only want the "slider" or "Pot" to
  192.    slide horizontally.
  193.  
  194.    FREEVERT - Set this flag if you want to slide vertically only.
  195.  
  196.    PROPBORDERLESS - Set this flag if you don't want borders.
  197.  
  198.    KNOBHIT - Check this flag if you want to know if the mouse button is
  199.    on the knob.
  200.  
  201.    For example,  if you want a standard slider which is horizontally placed
  202. in the window,  set the flags:  AUTOKNOB | FREEHORIZ
  203.  
  204.    If you are using a custom gadget, for instance a "joystick" that can move
  205. BOTH horizontally and vertically like the source code example in this lesson.
  206. then set the flags:  FREEHORIZ | FREEVERT.
  207.  
  208. -- (HorizPot) - Horizontal Position value for the gadget.
  209.  
  210. -- (VertPot)  - Vert Position value for the gadget.
  211.  
  212. -- (horizBody) - The incremental width of the gadget.   If set to 0x1000,
  213.    means that the pot will move 1/16th of the full position if the mouse
  214.    was pressed between the slider and the side of the gadget.   it always
  215.    moves "towards" the point where the mouse was pressed.  The "joystick" 
  216.    custom gadget in the example sort of "Follows" the mouse.
  217.  
  218. -- (VertBody) - Vertical incremental width of the gadget.
  219.  
  220.    The following fields are set by Intuition and are accessable to the 
  221. user if needed.
  222.  
  223. -- (cWidth) - Container width.
  224.  
  225. -- (cHeight) - Container height.
  226.  
  227. -- (HPotRes, VPotRes) - Horiz and Vert increments.
  228.  
  229. -- (LeftBorder, TopBorder) - Container borders.
  230.  
  231.    Here is a PropInfo structure for a custom designed joystick.
  232.  
  233. struct PropInfo cust_prop = {
  234.    FREEHORIZ | FREEVERT,            /* Want knob to go both vert and horiz */
  235.    0x8000,  0x8000,                 /* Want knob to be centered initially  */
  236.    0x800,   0x800,                  /* Smallest increment the knob can move */
  237.    150, 50,                         /* cWidth, cHeight - Container w & h */
  238.    1, 1,                            /* HPosres, VPotres - Pot increments */
  239.    0, 0                             /* Container borders  */
  240. };
  241.  
  242.    You can stick this anywhere in the global declarations section of your
  243. program.  Because of the limitations of the Lattice C compiler,  It should
  244. be declared "Before" the Gadget structure that uses it.
  245.  
  246.    An important thing to remember about constructing gadgets is that the
  247. Coordinates in the Gadget structure are relative to the coordinates in the
  248. Window or Screen.
  249.  
  250.    The coordinates in the border, or intuitext structure used by gadgets
  251. are RELATIVE to the Gadgets and NOT the window.   For instance,  if you
  252. want text to be displayed OVER the gadget rectangle,  your Y coords will
  253. be about -8 to -10,  while your x coords will be positive.   The point where
  254. text is written is at the UPPER LEFT section of the letters and NOT the
  255. lower left portion of the letters like in the Macintosh.
  256.  
  257.    If you use borders around your gadgets, make sure you make room for
  258. at least one pixel around the "Selection box".   Because, when the user
  259. presses in the box,  it is inversed, and if the border coincides with
  260. a pixel in the selection box,   that pixel overlaps and turns into
  261. another color, thus making it look a bit cludgey.
  262.  
  263.  
  264.  
  265. HOW TO CREATE GADGETS IN YOUR PROGRAM
  266. -------------------------------------
  267.  
  268.    FIRST OFF - Sketch out an approximate picture showing approximately
  269. what the overall layout of the gadgets should look like.    Eventually,
  270. we will write a Gadget Editor,   but for now,   lets make one up the
  271. old fashion way.
  272.  
  273.    Define gadget structures for each gadget.   Set the gadget flags
  274. appropriately,  specify pointers to Special structures, like "PropInfo"
  275. or "StringInfo" structure in the "SpecialInfo" field.   If you have
  276. custom images that you have created,   you need to declare a pointer
  277. to the image.
  278.  
  279.    When you declare the gadgets,  you create the LAST gadget first in
  280. your Source code.   Each sucessive gadget then "Links" to the one in
  281. front of it.   The last gadget pointer is a NULL.   After each of the
  282. gadgets are linked properly,  then:
  283.  
  284.    Declare any custom images,  borders,  or Text associated with the
  285. gadget.   This section of code shows an example of this.   Remember,  this
  286. portion of code should come BEFORE any of the gadget declarations because
  287. the C compiler doesn't seem to be able to forward reference. 
  288.  
  289. /*  Image for a custom proportional gadget */
  290.  
  291. UWORD custimage[] = {
  292. 0x0000, 0x0000, 0x0180, 0x0660, 0x1818, 0x2004, 0x4002, 0x4002,
  293. 0x4002, 0x4002, 0x2004, 0x1818, 0x0660, 0x0180, 0x0000, 0x0000
  294. };
  295.  
  296. struct Image cus_image = {
  297.   0, 0,                    /* LeftEdge, TopEdge */
  298.   16, 16, 1,               /* Width, Height, Depth */
  299.   &custimage[0],           /* Pointer to bit image */
  300.   1,  0,                   /* PlanePick, Planeonoff */
  301.   NULL                     /* No other images */
  302. };
  303.  
  304. One of the gadgets that use the above image:
  305.  
  306. #define CUST_KNOB 4
  307. struct Gadget cust_knob = {
  308.    &tex_gad, 17, 140, 150, 50, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
  309.    PROPGADGET, (APTR)&cus_image, NL,
  310.    &cus2_txt, NL, (APTR)&cust_prop, CUST_KNOB, NL
  311. };
  312.  
  313.    Now,  we have to make sure the very first gadget is linked to our window
  314. OR SCREEN.   In this particular example,  we are only using a window,  and
  315. are using the Intuition WorkBench Screen.   The NewWindow structure is declared
  316. further down in the Code as shown below.   Making the assumption that the 
  317. gadget shown above is the FIRST gadget (last in listing),  then the New
  318. Window structure is shown as below.
  319.  
  320. /***************************************************************************
  321. *                  N E W     W I N D O W     S T R U C T U R E
  322. ***************************************************************************/
  323.  
  324. struct NewWindow nw = {
  325.   0, 0,                  /*  Start position                               */
  326.   320, 200,              /*  width, height,                               */
  327.   0, 1,                  /*  detail, block pens                           */
  328.   CLOSEWINDOW            /*  IDCMP flags                             */
  329. | REFRESHWINDOW
  330. | MOUSEBUTTONS
  331. | MOUSEMOVE
  332. | GADGETDOWN     <--  MUST SET THIS ONE 
  333. | GADGETUP,      <--  AND THIS ONE
  334.                          /*  Regular flags for gadgets and such           */
  335.   WINDOWDEPTH
  336. | WINDOWSIZING
  337. | WINDOWDRAG
  338. | REPORTMOUSE    <-- AND THIS ONE
  339. | WINDOWCLOSE
  340. | SMART_REFRESH,
  341.  
  342.   &cust_knob,            /* First gadget in list  <-- WE DO IT HERE       */
  343.   NULL,                  /* User checkmark                                */
  344.   "Fun with Gadgets",    /* Window Title                                  */
  345.   NULL,                  /* Pointer to screen (Set later)                 */
  346.   NULL,                  /* Pointer to superbitmap                        */
  347.   0, 0, 320, 186,        /* Ignored because not sizeable                  */
  348.   WBENCHSCREEN,          /* Using the Workbench screen                    */
  349.   };
  350.  
  351.    The example program given uses a different First Gadget.   
  352.  
  353.    The last thing you should do is set the appropriate flags.   That is
  354. shown above.
  355.  
  356. RESPONDING TO THOSE GADGETS
  357. ---------------------------
  358.  
  359.    Last but not least,  you need to be able to respond, read, or act on
  360. a gadget.   This is done by "Listening" to a gadget port.   A particular
  361. bit comes to you in a Message class field.   You must recieve this "message"
  362. from Intuition telling you that the user "clicked" the mouse in a particular
  363. gadget.   You don't know which one yet.   But you snatch that "message"
  364. by detecting a certain bit in the message.class field.   You tuck this
  365. value away for later use and "Reply" to the message, using the 
  366. ReplyMsg function.  We keep doing this over and over until the user
  367. closes the window.   This is called an "Event loop".
  368.  
  369.  
  370. /***************************************************************************
  371.                             MAIN EVENT LOOP
  372. ***************************************************************************/
  373.  
  374.    for (;;)
  375.    {
  376.  
  377.       if (message = (struct IntuiMessage *)GetMsg(w->UserPort))  {
  378.         MessageClass = message->Class;
  379.         code = message->Code;
  380.         ReplyMsg(message);
  381.         switch (MessageClass) {
  382.  
  383.            case GADGETUP    :
  384.            case GADGETDOWN  : do_gadgets(message, w);
  385.                               break;
  386.  
  387.            case CLOSEWINDOW : close_things();
  388.                               exit(0);
  389.                               break;
  390.            case MOUSEBUTTONS: break;
  391.         }   /* Case */
  392.       }  /* if */
  393.    }  /* for */
  394. } /* main */
  395.  
  396.    In the Message,  contains the Address of the gadget chosen by the user. 
  397. You pass the Message and the Window into a function called do_gadgets.
  398. This function identifies the gadget,  then acts on it in the appropriate
  399. way.    This function is listed below.   I basically grab the address of
  400. the particular structure,  then look for that special private code that
  401. I described to identify the gadget.
  402.  
  403. /***************************************************************************
  404.                            HANDLE THE GADGETS
  405. ***************************************************************************/
  406. do_gadgets (mes, win)
  407.  
  408. struct IntuiMessage *mes;        /* Pointer to Message structure */
  409. struct Window *win;              /* And a window structure       */
  410. {
  411.         struct Gadget *igad;     /* Ptr to gadget that Intuition found    */
  412.         int  gadgid;             /* ID Code identifying which gadget      */
  413.         ULONG val;
  414.  
  415.      igad = (struct Gadget *) mes->IAddress;      /* Ptr to a gadget      */
  416.         gadgid = igad->GadgetID;    /* My own personal code for this gad  */
  417.         val = (ULONG)TexString.LongInt;
  418.         switch(gadgid) {
  419.  
  420.             case GREEN_GADGET: break;
  421.             case BLUE_GADGET : break;
  422.             case TEX_GAD     : printf("got here ...\n");
  423.                                printf("val = %ld\n", val);
  424.                                break;
  425.         }
  426. }
  427.  
  428. As each gadget is identified, a CASE statement selects the appropriate
  429. action to be taken depending on the gadget.   In many cases, the SAME
  430. action is usually performed on similar gadgets,   but in the above
  431. example,  I only handle 3 gadgets.   I could have exampled more,  but
  432. Good ol Lattice C has a nasty bug that won't let me use four cases
  433. without crashing.   This is why it takes so long to write programs on the
  434. Amiga.   But thats the price for being a pioneer.
  435.  
  436.    Feel free to chop it up and hack it to death.   So gotta work on
  437. Menus tommorrow.   Only have the Amiga for 5 more days.   Next on
  438. my aggenda for learning is:
  439.  
  440. Menus
  441.  
  442. Requestors
  443.  
  444. Sound
  445.  
  446.    This is it for now.   Have fun hacking,  and I will be back with more
  447. later.   Feel free to ask me questions,  and tell me your problems
  448. with gadgets so we can solve them.
  449.  
  450.