//| Copyright: (C) 2019-2020 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #include #include #include #include #include #include #include #include "cmPrefix.h" #include "cmGlobal.h" #include "cmFloatTypes.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmGr.h" #include "cmGrDevCtx.h" #include "cmGrPage.h" #include "cmGrPlot.h" #include "cmGrFltk.h" //-------------------------------------------------------------------------------------- cmGrDevDrvFltk::cmGrDevDrvFltk() : _fltk_pen_width(0), _fltk_pen_style(0), _fltk_font_size(0), _w(0), _h(0) { d.create = create; d.destroy = destroy; d.begin_draw = begin_draw; d.end_draw = end_draw; d.draw = draw; d.set_color = set_color; d.get_color = get_color; d.set_font_family = set_font_family; d.get_font_family = get_font_family; d.set_font_style = set_font_style; d.get_font_style = get_font_style; d.set_font_size = set_font_size; d.get_font_size = get_font_size; d.set_pen_style = set_pen_style; d.get_pen_style = get_pen_style; d.set_pen_width = set_pen_width; d.get_pen_width = get_pen_width; d.draw_line = draw_line; d.draw_rect = draw_rect; d.fill_rect = fill_rect; d.draw_ellipse = draw_ellipse; d.fill_ellipse = fill_ellipse; d.draw_diamond = draw_diamond; d.fill_diamond = fill_diamond; d.draw_triangle = draw_triangle; d.fill_triangle = fill_triangle; d.draw_text = draw_text; d.draw_text_rot = draw_text_rot; d.measure_text = measure_text; d.read_image = read_image; d.draw_image = draw_image; } bool cmGrDevDrvFltk::create( void* user, unsigned ww, unsigned hh ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; if( ww && hh && p->_w != ww && p->_h != hh ) { destroy(user); p->_w = ww; p->_h = hh; //printf("creat: 0x%x w:%i h:%i\n",(unsigned)p->fl_os,p->w,p->h); } return true; } void cmGrDevDrvFltk::destroy( void* user ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; p->_w = 0; p->_h = 0; } void cmGrDevDrvFltk::begin_draw( void* arg ) { } void cmGrDevDrvFltk::end_draw( void* arg ) { } void cmGrDevDrvFltk::draw( void* arg, int x, int y ) { } void cmGrDevDrvFltk::set_color( void* user, const cmGrColor_t c ) { Fl_Color color = fl_rgb_color(cmGrColorToR(c),cmGrColorToG(c),cmGrColorToB(c)); fl_color(color); } void cmGrDevDrvFltk::get_color( void* user, cmGrColor_t* c ) { Fl_Color color = fl_color(); *c = cmGrRgbToColor( ((color>>24)&0x000000ff),((color>>16)&0x000000ff),((color>>8)&0x000000ff)); } void cmGrDevDrvFltk::_get_font_family_style( unsigned* fontId, unsigned* style) { switch( fl_font() ) { case FL_HELVETICA: *fontId = kHelveticaFfGrId; *style = kNormalFsGrFl; break; case FL_HELVETICA_BOLD: *fontId = kHelveticaFfGrId; *style = kBoldFsGrFl; break; case FL_HELVETICA_ITALIC: *fontId = kHelveticaFfGrId; *style = kItalicFsGrFl; break; case FL_HELVETICA_BOLD_ITALIC: *fontId = kHelveticaFfGrId; *style = kBoldFsGrFl | kItalicFsGrFl; break; case FL_TIMES: *fontId = kTimesFfGrId; *style = kNormalFsGrFl; break; case FL_TIMES_BOLD: *fontId = kTimesFfGrId; *style = kBoldFsGrFl; break; case FL_TIMES_ITALIC: *fontId = kTimesFfGrId; *style = kItalicFsGrFl; break; case FL_TIMES_BOLD_ITALIC: *fontId = kTimesFfGrId; *style = kBoldFsGrFl | kItalicFsGrFl; break; case FL_COURIER: *fontId = kCourierFfGrId; *style = kNormalFsGrFl; break; case FL_COURIER_BOLD: *fontId = kCourierFfGrId; *style = kBoldFsGrFl; break; case FL_COURIER_ITALIC: *fontId = kCourierFfGrId; *style = kItalicFsGrFl; break; case FL_COURIER_BOLD_ITALIC: *fontId = kCourierFfGrId; *style = kBoldFsGrFl | kItalicFsGrFl; break; default: { assert(0); } } } void cmGrDevDrvFltk::_set_font_family_style( void* user, unsigned fontId, unsigned style) { switch( fontId ) { case kHelveticaFfGrId: switch( style ) { case kNormalFsGrFl: fontId = FL_HELVETICA; break; case kBoldFsGrFl: fontId = FL_HELVETICA_BOLD; break; case kItalicFsGrFl: fontId = FL_HELVETICA_ITALIC; break; case kItalicFsGrFl + kBoldFsGrFl: fontId = FL_HELVETICA_BOLD_ITALIC; break; default: { assert(0); } } break; case kTimesFfGrId: switch( style ) { case kNormalFsGrFl: fontId = FL_TIMES; break; case kBoldFsGrFl: fontId = FL_TIMES_BOLD; break; case kItalicFsGrFl: fontId = FL_TIMES_ITALIC; break; case kItalicFsGrFl + kBoldFsGrFl: fontId = FL_TIMES_BOLD_ITALIC; break; default: { assert(0); } } break; case kCourierFfGrId: switch( style ) { case kNormalFsGrFl: fontId = FL_COURIER; break; case kBoldFsGrFl: fontId = FL_COURIER_BOLD; break; case kItalicFsGrFl: fontId = FL_COURIER_ITALIC; break; case kItalicFsGrFl + kBoldFsGrFl: fontId = FL_COURIER_BOLD_ITALIC; break; default: { assert(0); } } break; default: { assert(0); } } cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; fl_font( fontId, p->_fltk_font_size ); } void cmGrDevDrvFltk::set_font_family( void* user, unsigned fontId ) { _set_font_family_style( user, fontId, get_font_style(user) ); } unsigned cmGrDevDrvFltk::get_font_family( void* user ) { unsigned fontId=0, style=0; _get_font_family_style(&fontId,&style); return fontId; } void cmGrDevDrvFltk::set_font_style( void* user, unsigned style ) { _set_font_family_style( user, get_font_family(user), style); } unsigned cmGrDevDrvFltk::get_font_style( void* user ) { unsigned fontId=0, style=0; _get_font_family_style(&fontId,&style); return style; } void cmGrDevDrvFltk::set_font_size( void* user, unsigned size ) { unsigned fontId=0, style=0; cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; _get_font_family_style(&fontId,&style); p->_fltk_font_size = size; _set_font_family_style(user,fontId,style); } unsigned cmGrDevDrvFltk::get_font_size( void* user ) { return fl_size(); } void cmGrDevDrvFltk::set_pen_style( void* user, unsigned style ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; switch( style ) { case kSolidLsGrFl: style = FL_SOLID; break; case kDashLsGrFl: style = FL_DASH; break; case kDotLsGrFl: style = FL_DOT; break; default: { assert(0); } } p->_fltk_pen_style = style; fl_line_style( p->_fltk_pen_style, p->_fltk_pen_width ); } unsigned cmGrDevDrvFltk::get_pen_style( void* user ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; unsigned style = kSolidLsGrFl; switch( p->_fltk_pen_style ) { case FL_SOLID: style = kSolidLsGrFl; break; case FL_DASH: style = kDashLsGrFl; break; case FL_DOT: style = kDotLsGrFl; break; default: { assert(0); } } return style; } void cmGrDevDrvFltk::set_pen_width( void* user, unsigned w ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; p->_fltk_pen_width = w; fl_line_style( p->_fltk_pen_style, p->_fltk_pen_width ); } unsigned cmGrDevDrvFltk::get_pen_width( void* user ) { cmGrDevDrvFltk* p = (cmGrDevDrvFltk*)user; return p->_fltk_pen_width; } void cmGrDevDrvFltk::draw_line( void* user, int x0, int y0, int x1, int y1 ) { fl_line(x0,y0,x1,y1); } void cmGrDevDrvFltk::draw_rect( void* user, int x0, int y0, unsigned w, unsigned h ) { fl_rect(x0,y0,w,h); } void cmGrDevDrvFltk::fill_rect( void* user, int x0, int y0, unsigned w, unsigned h ) { fl_rectf(x0,y0,w,h); } void cmGrDevDrvFltk::draw_ellipse( void* user, int x0, int y0, unsigned w, unsigned h ) { fl_arc(x0,y0,w,h,0,360); } void cmGrDevDrvFltk::fill_ellipse( void* user, int x0, int y0, unsigned w, unsigned h ) { fl_pie(x0,y0,w,h,0,360); } void cmGrDevDrvFltk::draw_diamond( void* user, int x0, int y0, unsigned w, unsigned h ) { } void cmGrDevDrvFltk::fill_diamond( void* user, int x0, int y0, unsigned w, unsigned h ) { } void cmGrDevDrvFltk::draw_triangle( void* user, int x0, int y0, unsigned w, unsigned h, unsigned dirFlag ) { } void cmGrDevDrvFltk::fill_triangle( void* user, int x0, int y0, unsigned w, unsigned h, unsigned dirFlag ) { } void cmGrDevDrvFltk::draw_text( void* user, const char* text, int x, int y ) { int y0 = y - fl_descent(); fl_draw(text,x,y0); /* Fl_Color c = fl_color(); fl_color(FL_RED); fl_point(x,y); fl_point(x,y0); fl_point(x,y - fl_height()); fl_color(c); */ } void cmGrDevDrvFltk::draw_text_rot( void* user, const char* text, int x, int y, int angle ) { fl_draw(angle,text,strlen(text),x,y); Fl_Color c = fl_color(); fl_color(FL_RED); fl_point(x,y); fl_color(c); } void cmGrDevDrvFltk::measure_text( void* user, const char* text, unsigned* w, unsigned* h ) { int ww; int hh; fl_measure(text,ww,hh); *w = ww; *h = hh; } void cmGrDevDrvFltk::read_image( void* user, unsigned char* p, int x, int y, unsigned w, unsigned h ) { fl_read_image(p,x,y,w,h,false); } void cmGrDevDrvFltk::draw_image( void* user, const unsigned char* p, int x, int y, unsigned w, unsigned h ) { fl_draw_image(p,x,y,w,h,3,0); } bool cmGrDevDrvFltk::is_initialized() const { return true; } //-------------------------------------------------------------------------------------- void testKey() { int k = Fl::event_key(); printf("code:0x%x text:%s ",k,Fl::event_text()); bool fl = Fl::event_state() & FL_NUM_LOCK; if( fl ) printf("KP "); // if this key has an ASCII printable symbol if( kSpaceGrId <= k && k <= kTildeGrId ) { char ch = Fl::event_text()[0]; // correct for an apparent bug in FLTK // which get's the case of the characters // wrong. if( ('A' <= ch && ch <= 'Z') ) ch = tolower(ch); else if(('a' <= ch && ch <= 'z' ) ) ch = toupper(ch); printf("Known: ASCII '%c'.\n", ch); return; } const char* str = NULL; if( str == NULL ) switch( k ) { case 0xffaa: str="KP_Mult"; break; case 0xffab: str="KP_Plus"; break; case 0xffad: str="KP_Minus"; break; case 0xffae: str="KP_DecPt"; break; case 0xffaf: str="KP_Div"; break; case 0xffb1: str="KP_1"; break; case 0xffb2: str="KP_2"; break; case 0xffb3: str="KP_3"; break; case 0xffb4: str="KP_4"; break; case 0xffb5: str="KP_5"; break; case 0xffb6: str="KP_6"; break; case 0xffb7: str="KP_7"; break; case 0xffb8: str="KP_8"; break; case 0xffb9: str="KP_9"; break; case 0xffbd: str="KP_Equal"; break; case 0xffbe: str="F1"; break; case 0xffbf: str="F2"; break; case 0xffc0: str="F3"; break; case 0xffc1: str="F4"; break; case 0xffc2: str="F5"; break; case 0xffc3: str="F6"; break; case 0xffc4: str="F7"; break; case 0xffc5: str="F8"; break; case 0xffc6: str="F9"; break; case 0xffc7: str="F10"; break; case 0xffc8: str="F11"; break; case 0xffc9: str="F12"; break; case FL_Home: str="Home"; break; case FL_Page_Up: str="PgUp"; break; case FL_Delete: str="Del"; break; case FL_End: str="End"; break; case FL_Page_Down: str="PgDn"; break; case FL_Left: str="Left"; break; case FL_Up: str="Up"; break; case FL_Right: str="Right"; break; case FL_Down: str="Down"; break; case FL_Insert: str="Insert"; break; case FL_Escape: str="Esc"; break; case FL_BackSpace: str="BS"; break; case FL_Tab: str="Tab"; break; case FL_Enter: str="Enter"; break; case FL_Print: str="Print"; break; case FL_Scroll_Lock: str="ScrLck";break; case FL_Pause: str="Pause"; break; case FL_Shift_L: str="L-Shift"; break; case FL_Shift_R: str="R-Shift"; break; case FL_Control_L: str="L_Ctrl"; break; case FL_Control_R: str="R_Ctrl"; break; case FL_Caps_Lock: str="CapLck"; break; case FL_Alt_L: str="L_Alt"; break; case FL_Alt_R: str="R_Alt"; break; case FL_Meta_L: str="L_Super"; break; case FL_Meta_R: str="R_Super"; break; case FL_Menu: str="Menu"; break; case FL_Num_Lock: str="NumLock"; break; case FL_KP_Enter: str="KP_Enter"; break; } printf("%s\n", (str==NULL ? "" : str)); } cmGrViewFltk::keyMap_t cmGrViewFltk::_keymap[] = { { 0, 0, 0, kInvalidKeyCodeGrId }, { 1, 0, 0, kInvalidKeyCodeGrId }, { 2, 0, 0, kInvalidKeyCodeGrId }, { 3, 0, 0, kInvalidKeyCodeGrId }, { 4, 0, 0, kInvalidKeyCodeGrId }, { 5, FL_Home, 0, kHomeGrId}, { 6, FL_Page_Up, 0, kPageUpGrId}, { 7, FL_End, 0, kEndGrId}, { 8, FL_BackSpace, 8, kBackSpaceGrId }, { 9, FL_Tab, 9, kTabGrId }, { 10, FL_Page_Down, 0, kPageDownGrId}, { 11, FL_Left, 0, kLeftGrId}, { 12, FL_Up, 0, kUpGrId}, { 13, FL_Enter, 13, kEnterGrId }, { 14, FL_Right, 0, kRightGrId}, { 15, FL_Down, 0, kDownGrId}, { 16, FL_Insert, 0, kInsertGrId}, { 17, FL_Print, 0, kPrintGrId}, { 18, FL_Scroll_Lock, 0, kScrollLockGrId}, { 19, FL_Pause, 0, kPauseGrId}, { 20, FL_Menu, 0, kMenuGrId}, { 21, FL_Shift_L, 0, kLShiftGrId}, { 22, FL_Shift_R, 0, kRShiftGrId}, { 23, FL_Control_L, 0, kLCtrlGrId}, { 24, FL_Control_R, 0, kRCtrlGrId}, { 25, FL_Alt_L, 0, kLAltGrId}, { 26, FL_Alt_R, 0, kRAltGrId}, { 27, FL_Escape, 27, kEscapeGrId }, { 28, FL_Meta_L, 0, kLSuperGrId}, { 29, FL_Meta_R, 0, kRSuperGrId}, { 30, FL_Num_Lock, 0, kNumLockGrId}, { 31, FL_Caps_Lock, 0, kCapsLockGrId}, { 32, 32, 32, kSpaceGrId }, { 33, 33, 33, kExclMarkGrId }, { 34, 34, 34, kDQuoteGrId }, { 35, 35, 35, kPoundGrId }, { 36, 36, 36, kDollarGrId }, { 37, 37, 37, kPercentGrId }, { 38, 38, 38, kAmpersandGrId }, { 39, 39, 39, kApostropheGrId }, { 40, 40, 40, kLParenGrId }, { 41, 41, 41, kRParenGrId }, { 42, 42, 42, kAsteriskGrId }, { 43, 43, 43, kPlusGrId }, { 44, 44, 44, kCommaGrId }, { 45, 45, 45, kHyphenGrId }, { 46, 46, 46, kPeriodGrId }, { 47, 47, 47, kForwardSlashGrId }, { 48, 48, 48, k0GrId }, { 49, 49, 49, k1GrId }, { 50, 50, 50, k2GrId }, { 51, 51, 51, k3GrId }, { 52, 52, 52, k4GrId }, { 53, 53, 53, k5GrId }, { 54, 54, 54, k6GrId }, { 55, 55, 55, k7GrId }, { 56, 56, 56, k8GrId }, { 57, 57, 57, k9GrId }, { 58, 58, 58, kColonGrId }, { 59, 59, 59, kSemiColonGrId }, { 60, 60, 60, kLesserGrId }, { 61, 61, 61, kEqualGrId }, { 62, 62, 62, kGreaterGrId }, { 63, 63, 63, kQMarkGrId }, { 64, 64, 64, kAtGrId }, { 65, 65, 65, kA_GrId }, { 66, 66, 66, kB_GrId }, { 67, 67, 67, kC_GrId }, { 68, 68, 68, kD_GrId }, { 69, 69, 69, kE_GrId }, { 70, 70, 70, kF_GrId }, { 71, 71, 71, kG_GrId }, { 72, 72, 72, kH_GrId }, { 73, 73, 73, kI_GrId }, { 74, 74, 74, kJ_GrId }, { 75, 75, 75, kK_GrId }, { 76, 76, 76, kL_GrId }, { 77, 77, 77, kM_GrId }, { 78, 78, 78, kN_GrId }, { 79, 79, 79, kO_GrId }, { 80, 80, 80, kP_GrId }, { 81, 81, 81, kQ_GrId }, { 82, 82, 82, kR_GrId }, { 83, 83, 83, kS_GrId }, { 84, 84, 84, kT_GrId }, { 85, 85, 85, kU_GrId }, { 86, 86, 86, kV_GrId }, { 87, 87, 87, kW_GrId }, { 88, 88, 88, kX_GrId }, { 89, 89, 89, kY_GrId }, { 90, 90, 90, kZ_GrId }, { 91, 91, 91, kLBracketGrId }, { 92, 92, 92, kBackSlashGrId }, { 93, 93, 93, kRBracketGrId }, { 94, 94, 94, kCaretGrId }, { 95, 95, 95, kUnderScoreGrId }, { 96, 96, 96, kAccentGrId }, { 97, 97, 97, ka_GrId }, { 98, 98, 98, kb_GrId }, { 99, 99, 99, kc_GrId }, { 100, 100, 100, kd_GrId }, { 101, 101, 101, ke_GrId }, { 102, 102, 102, kf_GrId }, { 103, 103, 103, kg_GrId }, { 104, 104, 104, kh_GrId }, { 105, 105, 105, ki_GrId }, { 106, 106, 106, kj_GrId }, { 107, 107, 107, kk_GrId }, { 108, 108, 108, kl_GrId }, { 109, 109, 109, km_GrId }, { 110, 110, 110, kn_GrId }, { 111, 111, 111, ko_GrId }, { 112, 112, 112, kp_GrId }, { 113, 113, 113, kq_GrId }, { 114, 114, 114, kr_GrId }, { 115, 115, 115, ks_GrId }, { 116, 116, 116, kt_GrId }, { 117, 117, 117, ku_GrId }, { 118, 118, 118, kv_GrId }, { 119, 119, 119, kw_GrId }, { 120, 120, 120, kx_GrId }, { 121, 121, 121, ky_GrId }, { 122, 122, 122, kz_GrId }, { 123, 123, 123, kLBraceGrId }, { 124, 124, 124, kPipeGrId }, { 125, 125, 125, kRBraceGrId }, { 126, 126, 126, kTildeGrId }, { 127, FL_Delete, 127, kDeleteGrId }, { 128, 0xffaa, 42, kNP_MultGrId }, { 129, 0xffab, 43, kNP_PlusGrId }, { 130, 0xffad, 45, kNP_MinusGrId }, { 131, 0xffae, 46, kNP_DecPtGrId}, { 132, 0xffaf, 47, kNP_DivGrId}, { 133, 0xffb0, 48, kNP_0GrId}, { 134, 0xffb1, 49, kNP_1GrId}, { 135, 0xffb2, 50, kNP_2GrId}, { 136, 0xffb3, 51, kNP_3GrId}, { 137, 0xffb4, 52, kNP_4GrId}, { 138, 0xffb5, 53, kNP_5GrId}, { 139, 0xffb6, 54, kNP_6GrId}, { 140, 0xffb7, 55, kNP_7GrId}, { 141, 0xffb8, 56, kNP_8GrId}, { 142, 0xffb9, 57, kNP_9GrId}, { 143, 0xffbd, 61, kNP_EqualGrId}, { 144, FL_KP_Enter, 13, kNP_EnterGrId}, { 145, 0xffbe, 0, kFunc_1GrId}, { 146, 0xffbf, 0, kFunc_2GrId}, { 147, 0xffc0, 0, kFunc_3GrId}, { 148, 0xffc1, 0, kFunc_4GrId}, { 149, 0xffc2, 0, kFunc_5GrId}, { 150, 0xffc3, 0, kFunc_6GrId}, { 151, 0xffc4, 0, kFunc_7GrId}, { 152, 0xffc5, 0, kFunc_8GrId}, { 153, 0xffc6, 0, kFunc_9GrId}, { 154, 0xffc7, 0, kFunc_10GrId}, { 155, 0xffc8, 0, kFunc_11GrId}, { 156, 0xffc9, 0, kFunc_12GrId}, { 157, 0x1008ff03, 0, kBrightUpGrId}, { 158, 0x1008ff02, 0, kBrightDnGrId}, { 159, 0xef16, 0, kAudio_PrevGrId}, { 160, 0xef14, 0, kAudio_PlayGrId}, { 161, 0xef17, 0, kAudio_NextGrId}, { 162, 0xef12, 0, kAudio_MuteGrId}, { 163, 0xef11, 0, kAudio_DnGrId }, { 164, 0xef13, 0, kAudio_UpGrId }, { 165, 0x1008ff2c, 0, kEjectGrId }, { cmInvalidIdx, cmInvalidId, 0, kInvalidKeyCodeGrId } }; const cmGrViewFltk::keyMap_t* cmGrViewFltk::_getGrKeyCode( unsigned fltk_code ) { if( 32 <= fltk_code && fltk_code <= 126 ) return _keymap + fltk_code; unsigned i; for(i=0; i<32; ++i) if( _keymap[i].fltk_code == fltk_code ) return _keymap + i; for(i=127; _keymap[i].idx != cmInvalidIdx; ++i) if( _keymap[i].fltk_code == fltk_code ) return _keymap + i; return NULL; } cmGrViewFltk::cmGrViewFltk( cmCtx_t* ctx, cmGrH_t grH, int x, int y, int w, int h ) : Fl_Widget(x,y,w,h),_grH(grH),_dcH(cmGrDcNullHandle) { cmGrDevCtxCreate( ctx, &_dcH, &_dd.d, &_dd, x, y, w, h ); } cmGrViewFltk::~cmGrViewFltk() { cmGrDevCtxDestroy(&_dcH); } unsigned eventModKeyFlags() { unsigned flags = 0; if( Fl::event_alt() ) flags |= kAltKeyGrFl; if( Fl::event_ctrl() ) flags |= kCtlKeyGrFl; if( Fl::event_shift() ) flags |= kShiftKeyGrFl; switch( Fl::event_button() ) { case FL_LEFT_MOUSE: flags |= kMsLBtnGrFl; break; case FL_RIGHT_MOUSE: flags |= kMsRBtnGrFl; break; case FL_MIDDLE_MOUSE: flags |= kMsCBtnGrFl; break; } return flags; } cmGrKeyCodeId_t cmGrViewFltk::_eventKeyCode() { const keyMap_t* kmp; if(( kmp = _getGrKeyCode(Fl::event_key())) != NULL ) return kmp->gr_code; return kInvalidKeyCodeGrId; } int cmGrViewFltk::handle(int event) { bool fl = false; switch(event) { case FL_ENTER: // req'd to receive FL_MOVE event break; case FL_LEAVE: break; case FL_PUSH: fl = cmGrEvent(_grH, kMsDownGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; case FL_RELEASE: fl = cmGrEvent(_grH, kMsUpGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; case FL_DRAG: fl = cmGrEvent(_grH, kMsDragGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; case FL_MOVE: fl = cmGrEvent(_grH, kMsMoveGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; case FL_FOCUS: Fl::focus(this); break; case FL_UNFOCUS: break; case FL_KEYDOWN: fl = cmGrEvent(_grH, kKeyDnGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; case FL_KEYUP: fl = cmGrEvent(_grH, kKeyUpGrFl | eventModKeyFlags(), _eventKeyCode(), Fl::event_x(),Fl::event_y()); break; default: return Fl_Widget::handle(event); } if( fl ) redraw(); return 1; } void cmGrViewFltk::resize(int x, int y, int w, int h ) { cmGrPExt_t pext0,pext1; cmGrPExtSet(&pext0,this->x(),this->y(),this->w(),this->h()); cmGrPExtSet(&pext1,x,y,w,h); if( cmGrPExtIsEqual(&pext0,&pext1)==false ) { // must call base to make size change Fl_Widget::resize(x,y,w,h); //printf("resize: %i %i %i %i : %i %i %i %i\n",x,y,w,h,this->x(),this->y(),this->w(),this->h()); if( cmGrIsValid( _grH ) ) { //cmGrDevCtxResize( _dcH, x, y, w, h ); cmGrSetPhysExtents( _grH, x, y, w, h); } } } void cmGrViewFltk::setGrH( cmGrH_t grH ) { _grH=grH;} void cmGrViewFltk::draw() { /* fl_line_style(FL_SOLID,1,NULL); fl_color(FL_RED); cmGrPExt_t pext; cmGrPhysExtents(_grH, &pext ); fl_rect(pext.loc.x,pext.loc.y,pext.sz.w,pext.sz.h); fl_line(x(),y(),x()+w()-1,y()+h()-1); fl_line(x()+w()-1,y(),x(),y()+h()-1); */ fl_push_clip(x(),y(),w(),h()); fl_color(FL_BACKGROUND_COLOR); fl_rectf(x(),y(),w(),h()); if( cmGrIsValid(_grH) ) { cmGrPExt_t pext0,pext1; //cmGrPExtSet(&pext0,this->x(),this->y(),this->w(),this->h()); cmGrPhysExtents(_grH, &pext0 ); cmGrDevCtxSize( _dcH, &pext1 ); if( cmGrPExtIsEqual(&pext0,&pext1)==false ) //cmGrDevCtxResize(_dcH, this->x(), this->y(), this->w(),this->h() ); cmGrDevCtxResize(_dcH, cmGrPExtL(&pext0), cmGrPExtT(&pext0), cmGrPExtW(&pext0), cmGrPExtH(&pext0) ); cmGrDevCtxBeginDraw(_dcH); cmGrDraw(_grH,_dcH); cmGrDevCtxEndDraw(_dcH); cmGrDevCtxDraw(_dcH); } fl_pop_clip(); } //-------------------------------------------------------------------------------------- cmGrPageFltk::cmGrPageFltk( cmCtx_t* ctx, cmGrPgH_t pgH, int x, int y, int w, int h ) : Fl_Group(x,y,w,h),_ctx(ctx),_pgH(pgH),_dcH(cmGrDcNullHandle), _vwV(NULL),_vwN(0) { end(); resizable(NULL); cmGrDevCtxCreate( ctx, &_dcH, &_dd.d, &_dd, x, y, w, h ); } cmGrPageFltk::~cmGrPageFltk() { if( _vwV != NULL ) { int i, n = _vwN; for(i=0; i= _vwN ) { assert( vwIdx == _vwN ); _vwV = cmMemResizeP(cmGrViewFltk*,_vwV,++_vwN); _vwV[ vwIdx ] = new cmGrViewFltk( _ctx, grH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h ); add(_vwV[vwIdx]); } else { _vwV[vwIdx]->setGrH(grH); cmGrSetPhysExtentsE(grH,&pext); } } void cmGrPageFltk::destroyView( unsigned vwIdx ) { assert( vwIdx < _vwN ); delete _vwV[vwIdx]; _vwV = NULL; } cmGrDcH_t cmGrPageFltk::devCtxHandle() { return _dcH; } cmGrViewFltk* cmGrPageFltk::viewWidget( unsigned vwIdx ) { assert( vwIdx < _vwN ); if( vwIdx < _vwN ) return _vwV[vwIdx]; return NULL; } void cmGrPageFltk::resize(int x, int y, int w, int h ) { cmGrPExt_t pext; x+=1; y+=1; w-=2; h-=2; Fl_Group::resize(x,y,w,h); // We would like to call cmGrPageLayout() here but it is not // possible because we cannot guarantee that we can get // an offscreen FLTK drawing context which needed to measure the // size of text strings given a paricular font. Instead we defer // to the draw() routine where we know the drawing context is // valid. cmGrPExtSet(&pext,x,y,w,h); cmGrPageResize(_pgH,&pext,_dcH); } void cmGrPageFltk::draw() { fl_color(FL_BACKGROUND_COLOR); fl_rectf(x(),y(),w(),h()); // if the dc is valid and the layout changed if( cmGrDevCtxIsValid(_dcH)) { if( cmGrPageLayout(_pgH,_dcH) ) { cmGrDevCtxResize( _dcH, x(), y(), w(), h() ); unsigned vwIdx; for(vwIdx=0; vwIdx<_vwN; ++vwIdx) { cmGrVwH_t vwH = cmGrPageViewHandle( _pgH, vwIdx ); cmGrViewFltk* vp = _vwV[vwIdx]; cmGrPExt_t p0ext,p1ext; assert( cmGrViewIsValid(vwH) ); // get the size of the view cmGrViewPExt( vwH, &p0ext ); // get the size of the FLTK widget containing the view cmGrPExtSet(&p1ext,vp->x(),vp->y(),vp->w(),vp->h()); // if the views are different sizes then if( !cmGrPExtIsEqual(&p0ext,&p1ext) ) vp->resize(p0ext.loc.x,p0ext.loc.y,p0ext.sz.w,p0ext.sz.h); } } cmGrDevCtxBeginDraw(_dcH); cmGrPageDraw(_pgH,_dcH); cmGrDevCtxEndDraw(_dcH); cmGrDevCtxDraw(_dcH); } draw_children(); } //-------------------------------------------------------------------------------------- cmGrPlotFltk::cmGrPlotFltk( cmCtx_t* ctx, int x, int y, int w, int h, int rn, int cn, int textSz ) : Fl_Group(x,y,w,h,NULL), _pgH(cmGrPgNullHandle),_plH(cmGrPlNullHandle), _pg(NULL),_ctl_grp(NULL),_usr_grp(NULL),_status(NULL), _hsb(NULL),_vsb(NULL), _gx(NULL),_gy(NULL),_lx(NULL),_ly(NULL), _s0x(NULL),_s0y(NULL),_s1x(NULL),_s1y(NULL),_sdx(NULL),_sdy(NULL), _textSz(textSz) { end(); // create the platform indendent page cmGrPageCreate(ctx,&_pgH,_s_cmGrCallback,this); // create the ctl panel add(_ctl_grp = _create_ctls()); // create the scroll bars _create_scroll_bars(); // create the FLTK page add(_pg = new cmGrPageFltk(ctx,_pgH,0,0,10,10)); // turn off automatic resizing - all resizing is done // explicitly in _layout(). resizable(NULL); // create the plot object manager cmGrPlotCreate(ctx,&_plH); cmGrPlotSetCb(_plH,_s_cmGrPlotObjCbFunc,this ); initViews(rn,cn); // layout the window _layout(); } cmGrPlotFltk::~cmGrPlotFltk() { cmGrPageDestroy(&_pgH); cmGrPlotDestroy(&_plH); } void cmGrPlotFltk::resize(int x, int y, int w, int h ) { Fl_Group::resize(x,y,w,h); _layout(); } cmGrPgH_t cmGrPlotFltk::pageHandle() { return _pgH; } cmGrPlH_t cmGrPlotFltk::plotHandle() { return _plH; } cmGrDcH_t cmGrPlotFltk::dcHandle() { return _pg->devCtxHandle(); } void cmGrPlotFltk::initViews( int rn, int cn ) { if( cmGrPageIsValid(_pgH) && _pg != NULL ) { cmGrPExt_t pext; cmGrPExtSet(&pext,_pg->x(),_pg->y(),_pg->w(),_pg->h()); cmGrPageInit( _pgH, &pext, rn, cn, _pg->devCtxHandle() ); } } void cmGrPlotFltk::setStatusText( const cmChar_t* text ) { _status->value(text); } void cmGrPlotFltk::on_button( unsigned id ) { cmGrH_t grH; if( !cmGrIsValid(grH = _getFocusedView()) ) return; switch( id ) { case kShowAllId: cmGrZoom( grH, kShowAllGrFl | kXAxisGrFl | kYAxisGrFl ); break; case kZoomInId: cmGrZoom( grH, kZoomInGrFl | kXAxisGrFl | kYAxisGrFl | kSelectGrFl ); break; case kZoomInXId: cmGrZoom( grH, kZoomInGrFl | kXAxisGrFl | kSelectGrFl ); break; case kZoomInYId: cmGrZoom( grH, kZoomInGrFl | kYAxisGrFl | kSelectGrFl ); break; case kZoomOutId: cmGrZoom( grH, kXAxisGrFl | kYAxisGrFl | kSelectGrFl ); break; case kZoomOutXId: cmGrZoom( grH, kXAxisGrFl | kSelectGrFl ); break; case kZoomOutYId: cmGrZoom( grH, kYAxisGrFl | kSelectGrFl ); break; case kReportId: cmGrReport( grH, NULL ); break; } } void cmGrPlotFltk::on_scroll( Fl_Scrollbar* sb, unsigned id ) { bool fl = false; cmGrH_t grH = cmGrNullHandle; if( cmGrIsValid(grH = _getFocusedView()) ) { switch( id ) { case kHScrollId: fl = cmGrSetScrollH( grH, sb->value() ); break; case kVScrollId: fl = cmGrSetScrollV( grH, (sb->maximum() - sb->slider_size()) + 1 - sb->value() ); break; } } if( fl ) { _pg->redraw(); } } void cmGrPlotFltk::on_view_create( unsigned viewIdx ) { if( _pg != NULL ) _pg->createView(viewIdx); } void cmGrPlotFltk::on_view_destroy( unsigned viewIdx ) { if( _pg != NULL ) _pg->destroyView(viewIdx); } void cmGrPlotFltk::rpt_local_pt( cmGrH_t grH ) { int bufCharCnt = 31; cmChar_t buf[ bufCharCnt ]; cmGrVwH_t vwH = cmGrPageViewHandle( _pgH, cmGrId(grH) ); const cmChar_t* cp = NULL ; if( _lx != NULL ) { _lx->value( cp = cmGrViewValue( vwH, kLocalX_VwId, buf, bufCharCnt)); _lx->redraw(); } if( _ly != NULL ) { _ly->value( cp = cmGrViewValue( vwH, kLocalY_VwId, buf, bufCharCnt)); _ly->redraw(); } } void cmGrPlotFltk::rpt_global_pt( cmGrH_t grH ) { int bufCharCnt = 31; cmChar_t buf[ bufCharCnt ]; cmGrVwH_t vwH = cmGrPageViewHandle( _pgH, cmGrId(grH) ); if( _gx != NULL ) { _gx->value( cmGrViewValue( vwH, kGlobalX_VwId, buf, bufCharCnt)); _gx->redraw(); } if( _gy != NULL ) { _gy->value( cmGrViewValue( vwH, kGlobalY_VwId, buf, bufCharCnt)); _gy->redraw(); } } void cmGrPlotFltk::on_phys_change( cmGrH_t grH ) { cmGrViewFltk* vwp = _pg->viewWidget( cmGrId( grH ) ); if( vwp != NULL ) { cmGrPExt_t pext; cmGrPhysExtents(grH,&pext); vwp->resize( pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h ); } } void cmGrPlotFltk::on_view_change(cmGrH_t grH) { unsigned vwIdx = cmGrId(grH); cmGrViewFltk* vwp; if( cmGrViewHasFocus( cmGrPageGrHandleToView(_pgH,grH) ) ) { cmGrPSz_t tot,vis,max; cmGrPPt_t pos; _showHideScrollBars(); cmGrScrollExtents(grH,&tot,&vis,&max,&pos); _hsb->value(pos.x,vis.w,0,tot.w); pos.y = (tot.h - vis.h) + 1 - pos.y; // invert vert slider _vsb->value(pos.y,vis.h,0,tot.h); } // update the hash labels if((vwp = _pg->viewWidget( vwIdx )) != NULL ) vwp->redraw(); } void cmGrPlotFltk::on_select_change(cmGrH_t grH) { cmGrViewFltk* vwp; unsigned vwIdx = cmGrId(grH); if( cmGrViewHasFocus( cmGrPageGrHandleToView(_pgH,grH) ) ) { int bufCharCnt = 31; cmChar_t buf[ bufCharCnt ]; cmGrVwH_t vwH = cmGrPageViewHandle( _pgH, vwIdx ); _s0x->value(cmGrViewValue( vwH, kSelX0_VwId, buf, bufCharCnt)); _s0x->redraw(); _s0y->value(cmGrViewValue( vwH, kSelY0_VwId, buf, bufCharCnt)); _s0y->redraw(); _s1x->value(cmGrViewValue( vwH, kSelX1_VwId, buf, bufCharCnt)); _s1x->redraw(); _s1y->value(cmGrViewValue( vwH, kSelY1_VwId, buf, bufCharCnt)); _s1y->redraw(); _sdx->value(cmGrViewValue( vwH, kSelW_VwId, buf, bufCharCnt)); _sdx->redraw(); _sdy->value(cmGrViewValue( vwH, kSelH_VwId, buf, bufCharCnt)); _sdy->redraw(); } if((vwp = _pg->viewWidget( vwIdx )) != NULL ) vwp->redraw(); } void cmGrPlotFltk::on_focused_plot( cmGrH_t grH) { on_view_change(grH); redraw(); } void cmGrPlotFltk::on_key_event( cmGrH_t grH, unsigned eventFlags, cmGrKeyCodeId_t keycode ) { cmGrPlotKeyEvent( _plH, grH, eventFlags, keycode ); } bool cmGrPlotFltk::on_plot_object( cmGrPlotCbArg_t* arg ) { return true; } void cmGrPlotFltk::_layout() { // position the vertical scroll bar _vsb->position(x()+w()-_vsb->w(),y()); _vsb->size(_vsb->w(),h()-_hsb->h()); // position the horizontal scroll bar _hsb->position(x(),y()+h()-_hsb->h()); _hsb->size(w()-_vsb->w(),_hsb->h()); // position the ctl panel _ctl_grp->position(x(),_hsb->y()-_ctl_grp->h()); _ctl_grp->size(w()-_vsb->w(),_ctl_grp->h()); // position the user programmable group _usr_grp->size(_ctl_grp->w()-_usr_grp->x()-1,_usr_grp->h()); // position the status ctl _status->size(_ctl_grp->w()-_status->x()-1,_status->h()); // position the page _pg->resize(x(),y(),w()-_vsb->w(),_ctl_grp->y()-y()); } Fl_Group* cmGrPlotFltk::_create_ctls() { Fl_Boxtype outBoxFlags = FL_FLAT_BOX; Fl_Group* grp = new Fl_Group(0,0,10,10); grp->user_data(this); grp->box(FL_FLAT_BOX); grp->end(); int x0 = kVBord; int y0 = kHBord; int x1 =0; int x = x0; int y = y0; Fl_Button* btn; btn = new Fl_Button(x,y,kBtnW,kBtnH,"All"); btn->callback(_s_ctl_cb,kShowAllId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"In"); btn->callback(_s_ctl_cb,kZoomInId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"In X"); btn->callback(_s_ctl_cb,kZoomInXId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"Out X"); btn->callback(_s_ctl_cb,kZoomOutXId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kLblW+kVBord; _gx = new Fl_Output(x,y+1,kOutW,kBtnH-2,"gx"); _gx->box(outBoxFlags); _gx->color(FL_LIGHT2); _gx->labelsize(_textSz); _gx->textsize(_textSz); grp->add(_gx); x += kOutW+kLblW+kVBord; _lx = new Fl_Output(x,y+1,kOutW,kBtnH-2,"lx"); _lx->box(outBoxFlags); _lx->color(FL_LIGHT2); _lx->labelsize(_textSz); _lx->textsize(_textSz); grp->add(_lx); x += kOutW+kLblW+kVBord; _s0x = new Fl_Output(x,y+1,kOutW,kBtnH-2,"sx"); _s0x->box(outBoxFlags); _s0x->color(FL_LIGHT2); _s0x->labelsize(_textSz); _s0x->textsize(_textSz); grp->add(_s0x); x += kOutW+kLblW+kVBord; _s1x = new Fl_Output(x,y+1,kOutW,kBtnH-2,"sx"); _s1x->box(outBoxFlags); _s1x->color(FL_LIGHT2); _s1x->labelsize(_textSz); _s1x->textsize(_textSz); grp->add(_s1x); x += kOutW+kLblW+kVBord; _sdx = new Fl_Output(x,y+1,kOutW,kBtnH-2,"dsx"); _sdx->box(outBoxFlags); _sdx->color(FL_LIGHT2); _sdx->labelsize(_textSz); _sdx->textsize(_textSz); grp->add(_sdx); x += kOutW+kVBord; x1 = x; x = x0; y += kBtnH+kHBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"Rpt"); btn->callback(_s_ctl_cb,kReportId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"Out"); btn->callback(_s_ctl_cb,kZoomOutId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"In Y"); btn->callback(_s_ctl_cb,kZoomInYId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kVBord; btn = new Fl_Button(x,y,kBtnW,kBtnH,"Out Y"); btn->callback(_s_ctl_cb,kZoomOutYId); btn->labelsize(_textSz); grp->add(btn); x += kBtnW+kLblW+kVBord; _gy = new Fl_Output(x,y+1,kOutW,kBtnH-2,"gy"); _gy->box(outBoxFlags); _gy->color(FL_LIGHT2); _gy->labelsize(_textSz); _gy->textsize(_textSz); grp->add(_gy); x += kOutW+kLblW+kVBord; _ly = new Fl_Output(x,y+1,kOutW,kBtnH-2,"ly"); _ly->box(outBoxFlags); _ly->color(FL_LIGHT2); _ly->labelsize(_textSz); _ly->textsize(_textSz); grp->add(_ly); x += kOutW+kLblW+kVBord; _s0y = new Fl_Output(x,y+1,kOutW,kBtnH-2,"sy"); _s0y->box(outBoxFlags); _s0y->color(FL_LIGHT2); _s0y->labelsize(_textSz); _s0y->textsize(_textSz); grp->add(_s0y); x += kOutW+kLblW+kVBord; _s1y = new Fl_Output(x,y+1,kOutW,kBtnH-2,"sy"); _s1y->box(outBoxFlags); _s1y->color(FL_LIGHT2); _s1y->labelsize(_textSz); _s1y->textsize(_textSz); grp->add(_s1y); x += kOutW+kLblW+kVBord; _sdy = new Fl_Output(x,y+1,kOutW,kBtnH-2,"dsy"); _sdy->box(outBoxFlags); _sdy->color(FL_LIGHT2); _sdy->labelsize(_textSz); _sdy->textsize(_textSz); grp->add(_sdy); x += kOutW+kVBord; x1 = cmMax(x1,x); x = x0; y += kBtnH+kHBord; _status = new Fl_Output(x,y+1,x1-x0,kBtnH-2); _status->box(FL_FLAT_BOX); _status->color(FL_LIGHT2); _status->textsize(_textSz); grp->add(_status); _usr_grp = new Fl_Group(x1,y0,x1-x0,y-y0); _usr_grp->end(); _usr_grp->box(FL_FLAT_BOX); grp->add(_usr_grp); x = x0; y += kBtnH+kHBord; grp->resizable(NULL); grp->resize(grp->x(),grp->y(),x1-grp->x(),y-grp->y()); return grp; } void cmGrPlotFltk::_create_scroll_bars() { // vert scroll bar _vsb = new Fl_Scrollbar(x()+w()-kScrD, y(), kScrD, h()-kScrD, NULL); _vsb->type(FL_VERTICAL); _vsb->callback(_s_ctl_cb,kVScrollId); add(_vsb); // horz scrollback _hsb = new Fl_Scrollbar(x(),y()+h()-kScrD, w()-kScrD, kScrD, NULL); _hsb->type(FL_HORIZONTAL); _hsb->callback(_s_ctl_cb,kHScrollId); add(_hsb); _showHideScrollBars(); } void cmGrPlotFltk::_showHideScrollBars() { bool hfl = true, vfl=true; cmGrH_t grH; if( cmGrIsValid(grH = _getFocusedView()) == false ) hfl = vfl = false; else { cmGrPSz_t tot, vis; cmGrScrollExtents(grH, &tot, &vis, NULL, NULL ); vfl = tot.h != vis.h; hfl = tot.w != vis.w; } if( hfl != _hsb->visible() ) hfl ? _hsb->show() : _hsb->hide(); if( vfl != _vsb->visible() ) vfl ? _vsb->show() : _vsb->hide(); } cmGrH_t cmGrPlotFltk::_getFocusedView() { cmGrVwH_t vwH = cmGrPageFocusedView(_pgH); if( cmGrViewIsValid(vwH) == false ) return cmGrNullHandle; return cmGrViewGrHandle( vwH ); } void cmGrPlotFltk::_s_ctl_cb(Fl_Widget* wp, long id ) { switch( id ) { case kHScrollId: case kVScrollId: { cmGrPlotFltk* p = static_cast(wp->parent()); p->on_scroll( (Fl_Scrollbar*)wp, id ); } break; case kShowAllId: case kReportId: case kZoomInId: case kZoomOutId: case kZoomInXId: case kZoomInYId: case kZoomOutXId: case kZoomOutYId: { cmGrPlotFltk* p = (cmGrPlotFltk*)wp->parent()->user_data(); p->on_button( id ); } break; } } void cmGrPlotFltk::_s_cmGrCallback( void* arg, cmGrH_t grH, cmGrCbId_t id, unsigned eventFlags, cmGrKeyCodeId_t keycode ) { cmGrPlotFltk* p = (cmGrPlotFltk*)arg; switch(id) { case kCreateCbGrId: p->on_view_create( cmGrId(grH)); break; case kDestroyCbGrId: p->on_view_destroy(cmGrId(grH)); break; case kLocalPtCbGrId: p->rpt_local_pt( grH ); break; case kGlobalPtCbGrId: p->rpt_global_pt(grH ); break; case kPhysExtCbGrId: p->on_phys_change( grH ); break; case kViewExtCbGrId: p->on_view_change( grH ); break; case kSelectExtCbGrId:p->on_select_change(grH); break; case kFocusCbGrId: p->on_focused_plot(grH); break; case kKeyUpCbGrId: p->on_key_event( grH, eventFlags, keycode ); break; case kKeyDnCbGrId: p->on_key_event( grH, eventFlags, keycode ); break; default: { assert(0); } } } bool cmGrPlotFltk::_s_cmGrPlotObjCbFunc( cmGrPlotCbArg_t* arg ) { cmGrPlotFltk* p = (cmGrPlotFltk*)arg->cbArg; return p->on_plot_object(arg); }