#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Fl_File_Btn.h" #include "Fl_Vert_Progress.h" #include "cmGlobal.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmRtSysMsg.h" #include "cmUiDrvr.h" #include "cmUiDrvrFltk.h" cmUiDrvrFltk::cmUiDrvrFltk(cmCtx_t* ctx, Fl_Tabs* tabs, cmUiDriverFunc_t cbFunc, void* cbArg) : _tabs(NULL),_cbFunc(NULL),_cbArgs(NULL),_panels(NULL) { cmErrSetup(&_err,&ctx->rpt,"cmUiDrvrFltk"); setBaseWindow(tabs); setCallback(cbFunc,cbArg); } void cmUiDrvrFltk::setBaseWindow( Fl_Tabs* tabs ) { _tabs = tabs; if( _tabs != NULL ) _tabs->callback(_s_tab_cb,this); } void cmUiDrvrFltk::setCallback( cmUiDriverFunc_t cbFunc, void* cbArg ) { _cbFunc = cbFunc; _cbArgs = cbArg; } cmUiDrvrFltk::~cmUiDrvrFltk() { _destroyAllPanels(false); } cmUiRC_t cmUiDrvrFltk::cmUiDriverFunc( void* cbArg, const cmUiDriverArg_t* args ) { cmUiDrvrFltk* p = (cmUiDrvrFltk*)cbArg; cmUiRC_t rc = kOkUiRC; switch(args->dId) { case kInvalidDId: break; case kCreateCtlDId: rc = p->_createCtl(args); break; case kDestroyCtlDId: rc = p->_destroyCtl(args->appId,args->panelId,args->usrId,true); break; case kSetValDId: rc = p->_setValueCtl(args); break; case kEnableDId: rc = p->_enableCtl(args); break; //case kDestroyAllDId: //rc = p->_destroyAllPanels(true); //break; case kMaxDId: assert(0); break; } return rc; } void cmUiDrvrFltk::_insertNewCtl( panel_t* pp, ctl_t* ctl, Fl_Widget* wp, unsigned flags ) { ctl->wdgt = wp; if( ctl->usrId != cmInvalidId ) { ctl->link = pp->ctls; pp->ctls = ctl; wp->callback( _s_ctl_cb, ctl ); } pp->grp->add(wp); int align_flags = 0; if( cmIsFlag(flags,kLeftUiFl)) align_flags |= FL_ALIGN_LEFT; if( cmIsFlag(flags,kTopUiFl)) align_flags |= FL_ALIGN_TOP; if( cmIsFlag(flags,kRightUiFl)) align_flags |= FL_ALIGN_RIGHT; if( cmIsFlag(flags,kBottomUiFl)) align_flags |= FL_ALIGN_BOTTOM; if( cmIsFlag(flags,kHCtrUiFl)) align_flags |= FL_ALIGN_CENTER; if( cmIsFlag(flags,kInsideUiFl)) align_flags |= FL_ALIGN_INSIDE; if( cmIsFlag(flags,kVCtrUiFl)) align_flags = cmClrFlag(align_flags,FL_ALIGN_TOP | FL_ALIGN_BOTTOM); wp->align(align_flags); int when_flags = 0; if( cmIsFlag(flags,kSendChangeFl)) when_flags |= FL_WHEN_CHANGED; if( cmIsFlag(flags,kSendEnterFl)) when_flags |= FL_WHEN_ENTER_KEY; if( cmIsFlag(flags,kSendFocusFl)) when_flags |= FL_WHEN_RELEASE; if( cmIsFlag(flags,kSendNoChangeFl)) when_flags |= FL_WHEN_NOT_CHANGED; if( when_flags != 0 ) wp->when(when_flags); } bool cmUiDrvrFltk::_hasNoAlignFlags( unsigned flags ) const { return !cmIsFlag(flags, kLeftUiFl | kTopUiFl | kRightUiFl | kBottomUiFl | kVCtrUiFl | kHCtrUiFl ); } cmUiRC_t cmUiDrvrFltk::_createCtl( const cmUiDriverArg_t* a ) { cmUiRC_t rc; panel_t* pp; panel_t* prvPnl; // if this is a panel create request if( a->cId == kPanelUiCId ) return _createPanel(a); // locate the new control's panel if((rc = _findPanel(a->appId,a->panelId,pp,prvPnl)) != kOkUiRC ) return rc; // allocate the control record ctl_t* ctl ; if( a->usrId == cmInvalidId ) ctl = &_dummy; else ctl = cmMemAllocZ(ctl_t,1); ctl->cId = a->cId; ctl->pnl = pp; ctl->usrId = a->usrId; ctl->flags = a->flags; int x = a->x + pp->x_offs; int y = a->y + pp->y_offs; // cache the event callback arg record so that it // does not have to be filled on every callback. cmUiDriverArgSetup(&ctl->cbArg,a->hdr.rtSubIdx,kUiDrvrSelRtId,kInvalidDId,pp->appId,a->usrId,pp->usrId,a->cId,0,0,0,NULL,x,y,a->w,a->h); //printf("%i %i %i %i\n",x,y,a->w,a->h); switch(a->cId) { case kInvalidUiCId: assert(0); break; case kPanelUiCId: break; case kBtnUiCId: ctl->u.btn = new Fl_Button(x,y,a->w,a->h,a->sval); _insertNewCtl(pp,ctl,ctl->u.btn,a->flags); ctl->cbArg.flags |= kIvalUiFl; break; case kCheckUiCId: ctl->u.chk = new Fl_Check_Button(x,y,a->w,a->h,a->sval); _insertNewCtl(pp,ctl,ctl->u.chk,a->flags); ctl->cbArg.flags |= kIvalUiFl; ctl->u.chk->value(a->ival); break; case kMenuBtnUiCId: ctl->u.mbt = new Fl_Menu_Button(x,y,a->w,a->h,a->sval!=NULL ? a->sval : NULL); _insertNewCtl(pp,ctl,ctl->u.mbt,a->flags); ctl->cbArg.flags |= kIvalUiFl; ctl->u.mbt->value(0); break; case kListUiCId: ctl->u.lst = new Fl_Select_Browser(x,y,a->w,a->h); _insertNewCtl(pp,ctl,ctl->u.lst,a->flags); ctl->cbArg.flags |= kIvalUiFl; break; case kLabelUiCId: { unsigned flags = a->flags; ctl->u.lbl = new Fl_Box(x,y,a->w,a->h); ctl->u.lbl->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kHCtrUiFl | kInsideUiFl; _insertNewCtl(pp,ctl,ctl->u.lbl,flags); } break; case kStringUiCId: { unsigned flags = a->flags; ctl->u.str = new Fl_Input(x,y,a->w/2,a->h); ctl->u.str->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.str,flags); ctl->cbArg.flags |= kSvalUiFl; } break; case kConsoleUiCId: { unsigned flags = a->flags; ctl->u.con = new Fl_Text_Display(x,y,a->w,a->h); ctl->u.con->buffer(new Fl_Text_Buffer()); ctl->u.con->textsize(12); ctl->u.con->textfont(FL_COURIER); ctl->u.con->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.con,flags); ctl->cbArg.flags |= kSvalUiFl; } break; case kSliderUiCId: { unsigned flags = a->flags; int w = a->w; int h = a->h; if( cmIsFlag(flags,kHorzUiFl) ) { if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; w /= 2; } if( cmIsFlag(flags,kVertUiFl) ) { if( _hasNoAlignFlags(flags) ) flags |= kTopUiFl | kHCtrUiFl; if( a->sval != NULL ) { int hh,ww; fl_measure(a->sval,ww,hh); if( flags & kTopUiFl ) { y += hh; h -= hh; } if( flags & kBottomUiFl) h -= hh; } } ctl->u.sld = new Fl_Value_Slider(x,y,w,h); ctl->u.sld->copy_label(a->sval); if( cmIsFlag(flags,kHorzUiFl) ) ctl->u.sld->type(FL_HOR_NICE_SLIDER); if( cmIsFlag(flags,kVertUiFl) ) ctl->u.sld->type(FL_VERT_NICE_SLIDER); _insertNewCtl(pp,ctl,ctl->u.sld,flags); ctl->cbArg.flags |= kFvalUiFl; } break; case kNumberUiCId: { unsigned flags = a->flags; ctl->u.num = new Fl_Value_Input(x,y,a->w/2,a->h); ctl->u.num->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.num,flags); ctl->cbArg.flags |= kFvalUiFl; ctl->u.num->when(FL_WHEN_ENTER_KEY | FL_WHEN_NOT_CHANGED ); } break; case kProgressUiCId: { unsigned flags = a->flags; ctl->u.prg = new Fl_Progress(x,y,a->w/2,a->h); ctl->u.prg->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.prg,flags); ctl->u.prg->color( fl_rgb_color((unsigned char)256),fl_rgb_color((unsigned char)128)); } break; case kMeterUiCId: { unsigned flags = a->flags; if( cmIsFlag(flags,kVertUiFl) ) { ctl->u.mtr = new Fl_Vert_Progress(x,y,a->w/2,a->h); ctl->u.mtr->color( fl_rgb_color((unsigned char)256),fl_rgb_color((unsigned char)128)); } else { ctl->u.mtr = new Fl_Progress(x,y,a->w,a->h); ctl->u.mtr->color( fl_rgb_color((unsigned char)256),fl_rgb_color((unsigned char)128)); } ctl->u.mtr->copy_label(a->sval); if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.mtr,flags); } break; case kFilenameUiCId: case kDirUiCId: { unsigned flags = a->cId==kDirUiCId ? Fl_File_Btn::kDir_Type_Id : Fl_File_Btn::kFile_Type_Id; ctl->u.fnb = new Fl_File_Btn(flags,"",x,y,a->w,a->h,a->sval); flags = a->flags; if( _hasNoAlignFlags(flags) ) flags |= kRightUiFl; _insertNewCtl(pp,ctl,ctl->u.fnb,flags); ctl->cbArg.flags |= kSvalUiFl; } break; case kMaxUiCId: assert(0); break; } pp->grp->redraw(); return rc; } cmUiRC_t cmUiDrvrFltk::_setValueCtl( const cmUiDriverArg_t* a ) { cmUiRC_t rc; panel_t* pp = NULL; panel_t* prvPnl = NULL; ctl_t* ctl = NULL; ctl_t* prvCtl = NULL; if((rc = _findPanel(a->appId,a->panelId,pp,prvPnl)) != kOkUiRC ) return rc; if((rc= _findCtl(pp, a->usrId, ctl, prvCtl )) != kOkUiRC ) return rc; switch( a->cId ) { case kInvalidUiCId: break; case kPanelUiCId: break; case kBtnUiCId: if( cmIsFlag(a->flags,kLblUiFl) ) ctl->u.btn->copy_label(a->sval); break; case kCheckUiCId: switch( a->flags & (kLblUiFl | kValUiFl) ) { case kValUiFl: ctl->u.chk->value(a->ival); break; case kLblUiFl: ctl->u.chk->copy_label(a->sval); break; } break; case kMenuBtnUiCId: switch( a->flags & (kAppendUiFl | kClearUiFl | kValUiFl) ) { case kValUiFl: if( a->ival < ctl->u.mbt->size() ) { ctl->u.mbt->value(a->ival); if( ctl->u.mbt->mvalue() != NULL) ctl->u.mbt->copy_label( ctl->u.mbt->mvalue()->label()); } break; case kClearUiFl: ctl->u.mbt->clear(); ctl->u.mbt->copy_label(""); break; case kAppendUiFl: { int n; ctl->u.mbt->add( a->sval,0,ctl->u.mbt->callback(),ctl->u.mbt->user_data(),0); n = ctl->u.mbt->size(); if( (n) == 2 ) { ctl->u.mbt->value(0); if( ctl->u.mbt->mvalue() != NULL) { const char* s = ctl->u.mbt->mvalue()->label(); ctl->u.mbt->copy_label( s); } } } break; } break; case kListUiCId: switch( a->flags & (kAppendUiFl | kClearUiFl | kValUiFl) ) { case kValUiFl: ctl->u.lst->value(a->ival); break; case kAppendUiFl: ctl->u.lst->add( a->sval ); break; case kClearUiFl: ctl->u.lst->clear(); break; } break; case kLabelUiCId: ctl->u.str->value(a->sval); break; case kStringUiCId: switch( a->flags & (kLblUiFl | kValUiFl) ) { case kValUiFl: ctl->u.str->value(a->sval); break; case kLblUiFl: ctl->u.str->copy_label(a->sval); break; } break; case kConsoleUiCId: switch( a->flags & (kLblUiFl | kValUiFl) ) { case kValUiFl: if(a->sval!=NULL) ctl->u.con->insert(a->sval); break; case kLblUiFl: ctl->u.str->copy_label(a->sval); break; } break; case kSliderUiCId: case kNumberUiCId: { Fl_Valuator* vp = static_cast(ctl->wdgt); // Correct for problem where the vertical slider values go up as the // slider knob is dragged down. bool invertFl = a->cId == kSliderUiCId && cmIsFlag(ctl->flags,kVertUiFl); switch(a->flags & (kNumMask | kLblUiFl | kMinUiFl | kMaxUiFl)) { case kLblUiFl: ctl->u.num->copy_label(a->sval); break; case kValUiFl: vp->value(a->fval); break; case kIncUiFl: vp->step(a->fval); break; case kMinUiFl: invertFl ? vp->maximum(a->fval) : vp->minimum(a->fval); break; case kMaxUiFl: invertFl ? vp->minimum(a->fval) : vp->maximum(a->fval); break; } } break; case kProgressUiCId: switch( a->flags & (kLblUiFl | kValUiFl | kMinUiFl | kMaxUiFl) ) { case kValUiFl: ctl->u.prg->value(a->ival); break; case kLblUiFl: ctl->u.prg->copy_label(a->sval); break; case kMinUiFl: ctl->u.prg->minimum(a->ival); break; case kMaxUiFl: ctl->u.prg->maximum(a->ival); break; } break; case kMeterUiCId: switch( a->flags & (kLblUiFl | kValUiFl | kMinUiFl | kMaxUiFl) ) { case kValUiFl: ctl->u.mtr->value(a->ival); ctl->u.mtr->redraw(); break; case kLblUiFl: ctl->u.mtr->copy_label(a->sval); break; case kMinUiFl: ctl->u.prg->minimum(a->ival); break; case kMaxUiFl: ctl->u.prg->maximum(a->ival); break; } break; case kFilenameUiCId: case kDirUiCId: switch(a->flags & (kFnMask | kValUiFl | kFnPatUiFl | kFnDirUiFl) ) { case kValUiFl: ctl->u.fnb->filename(a->sval); break; case kFnPatUiFl: ctl->u.fnb->pattern_string(a->sval); break; case kFnDirUiFl: ctl->u.fnb->type( ctl->u.fnb->type()==Fl_File_Btn::kFile_Type_Id ? Fl_File_Btn::kDir_Type_Id : Fl_File_Btn::kFile_Type_Id ); break; } break; case kMaxUiCId: assert(0); break; } // echo the result back to the UI //if( cmIsFlag(a->flags,kValUiFl|kAppendUiFl) ) // _cbFunc(_cbArgs,a); return rc; } cmUiRC_t cmUiDrvrFltk::_enableCtl( const cmUiDriverArg_t* a ) { cmUiRC_t rc; panel_t* pp = NULL; panel_t* prvPnl = NULL; ctl_t* ctl = NULL; ctl_t* prvCtl = NULL; if((rc = _findPanel(a->appId,a->panelId,pp,prvPnl)) != kOkUiRC ) return rc; if((rc= _findCtl(pp, a->usrId, ctl, prvCtl )) != kOkUiRC ) return rc; if( a->ival ) ctl->wdgt->activate(); else ctl->wdgt->deactivate(); _doCb(ctl,kEnableDId,0); return rc; } cmUiRC_t cmUiDrvrFltk::_destroyCtl( unsigned appId, unsigned panelId, unsigned usrId, bool deleteWindowEleFlag ) { cmUiRC_t rc = kOkUiRC; panel_t* pp = NULL; panel_t* prvPnl = NULL; // locate the panel assoc'd with the ctl if((rc = _findPanel(appId,panelId,pp,prvPnl,true)) != kOkUiRC ) return rc; // if the panel is the ctl to delete ... if( usrId == pp->usrId ) { // ... unlink the panel if( prvPnl!=NULL) prvPnl->link = pp->link; else { assert(_panels == pp ); _panels = pp->link; } } return _destroyCtl(pp,usrId,deleteWindowEleFlag); } cmUiRC_t cmUiDrvrFltk::_destroyCtl( panel_t* pp, unsigned usrId, bool deleteWindowEleFlag ) { cmUiRC_t rc = kOkUiRC; ctl_t* ctl = NULL; ctl_t* prvCtl = NULL; // if the panel is the ctl to delete if( usrId == pp->usrId ) { return _destroyPanel(pp,deleteWindowEleFlag); } // locate the control on the panel if((rc = _findCtl(pp,usrId,ctl,prvCtl,true)) != kOkUiRC ) return rc; // unlink the control if( prvCtl!=NULL) prvCtl->link = ctl->link; else { assert( pp->ctls == ctl ); pp->ctls = ctl->link; } // delete the window element if( deleteWindowEleFlag) delete ctl->wdgt; // release the control recd cmMemFree(ctl); return rc; } cmUiRC_t cmUiDrvrFltk::_createPanel( const cmUiDriverArg_t* a ) { int tx,ty,tw,th; _tabs->client_area(tx,ty,tw,th); panel_t* pnl = cmMemAllocZ(panel_t,1); pnl->drvr = this; pnl->grp = new Fl_Group(tx,ty,tw,th,a->sval); pnl->grp->user_data(pnl); pnl->appId = a->appId; pnl->usrId = a->usrId; pnl->x_offs = tx + 2; pnl->y_offs = ty + 2; pnl->link = _panels; _panels = pnl; pnl->grp->end(); if( cmIsFlag(a->flags,kPrependUiFl) ) _tabs->insert(*pnl->grp,0); else _tabs->add(pnl->grp); // cache the event callback arg record so that it // does not have to be filled on every callback. cmUiDriverArgSetup(&pnl->cbArg,a->hdr.rtSubIdx,kUiDrvrSelRtId,kSetValDId,a->appId,a->usrId,a->usrId,kPanelUiCId,kIvalUiFl,0,0,NULL,tx,ty,tw,th); _tabs->redraw(); return kOkUiRC; } cmUiRC_t cmUiDrvrFltk::_destroyAllPanels( bool deleteWindowEleFlag ) { cmUiRC_t rc = kOkUiRC; while( _panels != NULL ) { cmUiRC_t rc0; if((rc0 = _destroyCtl(_panels->appId,_panels->usrId,_panels->usrId,deleteWindowEleFlag)) != kOkUiRC ) rc = rc0; } return rc; } cmUiRC_t cmUiDrvrFltk::_destroyPanel(panel_t* pp, bool deleteWindowEleFlag) { cmUiRC_t rc = kOkUiRC; // delete the FLTK panel itself if( deleteWindowEleFlag ) { delete pp->grp; deleteWindowEleFlag = false; } while( pp->ctls != NULL ) { cmUiRC_t rc0; if((rc0 = _destroyCtl(pp,pp->ctls->usrId,deleteWindowEleFlag)) != kOkUiRC ) rc = rc0; } cmMemFree(pp); return rc; } cmUiRC_t cmUiDrvrFltk::_findPanel( unsigned appId, unsigned usrId, panel_t*& ppRef, panel_t*& prvPnl, bool errFl ) { ppRef = NULL; prvPnl = NULL; panel_t* pp = _panels; for(; pp!=NULL; pp=pp->link) { if(pp->appId==appId && pp->usrId==usrId ) { ppRef = pp; return kOkUiRC; } prvPnl = pp; } if( errFl ) cmErrMsg(&_err,kPanelNotFoundUiRC,"Panel not found for id=%i.",usrId); return kPanelNotFoundUiRC; } cmUiRC_t cmUiDrvrFltk::_findCtl( panel_t* pp, unsigned usrId, ctl_t*& ctlRef, ctl_t*& prvCtlRef, bool errFl ) { ctlRef = NULL; prvCtlRef = NULL; ctl_t* cp = pp->ctls; for(; cp!=NULL; cp=cp->link) { if( cp->usrId == usrId ) { ctlRef = cp; return kOkUiRC; } prvCtlRef = cp; } if( errFl ) cmErrMsg(&_err,kCtlNotFoundUiRC,"Control %i not found in panel %i.",usrId,pp->usrId); return kCtlNotFoundUiRC; } void cmUiDrvrFltk::_doCb( ctl_t* ctl, cmUiDId_t dId, unsigned flags ) { cmUiDriverArg_t* a = &ctl->cbArg; unsigned orgFlags = a->flags; a->flags |= flags; a->dId = dId; _cbFunc(_cbArgs,&ctl->cbArg); a->flags = orgFlags; a->dId = kInvalidDId; } void cmUiDrvrFltk::_s_ctl_cb(Fl_Widget* wp, void* arg ) { ctl_t* ctl = (ctl_t*)arg; cmUiDrvrFltk* p = ctl->pnl->drvr; cmUiDriverArg_t* a = &ctl->cbArg; bool callbackFl = true; unsigned flags = kValUiFl; switch( ctl->cId ) { case kInvalidUiCId: assert(0); callbackFl = false; break; case kPanelUiCId: callbackFl = false; break; case kBtnUiCId: break; case kCheckUiCId: a->ival = ctl->u.chk->value(); flags |= kIvalUiFl; break; case kMenuBtnUiCId: if( ctl->u.mbt->mvalue() != NULL && ctl->u.mbt->mvalue()->label() != NULL ) ctl->u.mbt->copy_label(ctl->u.mbt->mvalue()->label()); a->ival = ctl->u.mbt->value(); flags |= kIvalUiFl; break; case kListUiCId: a->ival = ctl->u.lst->value() - 1; flags |= kIvalUiFl; break; case kLabelUiCId: callbackFl = false; break; case kStringUiCId: a->sval = ctl->u.str->value(); flags |= kSvalUiFl; break; case kConsoleUiCId: callbackFl = false; break; case kSliderUiCId: a->fval = ctl->u.sld->value(); flags |= kFvalUiFl; break; case kNumberUiCId: a->fval = ctl->u.num->value(); flags |= kFvalUiFl; break; case kProgressUiCId: callbackFl = false; break; case kMeterUiCId: callbackFl = false; break; case kFilenameUiCId: a->sval = ctl->u.fnb->filename(); flags |= kSvalUiFl; break; case kDirUiCId: a->sval = ctl->u.fnb->filename(); flags |= kSvalUiFl; break; case kMaxUiCId: callbackFl = false; assert(0); break; } if( callbackFl ) p->_doCb(ctl,kSetValDId,flags); } void cmUiDrvrFltk::_s_tab_cb(Fl_Widget* wp, void* arg ) { cmUiDrvrFltk* p = (cmUiDrvrFltk*)arg; Fl_Widget* w = p->_tabs->value(); panel_t* pp = p->_panels; for(; pp!=NULL; pp=pp->link) { // if this is the panel being selected then send a 1 otherwise send a 0. pp->cbArg.flags = cmSetFlag(pp->cbArg.flags, kIvalUiFl ); pp->cbArg.dId = kSetValDId; pp->cbArg.ival = w->user_data() == pp->grp->user_data(); p->_cbFunc(p->_cbArgs,&pp->cbArg); pp->cbArg.flags = cmClrFlag(pp->cbArg.flags, kIvalUiFl ); pp->cbArg.dId = kInvalidDId; } }