/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* AttachPanel.cpp -- panel for displaying icon view of attached files. Created: Alastair Gourlay(SGI) c/o Dora Hsu, 26 Nov 1996 */ // Classes in this file: // XFE_AttachPanel // XFE_AttachPanelItem // #include "AttachPanel.h" #include #include #include #include "mozilla.h" #include "xfe.h" #include "net.h" #include "icons.h" #include "icondata.h" #include "DragDrop.h" #ifdef DEBUG_sgidev #define XDEBUG(x) x #else #define XDEBUG(x) #endif // // XFE_AttachPanel // // static initialization const int XFE_AttachPanel::_allocIncrement=50; // item list management const int XFE_AttachPanel::_marginWidth=5; // panel margin const int XFE_AttachPanel::_marginHeight=5; // panel margin const int XFE_AttachPanel::_horizSpacing=10; // panel spacing #define ATTACH_ICON_NAME "attachItemImage" #define ATTACH_LABEL_NAME "attachItemLabel" // callback stubs void XFE_AttachPanel::ExposeCb(Widget,XtPointer cd,XtPointer) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (ad && ad->_firstExpose) { ad->_firstExpose=FALSE; ad->realize(); } } void XFE_AttachPanel::InputCb(Widget,XtPointer cd,XtPointer cb) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (ad && cb) { XmDrawingAreaCallbackStruct *dcb=(XmDrawingAreaCallbackStruct*)cb; ad->inputCb(dcb->event); } } void XFE_AttachPanel::ScrollTraversalCb(Widget,XtPointer cd,XtPointer cb) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; XmTraverseObscuredCallbackStruct *scb=(XmTraverseObscuredCallbackStruct*)cb; if (ad && ad->_traversalProcId==0 && scb && scb->reason==XmCR_OBSCURED_TRAVERSAL) { // delay scroll until after completion of armCb(). Of course :) // if only Motif passed a valid cb->event, all this would be unecessary ad->_traversalWidget=scb->traversal_destination; ad->_traversalProcId=XtAppAddTimeOut(XtWidgetToApplicationContext(ad->_top), 0,ScrollTraversalProc,cd); } } void XFE_AttachPanel::ScrollTraversalProc(XtPointer cd, XtIntervalId *id) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (ad) { if (ad->_traversalProcId==*id) ad->_traversalProcId=0; if (ad->_traversalWidget) { ad->scrollTraversalProc(ad->_traversalWidget); ad->_traversalWidget=NULL; } } } void XFE_AttachPanel::ScrollResizeCb(Widget,XtPointer cd,XtPointer) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (ad && ad->_resizeProcId==0) { // delay resize until after completion of resize callback. Of course :) ad->_resizeProcId=XtAppAddTimeOut(XtWidgetToApplicationContext(ad->_top), 0,ScrollResizeProc,cd); } } void XFE_AttachPanel::ScrollResizeProc(XtPointer cd, XtIntervalId *id) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (ad) { if (ad->_resizeProcId==*id) ad->_resizeProcId=0; ad->scrollResizeProc(); } } void XFE_AttachPanel::PopupProc(Widget,XtPointer cd,XEvent *event,Boolean*) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; if (!ad->_popupMenu) return; if (event->xany.type!=ButtonPress) return; if (((XButtonEvent *)event)->button != Button3) return; if (((XButtonEvent *)event)->time <= ad->_popupLastEventTime) return; XmMenuPosition(ad->_popupMenu,(XButtonEvent*)event); XtManageChild (ad->_popupMenu); } /* By default, cancelling a popup menu with Button 3 will cause the * popup to be reposted at the location of the cancelling click. * * To switch off this behavior, remember when the menu was popped down. * In PopupHandler, don't repost the menu if the posting click just * cancelled a popup menu. */ void XFE_AttachPanel::PopdownCb(Widget w,XtPointer cd,XtPointer) { XFE_AttachPanel *ad=(XFE_AttachPanel*)cd; ad->_popupLastEventTime = XtLastTimestampProcessed (XtDisplay(w)); } // constructor XFE_AttachPanel::XFE_AttachPanel(MWContext* context) : XFE_Component() { _context=context; _inDestructor=FALSE; _parent=NULL; _top=NULL; _topClip=NULL; _topScrollBar=NULL; _pane=NULL; _resizeProcId=0; _traversalProcId=0; _firstExpose=TRUE; _popupParent=NULL; _popupMenu=NULL; _popupLastEventTime=0; _armedWidget=NULL; _traversalWidget=NULL; _multiClickEnabled=FALSE; _iconTranslations=NULL; _prefHeight=0; _items=NULL; _numItems=0; _allocItems=0; _currentSelection=NULL; } XFE_AttachPanel::~XFE_AttachPanel() { _inDestructor=TRUE; if (_resizeProcId!=0) XtRemoveTimeOut(_resizeProcId); if (_traversalProcId!=0) XtRemoveTimeOut(_traversalProcId); // XFE_Component will destroy the widget tree } void XFE_AttachPanel::createWidgets(Widget parent) { _parent=parent; Arg args[10]; // toplevel scrolled window XtSetArg(args[0],XmNscrollingPolicy, XmAUTOMATIC); _top=XmCreateScrolledWindow(_parent,"attach",args,1); XtAddCallback(_top,XmNtraverseObscuredCallback,ScrollTraversalCb,(XtPointer)this); //XtManageChild(_top); Widget vsb; XtVaGetValues(_top,XmNverticalScrollBar,&vsb,NULL); if (vsb) XtVaSetValues(vsb,XmNtraversalOn,False,NULL); // attachment pane _pane=XmCreateDrawingArea(_top,"pane",NULL,0); XtVaSetValues(_pane, XmNmarginWidth,0, XmNmarginHeight,0, NULL); // nyi - best way to avoid multiple redraw? XtAddCallback(_pane,XmNexposeCallback,ExposeCb,(XtPointer)this); XtAddCallback(_pane,XmNinputCallback,InputCb,(XtPointer)this); XtManageChild(_pane); // only want vertical scrolling - make form track width of outer window Widget hsb; XtVaGetValues(_top, XmNclipWindow,&_topClip, XmNverticalScrollBar,&_topScrollBar, XmNhorizontalScrollBar,&hsb, NULL); if (XmIsDrawingArea(_topClip)) { // it better be! XtAddCallback(_topClip,XmNresizeCallback,ScrollResizeCb,(XtPointer)this); XtAddCallback(_topClip,XmNinputCallback,InputCb,(XtPointer)this); } // hide horizontal scrollbar - prevent it flickering on during resize if (hsb) { XtVaSetValues(hsb, XmNheight,1, XmNmappedWhenManaged,FALSE, NULL); } // make scroller background match child Pixel bg; XtVaGetValues(_pane,XmNbackground,&bg,NULL); XtVaSetValues(_topClip,XmNbackground,bg,NULL); _popupParent=_top; setBaseWidget(_top); } void XFE_AttachPanel::initializePopupMenu() { if (!_popupMenu || !_popupParent) return; XtAddEventHandler (_popupParent,ButtonPressMask,False,PopupProc,this); //XtAddCallback(XtParent(_popupMenu),XmNpopdownCallback,PopdownCb,this); updateSelectionUI(); } // // item list management // void XFE_AttachPanel::addItem(const char *itemData,const char *itemLabel,const char *itemType,int pos) { if (!itemData || strlen(itemData)==0) return; XFE_AttachPanelItem *ai=new XFE_AttachPanelItem(this,itemData,itemLabel,itemType); addItem(ai,pos); } void XFE_AttachPanel::addItem(XFE_AttachPanelItem *newItem,int pos) { int i; if (pos==-1) pos=_numItems; if (pos<0 || pos>_numItems) return; // save pointer to passed item. // adopt it, and delete in removeItem(), destructor if (_numItems >= _allocItems) { _allocItems+=_allocIncrement; XFE_AttachPanelItem **newList=new XFE_AttachPanelItem*[_allocItems]; for (i=0;i<_numItems;i++) { newList[i]=_items[i]; _items[i]=NULL; } if (_items) delete _items; _items=newList; } for (i=_numItems;i>pos;i--) { _items[i]=_items[i-1]; } _items[pos]=newItem; _numItems++; } int XFE_AttachPanel::findItem(XFE_AttachPanelItem *ai) { if (ai==NULL) return -1; for (int i=0;i<_numItems;i++) { if (_items[i]==ai) { return i; } } return -1; } void XFE_AttachPanel::removeItem(XFE_AttachPanelItem *item) { int pos=findItem(item); if (pos>=0) removeItem(pos); } void XFE_AttachPanel::removeItem(int r) { // Warning: never decreases list alloc'd size // if XFE_AttachPanel object is long-lived, then it should. // use removeAllItems() method to force a cleanup. if (r<0 || r>=_numItems) return; if (_items[r]) { // if focus is on last item, move it to last-but-one item // to ensure that attach panel keeps focus after delete. if (r==_numItems-1 && r>0) { Widget focusWidget=XmGetFocusWidget(getBaseWidget()); Widget lastButOne=NULL; if (_items[r-1]) lastButOne=_items[r-1]->image(); if (focusWidget && focusWidget==_items[r]->image() && lastButOne!=NULL) { XmProcessTraversal(lastButOne,XmTRAVERSE_CURRENT); } } delete _items[r]; } for (int i=r; i<_numItems-1;i++) _items[i]=_items[i+1]; _items[_numItems-1]=NULL; _numItems--; } void XFE_AttachPanel::removeAllItems() { if (_items) { for (int i=0; i<_numItems;i++) { if (_items[i]) { if (_inDestructor) _items[i]->inParentDestructor(); delete _items[i]; _items[i]=NULL; } } delete _items; _items=NULL; _numItems=0; _allocItems=0; } } XFE_AttachPanelItem **XFE_AttachPanel::items() { return _items; } int XFE_AttachPanel::numItems() { return _numItems; } void XFE_AttachPanel::selectItem(XFE_AttachPanelItem* item) { if (!item || item->beingDestroyed()) return; if (_currentSelection && item!=_currentSelection) _currentSelection->select(FALSE); item->select(TRUE); _currentSelection=item; updateSelectionUI(); } void XFE_AttachPanel::deselectItem(XFE_AttachPanelItem* item) { if (!item || item!=_currentSelection) return; if (!item->beingDestroyed()) item->select(FALSE); _currentSelection=NULL; updateSelectionUI(); } // // display management // void XFE_AttachPanel::updateDisplay() { layout(); } void XFE_AttachPanel::traverseItem(int pos) { if (pos<0 || pos >=_numItems) return; _items[pos]->traverse(); } void XFE_AttachPanel::scrollToItem(int pos) { if (pos<0 || pos >=_numItems) return; _items[pos]->scrollVisible(); } int XFE_AttachPanel::getPreferredHeight() { if (_prefHeight>0) return _prefHeight; else return 20; } //#define DEBUG_LAYOUT void XFE_AttachPanel::layout() { #if 0 if (_firstExpose) return; #endif if (_items==NULL || _numItems==0) return; // examine items int i; int maxWidth=0; int maxHeight=0; for (i=0;i<_numItems;i++) { if (_items[i] && !_items[i]->beingDestroyed()) { _items[i]->calculatePrefGeometry(); if (_items[i]->prefWidth()>maxWidth) maxWidth=_items[i]->prefWidth(); if (_items[i]->prefHeight()>maxHeight) maxHeight=_items[i]->prefHeight(); } } if (maxWidth==0 || maxHeight==0) return; // calculate basic parameters Position wd; XtVaGetValues(_topClip,XmNwidth,&wd,NULL); unsigned int availWidth=(unsigned int)(wd>2*_marginWidth ? (wd-2*_marginWidth) : 1); unsigned int vSpacing=(_items[0] ? _items[0]->labelHeight()/2 : 10); //nyi - need a good way to calc cell width - deal with large, rare cases unsigned int cellWidth=maxWidth+_horizSpacing; if (cellWidth<1) cellWidth=1; unsigned int cellHeight=maxHeight; int cellsPerRow=availWidth/cellWidth; if (cellsPerRow<1) cellsPerRow=1; // lay out row by row. // give each item enough cells to prevent overlap #ifdef DEBUG_LAYOUT printf("\nlayout()\n\n"); printf(" availWidth=%d\n",availWidth); printf(" cellWidth=%d\n",cellWidth); printf(" cellHeight=%d\n",cellHeight); printf(" cellsPerRow=%d\n",cellsPerRow); printf("\n"); #endif int itemPos=0; int cellNum=0; int row=0; // if an icon has focus, restore it when we remap the pane Widget focusWidget=XmGetFocusWidget(_top); if (focusWidget && XtParent(focusWidget)!=_pane) focusWidget=NULL; unmapPane(); // calculate ideal height for this layout + border Dimension st; XtVaGetValues(_top,XmNshadowThickness,&st,NULL); _prefHeight=2*st + 2*_marginHeight + cellHeight + vSpacing; // do layout while (itemPos<_numItems) { #ifdef DEBUG_LAYOUT printf("[%d]\n",itemPos); #endif if (_items[itemPos] && !_items[itemPos]->beingDestroyed()) { int numCells=_items[itemPos]->prefWidth()/cellWidth + 1; if (numCells>cellsPerRow) numCells=cellsPerRow; #ifdef DEBUG_LAYOUT printf(" numCells=%d\n",numCells); #endif // see if it makes sense to move to a new row if (numCells>cellsPerRow-cellNum && cellNum!=0) { row++; _prefHeight+=cellHeight+vSpacing; cellNum=0; } #ifdef DEBUG_LAYOUT printf(" row:%d-%d (%d,%d) %dx%d\n", row,cellNum, cellNum*cellWidth,row*cellHeight, numCells*cellWidth,cellHeight); #endif //do layout _items[itemPos]->layout(_marginWidth+cellNum*cellWidth, _marginHeight+row*(cellHeight+vSpacing), numCells*cellWidth, cellHeight); cellNum+=numCells; } itemPos++; } mapPane(); // restore focus if we had it before the unmapPane() if (focusWidget) XmProcessTraversal(focusWidget,XmTRAVERSE_CURRENT); } void XFE_AttachPanel::mapPane() { if (_pane) XtSetMappedWhenManaged(_pane,TRUE); if (_topScrollBar) XtSetMappedWhenManaged(_topScrollBar,TRUE); } void XFE_AttachPanel::unmapPane() { if (_pane) XtSetMappedWhenManaged(_pane,FALSE); if (_topScrollBar) XtSetMappedWhenManaged(_topScrollBar,FALSE); } int XFE_AttachPanel::isAttachPanelWidget(Widget w) { if (w==NULL) return FALSE; if (w==_top || w==_topClip || w==_topScrollBar || w==_pane || XtParent(w)==_pane) return TRUE; return FALSE; } // // callback methods // void XFE_AttachPanel::realize() { // realize processing for existing items if (_items) { for (int i=0;i<_numItems;i++) _items[i]->realize(); layout(); } } void XFE_AttachPanel::doubleClickCb(int) { // no default double-click action - it's for the derived classes. } void XFE_AttachPanel::inputCb(XEvent *event) { // button up on panel background cancels selection if (_currentSelection!=NULL && event && event->xany.type==ButtonRelease && event->xbutton.button==1) { deselectItem(_currentSelection); } } void XFE_AttachPanel::scrollTraversalProc(Widget dest) { // let disarmCb handle scrolling for button click if (!dest || dest==_armedWidget) return; char *destName=XtName(dest); if (!destName || strcmp(destName,ATTACH_ICON_NAME)!=0) return; // if this is the icon of XFE_AttachItem, scroll it into view. XtPointer userData; XtVaGetValues(dest,XmNuserData,&userData,NULL); if (!userData) return; XFE_AttachPanelItem *ai=(XFE_AttachPanelItem*)userData; ai->scrollVisible(); } void XFE_AttachPanelItem::scrollVisible() { // scroll to icon, with enough margin to show label XmScrollVisible(_attachPanel->getBaseWidget(),_image,0,labelHeight()+2); XmScrollVisible(_attachPanel->getBaseWidget(),_label,0,0); } void XFE_AttachPanel::scrollResizeProc() { const int rspace=10; // must be >= 2, or window will oscillate Dimension width; if (!_topClip || !_pane) return; XtVaGetValues(_topClip,XmNwidth,&width,NULL); if (width_attachPanel->multiClickEnabled()) { switch(pcb->click_count) { case 1: ad->activateCb(); break; case 2: ad->doubleClickCb(); break; default: break; } } else { ad->activateCb(); } } } void XFE_AttachPanelItem::ArmCb(Widget w,XtPointer cd,XtPointer) { XFE_AttachPanelItem *ad=(XFE_AttachPanelItem*)cd; if (ad) ad->armCb(w); } void XFE_AttachPanelItem::DisarmCb(Widget,XtPointer cd,XtPointer) { XFE_AttachPanelItem *ad=(XFE_AttachPanelItem*)cd; if (ad) ad->disarmCb(); } // constructor XFE_AttachPanelItem::XFE_AttachPanelItem(XFE_AttachPanel *attach, const char *data, const char *dataLabel, const char *dataType) { _attachPanel=attach; _inParentDestructor=FALSE; _beingDestroyed=FALSE; if (data) _data=strdup(data); else _data=NULL; if (dataLabel) _dataLabel=strdup(dataLabel); else _dataLabel=(_data ? strdup(_data) : (char*)NULL); if (dataType) { // app specified a mime type for this data _dataType=strdup(dataType); } else { // try to determine type of attachment _dataType=strdup(XFE_DragBase::guessUrlMimeType(data)); } _parent=_attachPanel->pane(); _image=NULL; _label=NULL; _prefWidth=1; _prefHeight=1; // use link cursor over attach icons to indicate that they are active if (_cursor==None) _cursor=CONTEXT_DATA(_attachPanel->context())->link_cursor; // create widgets Arg args[10]; Pixel bg; XtVaGetValues(_parent,XmNbackground,&bg,NULL); // image XtSetArg(args[0],XmNbackground,bg); _image=XmCreatePushButton(_parent,ATTACH_ICON_NAME,args,1); XtVaSetValues(_image, XmNalignment,XmALIGNMENT_CENTER, XmNshadowThickness,0, XmNmarginWidth,0, XmNmarginHeight,0, XmNlabelType,XmPIXMAP, XmNlabelPixmap,iconPixmap(), XmNarmColor,bg, XmNmultiClick,XmMULTICLICK_KEEP, XmNuserData,(XtPointer)this, // scrollTraversalProc needs to get to item class NULL); XtAddCallback(_image,XmNactivateCallback,ActivateCb,(XtPointer)this); XtAddCallback(_image,XmNarmCallback,ArmCb,(XtPointer)this); XtAddCallback(_image,XmNdisarmCallback,DisarmCb,(XtPointer)this); if (_attachPanel->iconTranslations()) XtOverrideTranslations(_image,_attachPanel->iconTranslations()); // label XtSetArg(args[0],XmNbackground,bg); _label=XmCreateLabel(_parent,ATTACH_LABEL_NAME,args,1); XmString xms=XmStringCreateLocalized(_dataLabel ? _dataLabel : ""); XtVaSetValues(_label, XmNalignment,XmALIGNMENT_CENTER, XmNshadowThickness,0, //XmNmarginWidth,0, //XmNmarginHeight,0, XmNlabelString,xms, XmNuserData,FALSE, // selection marker for AttachPanelItem::select() NULL); XmStringFree(xms); show(); calculatePrefGeometry(); if (XtWindow(_image)) { XDefineCursor(XtDisplay(_image),XtWindow(_image),_cursor); } } // destructor XFE_AttachPanelItem::~XFE_AttachPanelItem() { _beingDestroyed=TRUE; if (this==_attachPanel->currentSelection()) _attachPanel->deselectItem(this); if (_data) free((void*)_data); if (_dataLabel) free((void*)_dataLabel); if (_dataType) free((void*)_dataType); if (_image) { XtUnmanageChild(_image); if (!_inParentDestructor) XtDestroyWidget(_image); } if (_label) { XtUnmanageChild(_label); if (!_inParentDestructor) XtDestroyWidget(_label); } } void XFE_AttachPanelItem::inParentDestructor() { _inParentDestructor=TRUE; } void XFE_AttachPanelItem::realize() { if (_image) { XtVaSetValues(_image,XmNlabelPixmap,iconPixmap(),NULL); calculatePrefGeometry(); XDefineCursor(XtDisplay(_image),XtWindow(_image),_cursor); } if (this==_attachPanel->currentSelection()) select(TRUE); else select(FALSE); } // this method should only be called when creating item. Pixmap XFE_AttachPanelItem::iconPixmap() { if (!XtIsRealized(_parent)) return XmUNSPECIFIED_PIXMAP; XDEBUG(printf("iconPixmap(%s)\n",_dataType?_dataType:"NULL")); // return pixmap matching item's mime type // create Pixmaps on first request MWContext *context=_attachPanel->context(); Pixel bg; XtVaGetValues(_parent,XmNbackground,&bg,NULL); if (!_dataType || strcmp(_dataType,UNKNOWN_CONTENT_TYPE)==0) { if (_unknownPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GUnknown.width, GUnknown.height, GUnknown.mono_bits, GUnknown.color_bits, GUnknown.mask_bits, FALSE); _unknownPixmap=icon.pixmap; } return _unknownPixmap; } // internal type name - used for attached document URL's if (strncmp(_dataType,"_url",5)==0){ if (_urlPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, LocationProxy.width, LocationProxy.height, LocationProxy.mono_bits, LocationProxy.color_bits, LocationProxy.mask_bits, FALSE); _urlPixmap=icon.pixmap; } return _urlPixmap; } if (strncmp(_dataType,"audio",5)==0){ if (_audioPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GAudio.width, GAudio.height, GAudio.mono_bits, GAudio.color_bits, GAudio.mask_bits, FALSE); _audioPixmap=icon.pixmap; } return _audioPixmap; } if (strncmp(_dataType,"application",11)==0) { if (_binaryPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GBinary.width, GBinary.height, GBinary.mono_bits, GBinary.color_bits, GBinary.mask_bits, FALSE); _binaryPixmap=icon.pixmap; } return _binaryPixmap; } if (strncmp(_dataType,"image",5)==0) { if (_imagePixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GImage.width, GImage.height, GImage.mono_bits, GImage.color_bits, GImage.mask_bits, FALSE); _imagePixmap=icon.pixmap; } return _imagePixmap; } if (strncmp(_dataType,"message",7)==0) { if (_messagePixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, MNTB_Forward.width, MNTB_Forward.height, MNTB_Forward.mono_bits, MNTB_Forward.color_bits, MNTB_Forward.mask_bits, FALSE); _messagePixmap=icon.pixmap; } return _messagePixmap; } if (strncmp(_dataType,"video",5)==0) { if (_moviePixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GMovie.width, GMovie.height, GMovie.mono_bits, GMovie.color_bits, GMovie.mask_bits, FALSE); _moviePixmap=icon.pixmap; } return _moviePixmap; } if (strcmp(_dataType,"text/x-vcard")==0) { if (_vcardPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, MNAB_NewPerson.width, MNAB_NewPerson.height, MNAB_NewPerson.mono_bits, MNAB_NewPerson.color_bits, MNAB_NewPerson.mask_bits, FALSE); _vcardPixmap=icon.pixmap; } return _vcardPixmap; } if (strncmp(_dataType,"text",4)==0) { if (_textPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GText.width, GText.height, GText.mono_bits, GText.color_bits, GText.mask_bits, FALSE); _textPixmap=icon.pixmap; } return _textPixmap; } // fallback to generic document pixmap if (_unknownPixmap==XmUNSPECIFIED_PIXMAP) { fe_icon icon={ 0 }; fe_MakeIcon(context,bg, &icon, NULL, GUnknown.width, GUnknown.height, GUnknown.mono_bits, GUnknown.color_bits, GUnknown.mask_bits, FALSE); _unknownPixmap=icon.pixmap; } return _unknownPixmap; } const char *XFE_AttachPanelItem::data() { return _data; } const char *XFE_AttachPanelItem::dataLabel() { return _dataLabel; } const char *XFE_AttachPanelItem::dataType() { return _dataType; } void XFE_AttachPanelItem::select(int selected) { // Hack to do selection highlight. // May need to do real X drawing in AttachPanel[Item]::exposeCb() if (_label) { Pixel fg; Pixel bg; XtPointer userData; XtVaGetValues(_label, XmNbackground,&bg, XmNforeground,&fg, XmNuserData,&userData, NULL); int labelHighlighted=(int)userData; if (selected && !labelHighlighted) { XtVaSetValues(_label, XmNbackground,fg, XmNforeground,bg, XmNuserData,1, NULL); } if (!selected && labelHighlighted) { XtVaSetValues(_label, XmNbackground,fg, XmNforeground,bg, XmNuserData,0, NULL); } } } void XFE_AttachPanelItem::calculatePrefGeometry() { Dimension iw,ih,lw,lh; XtVaGetValues(_image, XmNwidth,&iw, XmNheight,&ih, NULL); XtVaGetValues(_label, XmNwidth,&lw, XmNheight,&lh, NULL); _imageWidth=iw; _imageHeight=ih; _labelWidth=lw; _labelHeight=lh; // ? save image plus label geometry _prefWidth=(unsigned int)(iw>lw ? iw : lw); _prefHeight=(unsigned int)(ih+lh); } void XFE_AttachPanelItem::layout(int x, int y, unsigned int width, unsigned int height) { if (_label==NULL || _image==NULL || _prefWidth==0 || _prefHeight==0 || width==0 || height==0 ) return; int imageX; int imageY; int labelX; int labelY; imageX=x+(width-_imageWidth)/2; imageY=y+height-_labelHeight-_imageHeight; labelX=x+(width-_labelWidth)/2; labelY=y+height-_labelHeight; XtVaSetValues(_image, XmNx,imageX, XmNy,imageY, NULL); XtVaSetValues(_label, XmNx,labelX, XmNy,labelY, NULL); } void XFE_AttachPanelItem::show() { if (_image) XtManageChild(_image); if (_label) XtManageChild(_label); } void XFE_AttachPanelItem::hide() { if (_image) XtUnmanageChild(_image); if (_label) XtUnmanageChild(_label); } void XFE_AttachPanelItem::traverse() { if (_image) XmProcessTraversal(_image,XmTRAVERSE_CURRENT); } // // callback methods // void XFE_AttachPanelItem::activateCb() { if (this!=_attachPanel->currentSelection()) _attachPanel->selectItem(this); else _attachPanel->deselectItem(this); } void XFE_AttachPanelItem::doubleClickCb() { _attachPanel->doubleClickCb(_attachPanel->findItem(this)); } void XFE_AttachPanelItem::armCb(Widget w) { // flag button as down, use to discard ScrollTraversalCb calls for button press // (since the event field in the traverseObscuredCallbackStruct is useless.) _attachPanel->armedWidget(w); } void XFE_AttachPanelItem::disarmCb() { _attachPanel->armedWidget(NULL); // make sure label is visible after BtnUp on icon scrollVisible(); }