Logo Search packages:      
Sourcecode: gambas version File versions  Download package

CExample.c

/***************************************************************************

  CExample.c

  A component example

  (c) 2000-2003 Benoît Minisini <gambas@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 1, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/

/* This file is used for implementing a class and its possible virtual 
   classes.

   What is a virtual class ? It is a class that represents a sub-component
   of a class, but that you cannot instanciate nor reference into a
   variable. For example, the property Item of the ListBox class is a
   virtual class that represents a ListBox item.

   Virtual classes are just used as datatypes by the interpreter. But the
   object used behind is the real object coming from the real non-virtual
   class. For example, the Item property of the ListBox class stores the
   index of the item you want to deal with in the ListBox object, and
   returns this ListBox object. The ListBox object becomes then a virtual
   class object that you cannot store in a variable. As you must use the
   virtual class object immediately, by calling a method or a property
   on it, the stored index will be used immediately too.

   This mechanism has been designed so that the user manipulates temporary
   objects, without being compelled to create them. It is SO faster !

   Note that the name of a virtual class must begin with a dot. For
   example, the name of the virtual class used by the Item property is
   ".ListBoxItem".

   You can declare several classes in the same file, but you should
   generally avoid that. It is clearer this way.
*/

#define __CEXAMPLE_C

/* You can put there the system includes you need */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>


/* You must include main.h, to get a reference to the Gambas interface through
   the GB structure.
*/

#include "main.h"


/* Then you include the header of the class */

#include "CExample.h"


/* If your class raise events, you must declare them with the DECLARE_EVENT macro. */

#ifndef THIS_IS_JUST_AN_EXAMPLE
DECLARE_EVENT(FirstEvent);
DECLARE_EVENT(SecondEvent);
#endif


/* Then we implement the method and the properties of the class. First, we will
   begin with an example of each.
*/

/* To implement a method, you must write a function whose code is enclosed
   between the two macros: BEGIN_METHOD and END_METHOD.

   The BEGIN_METHOD macro takes TWO arguments: the function name, and a list
   of arguments separated by semicolons. The method arguments are NOT separated
   by commas, because they are in reality fields of a structure passed to
   the function.

   If your method takes no argument, you must use BEGIN_METHOD_VOID instead of
   BEGIN_METHOD. The BEGIN_METHOD_VOID function takes only one argument, the name
   of the function.

   The include gambas.h contains definitions for the argument types:

    - GB_BOOLEAN for a boolean argument.
    - GB_INTEGER for an integer argument.
    - GB_FLOAT for a double argument.
    - GB_STRING for a string argument.
    - GB_DATE for a date argument.
    - GB_VARIANT for a variant argument.
    - GB_OBJECT for a object reference.

   You MUST use these datatypes !

   To get the parameters, you have two macros : ARG() and VARG().

   The ARG() macro returns the address of the parameter in the interpreter stack, and
   is used with functions like GB.ToZeroString(), or GB.Store() functions.

   The VARG() macro returns the value of the parameter.
*/

#ifndef THIS_IS_JUST_AN_EXAMPLE
BEGIN_METHOD ( TheFunctionName , GB_INTEGER anInteger; GB_STRING aString; GB_VARIANT aVariant; GB_BOOLEAN aBoolean; )

  /* To get the value of a parameter, you must use the VARG macro. */

  printf("anInteger = %d\n", VARG(anInteger));

  /* To get a string parameter, you must use the special macros STRING and LENGTH
     to get the address of the string and its length.
  */

  printf("aString = %*.s\n", LENGTH(aString), STRING(aString));

  /* You can also transform the Gambas string into a C zero-terminated string with the
     GB.ToZeroString function. You must use the ARG macro to get the parameter address,
     and not the VARG macro that returns its value.
  */

  printf("aString = %.s\n", GB.ToZeroString(ARG(aString)));

  /* GB_VARIANT is a union of different datatypes. The type field of this union
     is one of the GB_T_* constants.
  */

  if (VARG(aVariant).type == GB_T_STRING)
    printf("I got the following string: %s\n", VARG(aVariant)._string.value);

  /* GB_BOOLEAN is stored as an integer, which is zero when FALSE, and different from
     zero when TRUE.
  */

  printf("aBoolean = %s\n", VARG(aBoolean) ? "TRUE" : "FALSE");

  /* If you want to raise an error into your method, you must use the GB.Error() function
     to register the error, and returns immediately after.
  */

  if (VARG(aBoolean))
  {
    GB.Error("There was an error !");
    return;
  }

  /* To return a value from the method, you can use the GB.Return<Type>() interface
     functions : GB.ReturnInteger() to return a integer, GB.ReturnBoolean() to return a
     boolean, etc.
  */

  GB.ReturnInteger(VARG(anInteger) * 2);

