The following is the code for two cameras showing the same text at varying zoom level. Text gets highlighted at mouseover. Note that the text gets highlighted in both cameras.
#include <cZUI/cZUI.h> // general client header #include <cZUI/drivers/sdsgesdl.h> // video driver #include <cZUI/drivers/edsdl.h> // event driver #include <cZUI/contrib/activeleaf.h> // easy-to-use leaf, we inherit from it #include <cZUI/graphwindow.cpp> // Handles all cameras that paint in one window #include <cZUI/scenenode.h> // Leaf nodes cannot be placed directly // into the scene. We need a scenenode // above every leaf. #include "alloc_list.h" // keeps track of allocated nodes class TextLeaf : public ActiveLeaf { protected: char *txt; public: TextLeaf( double px, double py, const char *t ) : ActiveLeaf(px,py) { txt = new char[ strlen(t) + 1 ]; strcpy( txt, t ); }; void paint( Camera *c ) { ScrollableView *v = c->get_view(); v->pen( 0,0,0, 1 ); // color:black, thickness:1 v->setfontsize( 8 ); v->textout( xpos, ypos+8, txt ); }; void paint_hover( Camera *c ) { ScrollableView *v = c->get_view(); v->setfontsize( 8 ); v->pen( 120,0,0, 1 ); // color:darkred, thickness:1 v->textout( xpos, ypos+8, txt ); }; void get_boundrect( double &bx1, double &by1, double &bx2, double &by2 ) { bx1 = xpos; by1 = ypos; bx2 = bx1 + strlen(txt)*5.5; by2 = ypos + 8; }; bool check_event_fitspixels( Event * ) { // always catch mouse events return true; }; }; int main( int argc, char* argv[] ) { alloc_list heap; if( SDL_Init( SDL_INIT_VIDEO /*| SDL_INIT_NOPARACHUTE*/ ) ) { std::cout << "Problems initializing video, exiting" << std::endl; abort(); } unsigned long framecnt = 0; // Open a window of 640x480, 16bit. SDL_Surface *s1 = SDL_SetVideoMode(400, 240, 16, 0 /*SDL_RESIZABLE*/); // And create a driver that uses it. SDLSGESurfaceDriver driver1(s1); // The second camera uses the same window SDLSGESurfaceDriver driver2(s1); // create the scene Scene sc; // A Frame-rate window, 100 FPS GraphWindow<GenericCameraFocus,FrameUpdatePolicy,10> window1( &sc ); // A Camera that fills most of the window. SurfaceCamera camera1( "Camera 1", &driver1, 0xff, 0xff, 0xff, 0, 30, 400, 210); // A Camera taking a small portion of the screen (10,10,60,60) SurfaceCamera camera2( "Camera 2", &driver2, 0xff,0xff,0xff, /*bkgcolor*/ 0, 0, 400, 30 ); window1.cameras.add_surface_camera( &camera1 ); camera1.assign_parent( &window1 ); window1.cameras.add_surface_camera( &camera2 ); camera2.assign_parent( &window1 ); // All scene nodes are created dynamically to be automatically // freed at layer destruction TextLeaf test1( 20, 20, "Test1" ); LayerNode txtLayer; txtLayer.add_child( heap.add( new SceneNode( &test1 ) ) ); camera1.add_layer( &txtLayer ); camera2.add_layer( &txtLayer ); CameraSetEvent cse1( &camera1, 0,0, 60,40 ); camera1.handle_event( &cse1 ); CameraOnEvent cmr1_on( &camera1 ); camera1.handle_event( &cmr1_on ); CameraSetEvent cse2( &camera1, -100,-60, 140,100 ); camera2.handle_event( &cse2 ); CameraOnEvent cmr2_on( &camera2 ); camera2.handle_event( &cmr2_on ); SDL_Event event; bool quit = false; while( !quit ){ while( SDL_PollEvent(&event) ) { switch(event.type){ case SDL_QUIT: quit = 1; break; default: Event *e = SDLEventDriver::handle_event(&event); window1.handle_event( e ); delete e; break; } } window1.advance_time(); window1.process_internal_events(); window1.repaint(); framecnt++; usleep( 2000 ); } SDL_Quit(); return 0; } |
Resulting scene:
BaseSceneNode is the base of all the other nodes and contains event handling, boundrect test functions and node movement functions to be overriden by the nodes higher up in the hierarchy.
SceneNodes can have one child beneath them, allowing for composition, customizing existing nodes without a need to subclass or modify them. SceneNodes are often used to restrict/twist the flow of events to the nodes below or to draw additional appearance over them. Composition is a flexible tool borrowed from the Piccolo toolkit.
LeafNode is probably the first node presenting enough functionality to derive from, in order to create your own nodes. LeafNodes contain a (X,Y) position on the virtual canvas, perform translate and rotate, and provide limited event management (calling paint() on RepaintEvents).
GroupNodes are used to manipulate nodes together (translate, rotate etc.) They will also cache the bounding rectangle to reduce computation load at event handling. GroupNodes can be combined with other SceneNodes to achieve various effects. GroupNodes are the most versatile of all.
LayerNodes are GroupNodes that can be directly added to Camera, and can be toggled on/off dynamically.
ActiveLeaf nodes are the most suitable base for a scene node. They will handle all events, including Repaint, RepaintRect, MouseOver, MouseMove, and MouseDown/Up events.
ContainerNodes are simple one-selection groups with notification of selection change.
CursorPolicyNodes are used to set cursor policy for a group of nodes without having to code cursor policy functionality into every node type.
DefaultCursorNodes can be used to set default cursor over an area.
EventFilter nodes can be used to allow/deny certain events to children nodes. AreaEventFilters can be used to filter out events over an area, for all its children.
HUDGroupNodes can be used to hold a group of nodes fixed to the screen, whatever the view of the Camera.
class ImageLeaf : public ActiveLeaf { protected: Image *normal, *hover; double image_zoom; public: void paint( Camera * ); void paint_hover( Camera * ); void get_boundrect( double& double& double& double& ); bool check_event_fitspixels( Event *e ); ImageLeaf( double, double, Image*, Image*, double iz =1. ); }; ImageLeaf :: ImageLeaf( double px, double py, Image *nr, Image *hv, double iz ) : ActiveLeaf( px, py ), normal( nr ), hover( hv ), image_zoom(iz) { } void ImageLeaf :: paint( Camera *c ) { c->get_view()->put_image( normal, (int)xpos, (int)ypos, image_zoom ); } void ImageLeaf :: paint_hover( Camera *c ) { c->get_view()->put_image( hover, (int)xpos, (int)ypos, image_zoom ); } void ImageLeaf :: get_boundrect( double& rx1, double &ry1, double &rx2, double &ry2 ) { int w,h; normal->get_dimensions( w, h ); w /= image_zoom; // image_zoom specifies the scene zoom at h /= image_zoom; // which image displays normally rx1 = xpos; ry1 = ypos; rx2 = rx1 + w; ry2 = ry1 + h; } bool ImageLeaf :: check_event_fitspixels( Event *e ) { if( hover ) return 1; return 0; } // in main Image *arr_normal, *arr_hover, *tmp; tmp = camera1.get_view()->load_image( "./bmw_normal.bmp" ); arr_normal = tmp->convert_to_565(); delete tmp; tmp = camera1.get_view()->load_image( "./bmw.bmp" ); arr_hover = tmp->convert_to_565(); delete tmp; ImageLeaf testimg( 5,17, arr_normal, arr_hover, 10 ); txtLayer.add_child( heap.add( new SceneNode( &testimg ) ) ); |