/* echo-countries.c 1.1 */ /* Copyright 1992, 1993 O'Reilly and Associates, Inc. Permission to use, copy, and modify this program is hereby granted, as long as this copyright notice appears in each copy of the program source code. */ #include "book_utils.h" #include "western-europe.h" static Display *dpy; static Window window; static PEXRenderer renderer; static PEXPickPath *last_pick; static PEXColor echo_color, normal_color; static PEXColor name_color, background_color; static PEXCoord2D name_position = {0.95, 0.93}; /* The structure ids. */ static PEXStructure w_europe, structs[NUM_COUNTRIES]; static void show_name( country, color ) char *country; PEXColor *color; { PEXSetViewIndex( dpy, renderer, PEXOCRender, 0 ); PEXSetTextPrecision( dpy, renderer, PEXOCRender, PEXStrokePrecision ); PEXSetCharHeight( dpy, renderer, PEXOCRender, 0.03 ); PEXSetTextAlignment( dpy, renderer, PEXOCRender, PEXHAlignRight, PEXVAlignBase ); PEXSetTextColor( dpy, renderer, PEXOCRender, PEXColorTypeRGB, color ); PEXText2D( dpy, renderer, PEXOCRender, &name_position, strlen(country), country ); } static void echo( path, echo_flag ) PEXPickPath *path; int echo_flag; { int i; PEXRendererAttributes rattrs; PEXPickElementRef *prim; PEXElementRef accum_path[3]; PEXColor *color; /* Set the renderer's clear-image attribute to False, and its */ /* echo mode to echo or un-echo. */ rattrs.clear_image = False; rattrs.echo_mode = echo_flag; PEXChangeRenderer( dpy, renderer, PEXRAClearImage | PEXRAEchoMode, &rattrs ); /* Accumulate state to the picked primitive. */ for ( i = 0; i < path->count; i++ ) { accum_path[i].structure = path->elements[i].sid; accum_path[i].offset = path->elements[i].offset; } PEXBeginRendering( dpy, window, renderer ); PEXAccumulateState( dpy, renderer, path->count, accum_path ); /* Render the picked country. */ prim = &path->elements[path->count-1]; PEXRenderElements( dpy, renderer, prim->sid, PEXBeginning, prim->offset, PEXBeginning, prim->offset ); /* Reset the renderer's echo mode attribute. */ rattrs.echo_mode = PEXNoEcho; PEXChangeRenderer( dpy, renderer, PEXRAEchoMode, &rattrs ); /* Show the country's name, which is stored in the pick id. */ color = echo_flag == PEXEcho ? &name_color : &background_color; show_name( (char*)prim->pick_id, color ); PEXEndRendering( dpy, renderer, True ); XFlush( dpy ); /* Reset the renderer's clear-image attribute. */ rattrs.clear_image = True; PEXChangeRenderer( dpy, renderer, PEXRAClearImage, &rattrs ); } static void pick( event ) XEvent *event; { int method, aperture_type, status, better; PEXPickRecord aperture; PEXPickPath *path; XWindowAttributes wattrs; method = PEXPickLast; /* Determine the aperture by converting the pick point to DC. */ aperture_type = PEXPickDeviceDCHitBox; XGetWindowAttributes( dpy, window, &wattrs ); aperture.box.position.x = event->xbutton.x; aperture.box.position.y = wattrs.height - event->xbutton.y; aperture.box.distance = 2; /* 2-pixel aperture radius */ /* Resolve the pick. */ path = PEXPickOne( dpy, window, renderer, w_europe, method, aperture_type, &aperture, &status, &better ); /* Turn off the old echo, if any. */ if ( last_pick ) { echo( last_pick, PEXUnEcho ); PEXFreePickPaths( 1, last_pick ); last_pick = (PEXPickPath *)NULL; } /* Echo the newly picked country. */ if ( status == PEXPick ) { echo( path, PEXEcho ); last_pick = path; } } static void create_model() { PEXColor color; PEXName names[2]; int i; /* Set the normal and echo colors. */ SET_COLOR( 1, 0, 0, normal_color ); /* red */ SET_COLOR( 1, 1, 1, echo_color ); /* white */ SET_COLOR( 1, 1, 0, name_color ); /* yellow */ /* Create the structures for the individual countries. */ for ( i = 0; i < NUM_COUNTRIES; i++ ) { structs[i] = PEXCreateStructure( dpy ); /* Add the country and group name to the name set. */ names[0] = (PEXName) countries[i].name; names[1] = (PEXName) countries[i].group; PEXAddToNameSet( dpy, structs[i], PEXOCStore, 2, names ); /* Set the country's pick id to its name string. */ PEXSetPickID( dpy, structs[i], PEXOCStore, (unsigned long) countries[i].string ); /* Create the primitive representing the country. */ PEXFillAreaSet2D( dpy, structs[i], PEXOCStore, PEXShapeUnknown, False, PEXContourUnknown, countries[i].num_lists, countries[i].lists ); } /* Create the top-level structure. */ w_europe = PEXCreateStructure( dpy ); PEXSetViewIndex( dpy, w_europe, PEXOCStore, 1 ); /* Set the edge attributes. */ PEXSetSurfaceEdgeFlag( dpy, w_europe, PEXOCStore, PEXOn ); SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetSurfaceEdgeColor( dpy, w_europe, PEXOCStore, PEXColorTypeRGB, &color ); /* Set the interior attributes. */ PEXSetInteriorStyle( dpy, w_europe, PEXOCStore, PEXInteriorStyleSolid ); PEXSetSurfaceColor( dpy, w_europe, PEXOCStore, PEXColorTypeRGB, &normal_color ); /* Put all countries in the WESTERN_EUROPE Group. */ names[0] = (PEXName) WESTERN_EUROPE; PEXAddToNameSet( dpy, w_europe, PEXOCStore, 1, names ); /* Invoke all the countries. */ for ( i = 0; i < NUM_COUNTRIES; i++ ) PEXExecuteStructure( dpy, w_europe, PEXOCStore, structs[i] ); } static void redraw() { /* Refresh the picture. */ PEXRenderNetwork( dpy, window, renderer, w_europe ); /* Redraw any echo. */ if ( last_pick ) echo( last_pick, PEXEcho ); XFlush( dpy ); } static void set_pick_filter( inclusion, exclusion ) PEXNameSet inclusion; PEXNameSet exclusion; { unsigned long num_names = 1; PEXName incl_list[1]; /* Add the top-level name to the pick filter's inclusion list. */ /* Leave the exclusion list empty. */ incl_list[0] = WESTERN_EUROPE; PEXChangeNameSet( dpy, inclusion, PEXNSAdd, num_names, incl_list ); } static void set_view( view_table ) PEXLookupTable view_table; { PEXViewEntry view; PEXCoord2D vwindow[2]; double view_plane, front_plane, back_plane; PEXCoord prp; PEXNPCSubVolume viewport; int error; /* The view orientation parameters. */ static PEXCoord view_ref_pt = {0,0,0}; static PEXVector view_plane_normal = {0,0,1}; static PEXVector view_up_vec = {0,1,0}; /* Compute the view orientation transform. */ (void)PEXViewOrientationMatrix( &view_ref_pt, &view_plane_normal, &view_up_vec, view.orientation ); /* The view mapping parameters. */ prp.x = 0.5; prp.y = 0.5; prp.z = 1; vwindow[0].x = -0.1; vwindow[1].x = 1.7; vwindow[0].y = -0.1; vwindow[1].y = 1.7; front_plane = 1; view_plane = 0; back_plane = 0; viewport.min.x = 0; viewport.max.x = 1; viewport.min.y = 0; viewport.max.y = 1; viewport.min.z = 0; viewport.max.z = 1; /* Compute the view mapping transform. */ (void)PEXViewMappingMatrix( vwindow, &viewport, False, &prp, view_plane, back_plane, front_plane, view.mapping ); /* The view clipping parameters. */ view.clip_flags = PEXClippingAll; view.clip_limits = viewport; /* Set view 1. */ PEXSetTableEntries( dpy, view_table, 1, 1, PEXLUTView, (PEXPointer) &view ); } #define WIN_GEOM "500x500+50+50" main( argc, argv ) int argc; char *argv[]; { XEvent event; XColor win_colr; PEXExtensionInfo *pexinfo; XVisualInfo vis_info; XStandardColormap cmap_info; PEXColorApproxEntry capx_info; PEXRendererAttributes rattrs; int done = 0; char *dpy_name; if ( !(dpy = ora_init_pex( argv, &pexinfo ) ) ) exit(1); dpy_name = XDisplayString( dpy ); /* the full name */ /* Picking is supported only in PEX version 5.1. */ if ( !VERSION_5_1( pexinfo ) ) { fprintf( stderr, "PEX Version 5.1 unavailable on %s.\n", dpy_name ); exit(1); } /* Determine the best visual to use. */ ora_find_best_visual( dpy, &vis_info ); /* Get a standard colormap for the visual. */ if ( !ora_get_standard_colormap( dpy, &vis_info, &cmap_info ) ) { fprintf ( stderr, "Cannot find a standard colormap\n" ); exit(1); } ora_set_stdcmap_approx( &vis_info, &cmap_info, &capx_info ); /* Create the window, specifying a gray background. */ win_colr.red = win_colr.green = win_colr.blue = 0; win_colr.flags = DoRed | DoGreen | DoBlue; window = ora_create_window( dpy, &vis_info, &cmap_info, WIN_GEOM, &win_colr ); /* Set up the PEX renderer. */ if ( !STRUCTURE_SPT( pexinfo ) ) { fprintf( stderr, "%s does not support renderers", dpy_name ); exit(1); } renderer = ora_setup_renderer( dpy, window, &capx_info, &rattrs ); /* Set the renderer's background and clear-image attributes. */ rattrs.clear_image = True; rattrs.background_color.type = PEXColorTypeRGB; SET_COLOR( 0.66, 0.66, 0.66, background_color ); rattrs.background_color.value = background_color; PEXChangeRenderer( dpy, renderer, PEXRAClearImage | PEXRABackgroundColor, &rattrs ); create_model(); set_view( rattrs.view_table ); set_pick_filter( rattrs.pick_incl, rattrs.pick_excl ); PEXSetEchoColor( dpy, renderer, PEXColorTypeRGB, &echo_color ); /* Read and respond to X events. */ XSelectInput( dpy, window, ExposureMask | ButtonPressMask ); while ( !done ) { XNextEvent( dpy, &event ); switch ( event.type ) { case Expose: while ( XCheckTypedWindowEvent( dpy, window, Expose, &event ) ) ; /* empty statement */ redraw(); break; case ButtonPress: switch ( event.xbutton.button ) { case Button1: pick( &event ); break; default: done = 1; break; } break; } } XCloseDisplay( dpy ); return 0; }