END_METHOD
#endif



/* To implement a property, you must write a function whose code is enclosed
   between the two macros : BEGIN_PROPERTY and END_PROPERTY.

   The BEGIN_PROPERTY macro takes one argument : the property name.

   The function is called both for reading and writing the property. To
   distinguish between the two cases, you must use the READ_PROPERTY macro.
   Of course, if your property is read-only, this is not necessary.

   When reading the property, you must return the property value with one of the
   GB.Return<Type> functions.

   When writing the property, you get the value to write with the VPROP macro.
   This macro takes one argument : the datatype of the property, which must be one
   of the datatype macro defined in gambas.h :

    - GB_BOOLEAN for a boolean property.
    - GB_INTEGER for an integer property.
    - GB_FLOAT for a double property.
    - GB_STRING for a string property.
    - GB_DATE for a date property.
    - GB_VARIANT for a variant property.
    - GB_OBJECT for a object reference property.

   Use the PROP macro to get the address of the value, if you want to use functions like
   GB.ToZeroString() or GB.Store() for example.
*/

#ifndef THIS_IS_JUST_AN_EXAMPLE
BEGIN_PROPERTY ( ThePropertyName )

  /* First, you must check if we want to read or to write the property. */

  if (READ_PROPERTY)
  {
    /* Here we are reading the property */

    printf("Returns the property value\n");

    /* The THIS macro is defined in the class header file. It returns a pointer
       to the data of the object structure.

       We suppose here that there is a char *AStringProperty defined in the object
       structure, and that char * points to a Gambas string.
    */

    GB.ReturnString(THIS->AStringProperty);
  }
  else
  {
    /* Here we are writing the property */

    /* To store a complex Gambas datatype like String or Object, you must use
       GB.StoreString() or GB.StoreObject(). These functions deals with
       reference counting.
    */

    printf("I'm going to write the value: %s\n", GB.ToZeroString(PROP(GB_STRING)));

    GB.StoreString(PROP(GB_STRING), &THIS->AStringProperty);

    /* Generally, a modified property implies some other actions */

    printf("Property has been modified. The new value is %s\n", THIS->AStringProperty);
  }

END_PROPERTY
#endif


/* Here are the real implementations of the CExample class methods and
   properties...
*/

BEGIN_METHOD(CEXAMPLE_new, GB_INTEGER width; GB_INTEGER height; GB_INTEGER data)

  THIS->data = (unsigned long *)VARG(data);
  THIS->width = VARG(width);
  THIS->height = VARG(height);

END_METHOD


BEGIN_METHOD_VOID(CEXAMPLE_free)

  /* Nothing to do */

END_METHOD


BEGIN_PROPERTY(CEXAMPLE_width)

  GB.ReturnInteger(THIS->width);

END_PROPERTY


BEGIN_PROPERTY(CEXAMPLE_height)

  GB.ReturnInteger(THIS->height);

END_PROPERTY


BEGIN_METHOD_VOID(CEXAMPLE_hflip)

  int i, i2, j, w, h;
  unsigned long *d;
  unsigned long c;

  w = THIS->width;
  h = THIS->height;
  d = THIS->data;

  for (j = 0; j < h; j++)
  {
    for (i = 0, i2 = (w - 1); i < (w / 2); i++, i2--)
    {
      c = d[i];
      d[i] = d[i2];
      d[i2] = c;
    }
    d += w;
  }

END_METHOD


BEGIN_METHOD_VOID(CEXAMPLE_vflip)

  int i, j, w, h;
  unsigned long *d, *d2;
  unsigned long c;

  w = THIS->width;
  h = THIS->height;
  d = THIS->data;
  d2 = &d[(h - 1) * w];

  for (j = 0; j < (h / 2); j++)
  {
    for (i = 0; i < w; i++)
    {
      c = d[i];
      d[i] = d2[i];
      d2[i] = c;
    }
    d += w;
    d2 -= w;
  }

