/* * item_move.c * Move items around in a panel using an interpose event handler * specific to the panel. Two panels are created -- the left panel * contains panel buttons that allow you to create certain types of * items that are put in the second panel. Use the MENU (right) * mouse button to move items around in the second panel. */ #include <stdio.h> #include <xview/xview.h> #include <xview/panel.h> /* We need handles to the base frame and a panel -- instead of * using global variables, we're going to attach the objects to * the objects which need to reference them. Attach using * XV_KEY_DATA -- here are the keys. */ #define PACKAGE_KEY 100 #define FRAME_KEY 101 #define PANEL_KEY 102 main(argc, argv) int argc; char *argv[]; { Frame frame; Panel panel; Xv_Window window; Panel_item create_text, item; Notify_value my_event_proc(); int create_item(); char buf[64]; xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL); sprintf(buf, "%s: Use MENU (Right) Button To Move Items", argv[0]); frame = (Frame)xv_create(XV_NULL, FRAME, FRAME_LABEL, buf, FRAME_SHOW_FOOTER, TRUE, NULL); /* * Create panel for known panel items. Layout panel vertically. */ panel = (Panel)xv_create(frame, PANEL, PANEL_LAYOUT, PANEL_VERTICAL, NULL); /* * Create text panel item, attach the frame as client data for * use by the notify procedure create_item(). Text items inherit * the layout of "label" and "value" from its parent panel. * override for the text item by setting PANEL_LAYOUT explicitly. */ create_text = (Panel_item)xv_create(panel, PANEL_TEXT, XV_X, 0, XV_Y, 20, PANEL_LABEL_STRING, "Create Button:", PANEL_NOTIFY_PROC, create_item, PANEL_LAYOUT, PANEL_HORIZONTAL, PANEL_VALUE_DISPLAY_LENGTH, 10, NULL); /* * Create panel button to determine which type of button to create -- * a button, message, or text item. See create_item(). */ item = (Panel_item)xv_create(panel, PANEL_CHOICE, XV_X, 0, XV_Y, 50, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LAYOUT, PANEL_HORIZONTAL, PANEL_LABEL_STRING, "Item type", PANEL_CHOICE_STRINGS, "Button", "Message", "Text", NULL, NULL); window_fit(panel); /* Create a new panel to be used for panel creation. The panel * from above is no longer referenced. The panel created here * is the panel used throughout the rest of this program. To * add confusion, "panel" is used as the handle of this panel, too. * The panel referenced in WIN_RIGHT_OF and XV_HEIGHT is the old * one since the new one hasn't been created yet. */ panel = (Panel)xv_create(frame, PANEL, WIN_RIGHT_OF, canvas_paint_window(panel), XV_WIDTH, 300, XV_HEIGHT, xv_get(panel, XV_HEIGHT), WIN_BORDER, TRUE, XV_KEY_DATA, PANEL_KEY, panel, NULL); /* Install event handling routine for the panel. This must be done * by an interpose function to make sure that the ACTION_MENU * event is not consumed by the first panel before it has a chance * to get to the second panel's event proc: my_event_proc. */ notify_interpose_event_func(panel, my_event_proc, NOTIFY_SAFE); /* attach various items to the text item for text_select() */ xv_set(create_text, XV_KEY_DATA, FRAME_KEY, frame, XV_KEY_DATA, PACKAGE_KEY, item, XV_KEY_DATA, PANEL_KEY, panel, NULL); window_fit(frame); xv_main_loop(frame); } /* * Process events for panel's subwindow. This routine gets -all- * events that occur in the panel subwindow but passes them on to * the normal event dispatcher when the interposed function has been * completed. The notify function, my_event_proc, is only * interested in MENU button events that happen on top of panel items. * When the user clicks and _drags_ the MENU button on a panel item, * the item is moved to where the mouse moves to. */ Notify_value my_event_proc(panel, event, arg, type) Panel panel; Event *event; Notify_arg arg; Notify_event_type type; { static Panel_item item; static int x_offset, y_offset; Frame frame = (Frame)xv_get(panel, XV_OWNER); Rect *rect, *item_rect; char buf[64]; /* * If the mouse is dragging an item, reset its new location. */ if (event_action(event) == LOC_DRAG && item) { Panel_item pi; Rect r; /* * Get the rect of item, then *copy* it -- never change data * returned by xv_get(). Modify the copied rect reflecting * new X,Y position of panel item and check to see if it * intersects with any existing panel items. */ rect = (Rect *)xv_get(item, XV_RECT); rect_construct(&r, /* see <xview/rect.h> for macros */ rect->r_left, rect->r_top, rect->r_width, rect->r_height); r.r_left = event->ie_locx - x_offset; r.r_top = event->ie_locy - y_offset; PANEL_EACH_ITEM(panel, pi) if (pi == item) continue; /* don't let panel items overlap */ item_rect = (Rect *)xv_get(pi, XV_RECT); if (rect_intersectsrect(item_rect, &r)) return; PANEL_END_EACH /* no overlap -- move panel item. */ xv_set(item, PANEL_ITEM_X, r.r_left, PANEL_ITEM_Y, r.r_top, NULL); } /* If it's not the MENU button, we're not interested, * so allow the event to be passed on to the notifier * for normal event handling. */ if (event_action(event) != ACTION_MENU) { notify_next_event_func(panel, (Notify_event) event, arg, type); return; } /* * next two cases is MENU button just-down or just-released */ if (event_is_down(event)) { /* Right (MENU) button down on an item -- determine panel item */ if ( (xv_get((panel), PANEL_FIRST_ITEM) ) == NULL ) { sprintf(buf, "No panel items are currently in the panel."); xv_set(frame, FRAME_RIGHT_FOOTER, buf, NULL); } PANEL_EACH_ITEM(panel, item) rect = (Rect *)xv_get(item, XV_RECT); if (rect_includespoint(rect, event->ie_locx, event->ie_locy)) { x_offset = event->ie_locx - rect->r_left; y_offset = event->ie_locy - rect->r_top; sprintf(buf, "Panel item found."); xv_set(frame, FRAME_RIGHT_FOOTER, buf, NULL); break; } else { sprintf(buf, "The cursor is not over any panel item."); xv_set(frame, FRAME_RIGHT_FOOTER, buf, NULL); } PANEL_END_EACH if (item) sprintf(buf, "Moving item: '%s'", (char *)xv_get(item, PANEL_LABEL_STRING)); else buf[0] = 0; } else if (item) { char *name = (char *)xv_get(item, PANEL_LABEL_STRING); /* test if item is inside panel by comparing XV_RECTs */ rect = (Rect *)xv_get(panel, XV_RECT); if (!rect_includespoint(rect, event->ie_locx + rect->r_left, event->ie_locy + rect->r_top)) { /* item is outside the panel -- remove item */ xv_destroy(item); sprintf(buf, "Removed '%s' from panel", name); } else sprintf(buf, "'%s' moved to %d %d", name, (int)xv_get(item, XV_X), (int)xv_get(item, XV_Y)); /* set "item" to null so that new drag * events don't attempt to move old item. */ item = NULL; } xv_set(frame, FRAME_LEFT_FOOTER, buf, NULL); } /* * Callback routine for all panel buttons. * If the panel item is the text item, determine the name of the new * panel button the user wishes to create. Loop through all the * existing panel items looking for one with the same label. If so, * return PANEL_NONE and set the frame's footer with an error message. * Otherwise, create a new panel item with the label, reset the text * item value and return PANEL_NEXT. */ int create_item(item, event) Panel_item item; Event *event; { Xv_pkg *pkg; Panel panel = (Panel)xv_get(item, XV_KEY_DATA, PANEL_KEY); Frame frame = (Frame)xv_get(item, XV_KEY_DATA, FRAME_KEY); Panel_item pi, pkg_item; char buf[64]; int selected(); pkg_item = (Panel_item)xv_get(item, XV_KEY_DATA, PACKAGE_KEY); (void) strncpy(buf, (char *)xv_get(item, PANEL_VALUE), sizeof buf); if (!buf[0]) return PANEL_NONE; switch((int)xv_get(pkg_item, PANEL_VALUE)) { case 1: pkg = PANEL_MESSAGE; break; case 2: pkg = PANEL_TEXT; break; default: pkg = PANEL_BUTTON; } /* loop thru all panel items and check for item with same name */ PANEL_EACH_ITEM(panel, pi) if (!strcmp(buf, (char *)xv_get(pi, PANEL_LABEL_STRING))) { xv_set(frame, FRAME_LEFT_FOOTER, "Label Taken", NULL); return PANEL_NONE; } PANEL_END_EACH (void) xv_create(panel, pkg, PANEL_LABEL_STRING, buf, PANEL_NOTIFY_PROC, selected, XV_KEY_DATA, FRAME_KEY, frame, /* only for text items, but doesn't affect other items */ PANEL_VALUE_DISPLAY_LENGTH, 10, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL); xv_set(item, PANEL_VALUE, "", NULL); return PANEL_NEXT; } /* * For panel buttons. return XV_OK or XV_ERROR if the item was * selected using the left mouse button or not. */ int selected(item, event) Panel_item item; Event *event; { Frame frame = (Frame)xv_get(item, XV_KEY_DATA, FRAME_KEY); char buf[64]; if (event_action(event) == ACTION_SELECT) { sprintf(buf, "'%s' selected", xv_get(item, PANEL_LABEL_STRING)); xv_set(frame, FRAME_RIGHT_FOOTER, buf, NULL); return XV_OK; } return XV_ERROR; }