END_METHOD


/* This is the implementation of a method used in a virtual class.

   Note how we can use the THIS macro, as the virtual object is in
   reality the real main object.
*/

BEGIN_METHOD(CEXAMPLE_pixels_get, GB_INTEGER x; GB_INTEGER y)

  int x = VARG(x);
  int y = VARG(y);

  if ((x < 0) || (y < 0) || (x >= THIS->width) || (y >= THIS->height))
    GB.ReturnInteger(-1);
  else
    GB.ReturnInteger(*(THIS->data + (y * THIS->width) + x));

END_METHOD


/* The last part of the class implementation file is the declaration of its
   description.

   A class description is an array of GB_DESC struct filled with special macros
   declared in gambas.h
*/

GB_DESC CExampleDesc[] =
{
  /* The first macro to use is GB_DECLARE. This macro takes two parameters :
     the class name, and the size of its object structure.

     If the class is virtual, or static (i.e. not creatable), you must pass 0
     to the size parameter.
  */

  GB_DECLARE("Example", sizeof(CEXAMPLE)),

  /* If you want this class to inherits another class, you can use the
     GB_INHERITS macro.

     Be careful : the object structure of your class must begin with the
     same field than the object structure of the inherited class.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_INHERITS("ExampleMother"),
  #endif

  /* If the class is virtual, you must use the GB_VIRTUAL_CLASS macro */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_VIRTUAL_CLASS(),
  #endif

  /* Then you can declare methods, constants, properties, and events.
     The order of the declarations is not important.

     The datatypes of Gambas properties, constants, method return values
     are specified with a string following this convention :

     - "b" is the Boolean datatype.
     - "i" is the Integer datatype.
     - "f" is the Float datatype
     - "d" is the Date datatype.
     - "s" is the String datatype.
     - "v" is the Variant datatype.
     - "o" is the Object datatype.

     To specify a class datatype, give the name of the class followed by a
     semicolon : "Class;" for example.
  */

  /*
     You declare a constant with the GB_CONSTANT macro.

     The syntax is : GB_CONSTANT(Name, Type, Value)

     - Name is the name of the constant.

     - Type is a string given the datatype of the constant.
       "i" indicates an integer constant, "f" a float constant, and "s" a string
       constant.

     - Value is the value of the constant: an integer if the constant is an
       integer, a string if the constant is a string, and the string represenation
       of the number if the constant is a float.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_CONSTANT("AnIntegerConstant", "i", 1972),
  GB_CONSTANT("AStringConstant", "s", "Gambas"),
  GB_CONSTANT("AFloatConstant", "f", "3.1415"),
  #endif

  /*
     You declare a method with the GB_METHOD macro, or GB_STATIC_METHOD
     if the method is static.

     The syntax is : GB_METHOD(Name, Type, Function, Parameters)

     - Name is the name of the method.

     - Type is the datatype of the value returned by the method. If the method
       returns no value, then you must put NULL there.

     - Function is the name of the function implementing the method.

     - Parameters is the string signature of the method.

     A signature is a catenated string of each parameter datatypes like
     "iiExample;s", but with the following extensions :

     - [ and ] delimit optional parameters.

     - ( and ) give a name to the first following parameter.

     - < and > indicates the possible constant values that the last integer
       parameter can take. It is mainly used with property declaration.

     If the method takes no parameters, then you must put NULL there.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_METHOD("AMethodThatReturnsNoValue", NULL, do_the_job,
    "(FirstParameter)i(SecondParameter)s[(FirstOptionalParameter)ClassName;(SecondOptionalParameter)v]"),
  GB_METHOD("AMethodThatReturnsAStringAndTakesNoParameter", "s", do_another_job, NULL),
  #endif

  /*
     You declare a property with the GB_PROPERTY macro, or GB_STATIC_PROPERTY
     if the property is static.

     If the property is read-only, you must use the GB_READ_PROPERTY and
     GB_STATIC_READ_PROPERTY macros.

     The syntax is : GB_PROPERTY(Name, Type, Function)

     - Name is the name of the property.

     - Type is a string that specifies the Gambas datatype of the property.

     - Function is the name of the function implementing the property.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_PROPERTY("AProperty", "s", do_AProperty),
  GB_STATIC_PROPERTY("AStaticProperty", "i", do_AStaticProperty),
  GB_READ_PROPERTY("AReadOnlyProperty", "i", do_AReadOnlyProperty),

  /* Note that the following property takes its value in the symbols defined in
     the Border class. Consequently, all these symbols must be constant.
  */

  GB_PROPERTY("AnotherProperty", "i<Border>", do_AnotherProperty),

  /* To be more precise, you can specify exactly which symbols are useful
     with this property.
  */

  GB_PROPERTY("AWellDefinedProperty", "i<Border,None,Plain>", do_AWellDefinedProperty),
  #endif

  /*
     You declare that the object can raise an event with the GB_EVENT macro.

     The syntax is : GB_EVENT(Name, Type, Signature, Identifier)

     - Name is the name of the event.

     - Type is the datatype returned by the event handler. It can be "b" for a
       Boolean or NULL for a handler returning no value.

     - Signature is the signature of the event, like the Signature parameter of
       the GB_METHOD macro.

     - Identifier is a pointer to a previously declared variable where the
       interpreter will put a value uniquely identifying this event.
       
       To declare an event identifier, use the DECLARE_EVENT macros.

       This identifier will be used with the GB.Raise() function to raise the
       event.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_EVENT("FirstEvent", NULL, "(Parameter)i", &FirstEvent),
  GB_EVENT("SecondEvent", "b", NULL, &SecondEvent),
  #endif

  /*
     There are special methods, whose name begins with an underscore
     characters. These special methods are called by interpreter in
     particular contexts.
  */

  /* The _new method is called when the class is instanciated. In this
     method, you must initialize the newly created object.

     The parameters of the method come from the parameters of the NEW
     instruction.
     
     This class manipulate the pixels data of an image Picture. You
     must pass to the constructor the width and the height of Picture,
     and the value returned by the Data property of the Pixels property
     of the Picture.
  */

  GB_METHOD("_new", NULL, CEXAMPLE_new, "(Width)i(Height)i(Data)i"),

  /* The _free method is called just before an object is destroyed. In this
     method, you must release every string and references used by the object.
  */

  GB_METHOD("_free", NULL, CEXAMPLE_free, NULL),

  /* The _get method is the read implementation of the [] operator. The
     parameters of this method come from the parameters of the operator.

     This method can be static or dynamic.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_METHOD("_get", "i", CEXAMPLE_get, "(X)i(Y)i"),
  #endif

  /* The _put method is the write implementation of the [] operator. The
     parameters of this method come from the parameters of the operator.

     The first parameter of this method is always the value that must be
     stored.

     This method can be static or dynamic.
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_METHOD("_put", NULL, CEXAMPLE_put, "(Value)i(X)i(Y)i"),
  #endif

  /* The _call method is executed when the class or the object is used as
     a method. A good example of a static use of this feature is the class
     Message, and a good example of a dynamic use of this feature is the
     virtual class .TextSelection of the TextBox or TextArea controls.

     For example, you can type Example("Show me !")
  */

  #ifndef THIS_IS_JUST_AN_EXAMPLE
  GB_STATIC_METHOD("_call", NULL, CEXAMPLE_call, "(Message)s"),
  #endif

  GB_PROPERTY_READ("Width", "i", CEXAMPLE_width),
  GB_PROPERTY_READ("Height", "i", CEXAMPLE_height),

  /* Here is an example of the use of a virtual class. The Data property
     will return a virtual representation of the Example object that will
     be used for getting the pixel datas passed to the Example constructor.
  */

  GB_PROPERTY_SELF("Pixels", ".ExamplePixels"),

  GB_METHOD("HFlip", NULL, CEXAMPLE_hflip, NULL),
  GB_METHOD("VFlip", NULL, CEXAMPLE_vflip, NULL),

  /* The declaration structure must end with the GB_END_DECLARE macro. */

  GB_END_DECLARE
};


/* Now we declare the virtual class used by the Data property */

GB_DESC CExamplePixelsDesc[] =
{
  /* We declare the name of the class, with a dot as first character. We tell
     the interpreter that the size of the object is 0 and that it is a virtual
     class.
  */

  GB_DECLARE(".ExamplePixels", 0), GB_VIRTUAL_CLASS(),

  /* This method will return the color of a pixel */

  GB_METHOD("_get", "i", CEXAMPLE_pixels_get, "(X)i(Y)i"),

  GB_END_DECLARE
};


Generated by  Doxygen 1.6.0   Back to index