Initial commit

This commit is contained in:
kpl 2012-10-30 12:42:21 -07:00
parent 015929c965
commit 7e8b9b5570
9 changed files with 1154 additions and 45 deletions

View File

@ -15,7 +15,7 @@ AM_CPPFLAGS = -D _GNU_SOURCE -I.. -I$(srcdir)/src/libcm -I$(srcdir)/src/libcm/
AM_CFLAGS = -Wno-multichar AM_CFLAGS = -Wno-multichar
AM_CXXFLAGS = AM_CXXFLAGS =
AM_LDFLAGS = AM_LDFLAGS =
MYLIBS = -lpthread -lfftw3f -lfftw3 MYLIBS = -lpthread -lfftw3f -lfftw3 -lfltk
CMLIBS = src/libcm/libcm.la # autoconfig manual recommends storing direct referenes to non-3rd party libraries rather than using -L and -l CMLIBS = src/libcm/libcm.la # autoconfig manual recommends storing direct referenes to non-3rd party libraries rather than using -L and -l
@ -56,6 +56,7 @@ include_HEADERS += $(cmHDR)
lib_LTLIBRARIES += src/libcm/libcm.la lib_LTLIBRARIES += src/libcm/libcm.la
src_proj_proj_SOURCES = src/proj/main.c src_cmflapp_cmflapp_SOURCES = src/cmflapp/main.cpp src/cmflapp/app.h src/cmflapp/app.cpp
src_proj_proj_LDADD = $(CMLIBS) $(MYLIBS) src_cmflapp_cmflapp_SOURCES += src/cmflapp/Fl_Splitter.h src/cmflapp/Fl_Splitter.cpp
bin_PROGRAMS += src/proj/proj src_cmflapp_cmflapp_LDADD = $(CMLIBS) $(MYLIBS)
bin_PROGRAMS += src/cmflapp/cmflapp

View File

@ -3,10 +3,10 @@
# this configure.ac or any of the Makefile.am files. # this configure.ac or any of the Makefile.am files.
# #
AC_INIT([proj],[1.0],[proj@larke.org]) AC_INIT([cmflapp],[1.0],[cmflapp@larke.org])
AC_CONFIG_AUX_DIR([build-aux]) # put aux files in build-aux AC_CONFIG_AUX_DIR([build-aux]) # put aux files in build-aux
AM_INIT_AUTOMAKE([1.9 -Wall foreign subdir-objects]) # subdir-objects needed for non-recursive make AM_INIT_AUTOMAKE([1.9 -Wall foreign subdir-objects]) # subdir-objects needed for non-recursive make
AC_CONFIG_SRCDIR([src/proj/main.c]) AC_CONFIG_SRCDIR([src/cmflapp/main.cpp])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

265
src/cmflapp/Fl_Splitter.cpp Normal file
View File

@ -0,0 +1,265 @@
// Code based on: http://www.mail-archive.com/fltk@easysw.com/msg04573.html
// Lucas Sanner/Ian MacArthur
#include "Fl_Splitter.h"
void Fl_HSplitter::draw()
{
Fl_Group::draw();
fl_color(FL_BLACK);
fl_line_style( FL_DOT, 1);
if(bSplit && Fl::event_button1() != 0)
{
fl_push_clip(x(), y(), w(), h());
yPos = Fl::event_y();
if(Fl::event_y() > h() - (border * 2))
yPos = h() - (border * 2);
if(Fl::event_y() < y() + (border * 2))
yPos = y() + (border * 2);
fl_line( x() + border, yPos - 1, x() + w() - (border*2), yPos - 1 );
fl_line( x() + border, yPos , x() + w() - (border*2), yPos );
fl_line( x() + border, yPos + 1, x() + w() - (border*2), yPos + 1 );
/*
fl_line(
x() + border,
yPos,
x() + w() - (border*2),
yPos );
fl_line(
x() + border,
yPos + 1,
x() + w() - (border*2),
yPos + 1 );
*/
fl_pop_clip();
}
else
{
fl_push_clip(x(), y(), w(), h());
fl_pop_clip();
}
}
int Fl_HSplitter::handle(int e)
{
int ret = Fl_Group::handle(e);
switch(e)
{
case FL_MOVE:
if(Fl::event_y() > hCtnl - border && Fl::event_y() < hCtnl + border)
{
fl_cursor(FL_CURSOR_NS);
bSplit = true;
}
else
{
fl_cursor(FL_CURSOR_DEFAULT);
bSplit = false;
}
return 1;
case FL_PUSH:
if(Fl::event_button() == FL_LEFT_MOUSE && bSplit)
{
redraw();
}
return 1;
case FL_RELEASE:
if(Fl::event_button() == FL_LEFT_MOUSE && bSplit)
{
container1->resize(x(), y(), w(), yPos - y());
hCtnl = yPos;
container2->resize(x(),hCtnl, w(), h() - (yPos - y()));
if( stretchTopFl )
init_sizes();
bSplit = false;
redraw();
}
return 1;
case FL_DRAG:
if(bSplit && Fl::event_state(FL_BUTTON1) != 0)
redraw();
return 1;
}
return(ret);
}
Fl_HSplitter::Fl_HSplitter(int x, int y, int w, int h, int h1, const char *l, bool stretchBotFl)
: Fl_Group(x, y, w, h, l)
{
int h2 = h - h1;
begin();
container1 = new Splitter_Container(x, y, w, h1);
//container1->color((Fl_Color) FL_RED);
end();
begin();
container2 = new Splitter_Container(x, y + h1, w, h2);
//container2->color((Fl_Color) FL_BLUE);
end();
hCtnl = y + h1;
bSplit = false;
stretchTopFl = !stretchBotFl;
border = Fl::box_dy(FL_DOWN_BOX);
if( stretchTopFl )
resizable(container1);
}
void Fl_HSplitter::resize_splitter(int x, int y, int w, int h)
{
resize(x, y, w, h);
if( stretchTopFl )
{
hCtnl = container1->h() + y;
yPos = hCtnl;
}
else
{
container1->resize(x, y, w, hCtnl - y);
container2->resize(x, hCtnl, w, h - (hCtnl - y));
}
}
void Fl_VSplitter::draw()
{
Fl_Group::draw();
fl_color(FL_BLACK);
fl_line_style( FL_DOT, 1);
if(bSplit && Fl::event_button1() != 0)
{
fl_push_clip(x(), y(), w(), h());
xPos = Fl::event_x();
if(Fl::event_x() > w() - (border * 2))
xPos = w() - (border * 2);
if(Fl::event_x() < x() + (border * 2))
xPos = x() + (border * 2);
fl_line(xPos - 1, y() + border, xPos - 1, y() + h() - (border * 2));
fl_line(xPos, y() + border, xPos, y() + h() - (border * 2));
fl_line(xPos + 1, y() + border, xPos + 1, y() + h() - (border * 2));
fl_pop_clip();
}
else
{
fl_push_clip(x(), y(), w(), h());
fl_pop_clip();
}
}
int Fl_VSplitter::handle(int e)
{
int ret = Fl_Group::handle(e);
switch(e)
{
case FL_MOVE:
if(Fl::event_x() > wCtn1 - border && Fl::event_x() < wCtn1 + border)
{
fl_cursor(FL_CURSOR_WE);
bSplit = true;
}
else
{
fl_cursor(FL_CURSOR_DEFAULT);
bSplit = false;
}
return 1;
case FL_PUSH:
if(Fl::event_button() == FL_LEFT_MOUSE && bSplit)
{
redraw();
}
return 1;
case FL_RELEASE:
if(Fl::event_button() == FL_LEFT_MOUSE && bSplit)
{
container1->resize(x(), y(), xPos, h());
wCtn1 = xPos;
container2->resize(wCtn1, y(), w() - wCtn1, h());
bSplit = false;
redraw();
}
return 1;
case FL_DRAG:
if(bSplit && Fl::event_state(FL_BUTTON1) != 0)
redraw();
return 1;
}
return(ret);
}
Fl_VSplitter::Fl_VSplitter(int x, int y, int w, int h, const char *l)
: Fl_Group(x, y, w, h, l)
{
begin();
container1 = new Splitter_Container(x, y, w / 2, h);
//container1->color((Fl_Color) FL_RED);
end();
begin();
container2 = new Splitter_Container(x + (w / 2), y, w / 2, h);
//container2->color((Fl_Color) FL_BLUE);
end();
wCtn1 = w / 2;
bSplit = false;
border = Fl::box_dx(FL_DOWN_BOX);
}
void Fl_VSplitter::resize_splitter(int x, int y, int w, int h)
{
resize(x, y, w, h);
container1->resize(x, y, wCtn1, h);
container2->resize(wCtn1, y, w - wCtn1, h);
}

74
src/cmflapp/Fl_Splitter.h Normal file
View File

@ -0,0 +1,74 @@
// Code based on: http://www.mail-archive.com/fltk@easysw.com/msg04573.html
// Lucas Sanner/Ian MacArthur
#ifndef Fl_Splitter_h
#define Fl_Splitter_h
#include <FL/Fl.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Box.H>
#include <FL/fl_draw.H>
class Splitter_Container : public Fl_Group
{
void draw()
{
fl_push_clip(x(), y(), w(), h());
Fl_Group::draw();
fl_pop_clip();
}
public:
Splitter_Container(int x, int y, int w, int h, char *l = NULL)
: Fl_Group(x, y, w, h, l)
{
//box(FL_DOWN_BOX);
}
};
class Fl_HSplitter : public Fl_Group
{
int hCtnl, border, yPos;
bool bSplit;
bool stretchTopFl; // set to make top container stretch when splitter is resized
int hh2;
void draw();
int handle(int e);
public:
Splitter_Container *container1, *container2;
Fl_HSplitter(int x, int y, int w, int h, int h1, const char *l=NULL, bool stretchBotFl=false);
void resize_splitter(int x, int y, int w, int h);
};
class Fl_VSplitter : public Fl_Group
{
int wCtn1, border, xPos;
bool bSplit;
void draw();
int handle(int e);
public:
Splitter_Container *container1, *container2;
Fl_VSplitter(int x, int y, int w, int h, const char *l = NULL);
void resize_splitter(int x, int y, int w, int h);
};
#endif

555
src/cmflapp/app.cpp Normal file
View File

@ -0,0 +1,555 @@
#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Text_Buffer.H>
#include <FL/Fl_Text_Display.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Value_Input.H>
#include <FL/Fl_Value_Slider.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/fl_draw.H>
#include "Fl_Splitter.h"
#include "cmPrefix.h"
#include "cmGlobal.h"
#include "cmRpt.h"
#include "cmErr.h"
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmFileSys.h"
#include "cmThread.h"
#include "appErr.h"
#include "app.h"
class drawWnd : public Fl_Widget
{
public:
drawWnd(app* ap, int x, int y, int w, int h, const char* label = NULL );
virtual ~drawWnd();
virtual int handle(int event);
virtual void resize(int x, int y, int w, int h );
protected:
virtual void draw();
private:
app* _app;
};
drawWnd::drawWnd(app* ap, int x, int y, int w, int h, const char* label )
: Fl_Widget(x,y,w,h,label),
_app(ap)
{}
drawWnd::~drawWnd()
{}
int drawWnd::handle(int event)
{
switch(event)
{
case FL_PUSH:
{
const char* label;
switch( Fl::event_button() )
{
case FL_LEFT_MOUSE: label = "left"; break;
case FL_RIGHT_MOUSE: label = "right"; break;
case FL_MIDDLE_MOUSE: label = "middle"; break;
default:
label = "none";
}
_app->print("%i %i %s\n",Fl::event_x(),Fl::event_y(),label);
}
break;
default:
return Fl_Widget::handle(event);
}
return 1;
}
void drawWnd::resize(int x, int y, int w, int h )
{
// must call base to make size change
Fl_Widget::resize(x,y,w,h);
}
void drawWnd::draw()
{
int offs = 10;
//fl_draw_box(FL_DOWN_BOX,x()+10,y()+10,w()-20,h()-20,FL_RED);
//fl_frame("XXXX",x()+offs,y()+offs,w()-2*offs,h()-2*offs);
fl_line_style(FL_SOLID,1,NULL);
fl_color(FL_RED);
fl_line(x()+offs,y()+offs,x()+w()-offs,y()+h()-offs);
int x = w()/2;
int y = h()/2;
fl_color(FL_BLACK);
fl_draw(90,"string",x,y);
// XXXXXXX
// X00000X
// X00000X
// X00X00X
// X00000X
// X00000X
// XXXXXXX
fl_rect(x-3,y-3,7,7);
fl_point(x,y);
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
app::app(cmCtx_t* ctx, cmTsMp1cH_t printqH, int w, int h, const char* label, int argc, char* argv[])
: Fl_Double_Window(w,h,label), _timerPeriodSecs(0),
_ctx(ctx), _splt(NULL),_buf(NULL),_con(NULL),_tabs(NULL),_menu(NULL),
_printqH(printqH),_printFl(0)
{
// install a callback to cleanup when the app window closes
// (the btn and menu callbacks also rely on a pointer to 'this' being found in app.user_data()
// see _getApp())
callback(_s_callback,this);
// the main window is divided between the menu bar on top
// and a horizontal splitter on the bottom
begin();
createMenu(w,kMenuH);
_splt = new Fl_HSplitter(0, kMenuH, w, h-kStatusH, h-kStatusH-100);
end();
// Create a text display object for console output and
// add it to the lower splitter area
_buf = new Fl_Text_Buffer();
_con = new Fl_Text_Display(_splt->container2->x(),_splt->container2->y(),_splt->container2->w(),_splt->container2->h());
_con->buffer(_buf);
_splt->container2->add(_con);
// create tabbed windows
const char* titles[] = { "Title 1", "Title 2" };
_create_tabs(2,titles);
// make the splitter the resizable group element (thereby making the menu non-resizable).
// see:http://fltk.org/articles.php?L415+I0+T+M1000+P1
resizable(_splt);
show(argc, argv);
// The application is now visible.
// direct all output to the console window
cmRptSetup(&_ctx->rpt,_s_print,_s_print, this);
cmTsMp1cSetCbFunc(_printqH, _s_print_queue_cb, this );
// install a timer
_timerPeriodSecs = 0.1;
Fl::add_timeout(_timerPeriodSecs,app::_s_timer_cb,this);
// install an idle callback
//Fl::add_idle(_s_idle_cb,this);
print("Started!\n");
}
app::~app()
{}
void app::createControls(Fl_Group* grp)
{
const int vBord = 3;
const int ctl_width = 100;
int xx = grp->x() + 5;
int yy = grp->y() + vBord;
Fl_Check_Button* cbt = new Fl_Check_Button(xx,yy,ctl_width,kCtlH,"Check");
cbt->callback( _s_btn_cb, kBtn1MId );
yy += cbt->h() + vBord;
Fl_Button* btn = new Fl_Button(xx,yy,ctl_width,kCtlH,"Button");
btn->callback( _s_btn_cb, kBtn2MId );
yy += btn->h() + vBord;
// menu buttons callback through menuCallback() not btnCallback()
Fl_Menu_Button* mbt = new Fl_Menu_Button(xx,yy,ctl_width,kCtlH,"Menu");
mbt->add("Item 1",0,_s_menu_btn_cb, (void*)kMenuBtn1MId, 0);
mbt->add("Item 2",0,_s_menu_btn_cb, (void*)kMenuBtn2MId, 0);
yy += mbt->h() + vBord;
Fl_Value_Input* vip = new Fl_Value_Input(xx,yy,ctl_width/2,kCtlH,"Value In");
vip->callback(_s_value_cb, kValue1MId );
vip->align(FL_ALIGN_RIGHT); // place label to the right of the input ctl
// Only make the callback when the enter key is struck or the ctl loses focus and the value has changed.
// Removing this line causes the callback whenever the input changes.
vip->when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE );
vip->bounds(-10.0,10.0);
vip->step(0.1);
yy += vip->h() + vBord;
Fl_Value_Slider* sdp = new Fl_Value_Slider(xx,yy,ctl_width,kCtlH,"Slider");
sdp->callback(_s_value_cb, kValue2MId );
sdp->align(FL_ALIGN_RIGHT);
sdp->type(FL_HOR_NICE_SLIDER);
sdp->bounds(-10.0,10.0);
sdp->step(0.1);
yy += sdp->h() + vBord;
Fl_Input* inp = new Fl_Input(xx,yy,ctl_width/2,kCtlH,"Text");
inp->callback(_s_input_cb,kInput1MId);
inp->align(FL_ALIGN_RIGHT);
yy += inp->h() + vBord;
}
void app::initializeTab(int tabIndex, int x, int y, int w, int h, const char* label)
{
switch(tabIndex)
{
case 0:
{
Fl_Group* grp = new Fl_Group(x,y,w,h,label);
grp->begin();
createControls(grp);
grp->end();
}
break;
case 1:
{
Fl_Group* grp = new Fl_Group(x,y,w,h,label);
grp->begin();
_draw = new drawWnd(this,x,y,w,h,NULL);
grp->end();
}
break;
}
}
void app::createMenu(int w, int h)
{
Fl_Menu_Item items[] =
{
{ "&File", 0, 0, 0, FL_SUBMENU },
{ "&New File", FL_COMMAND + 'n', (Fl_Callback*)_s_menu_cb, (void*)kFileNewMId },
{ "&Open File", FL_COMMAND + 'o', (Fl_Callback*)_s_menu_cb, (void*)kFileOpenMId },
{ 0 },
{ "&Edit", 0, 0, 0, FL_SUBMENU },
{ "&Copy", FL_COMMAND + 'c', (Fl_Callback*)_s_menu_cb, (void*)kEditCopyMId },
{ "&Paste", FL_COMMAND + 'v', (Fl_Callback*)_s_menu_cb, (void*)kEditPasteMId },
{ 0 },
{ 0 }
};
_menu = new Fl_Menu_Bar(0,0,w,h);
_menu->copy(items);
}
void app::menuCallback(const Fl_Menu_Item* mip, long int id)
{
switch(id)
{
case kFileOpenMId:
{
// file chooser demo
const char* pathStr = cmFsUserDir(); // make the default dir the user's home dir
const char patStr[] = "Text Files (*.txt)\tAudio Files (*.{wav,aif,aiff})"; // All Files (*.*) is append to this automatically
const char titleStr[] = "Select files";
Fl_File_Chooser fc = Fl_File_Chooser(pathStr,patStr,Fl_File_Chooser::MULTI,titleStr);
fc.preview(0); // default the previous option to 'off'.
fc.show(); // show the chooser
// make the chooser modal
while( fc.shown() )
Fl::wait();
// print the selected files
int i;
for(i=1; i<=fc.count(); ++i)
print("%i %s\n",i,cmStringNullGuard(fc.value(i)));
}
break;
}
print("%i %s\n",id,mip->label());
}
void app::btnCallback(const Fl_Button* bp, int id )
{
print("%i %s %i\n",id,bp->label(),bp->value());
}
void app::valueCallback(const Fl_Valuator* vp, int id )
{
print("%i %s %f\n",id,vp->label(),vp->value());
}
void app::inputCallback(const Fl_Input* ip, int id )
{
print("%i %s %s\n",id,ip->label(),ip->value());
}
void app::appCallback(Fl_Widget* wp)
{
switch( Fl::event() )
{
case FL_CLOSE:
{
/*
int cc = _closeCnt;
// attempt to shut down the pgm
_closeCnt += finalizePgm() == false;
// the first time the pgm fails to shut down
// do not allow the pgm to close the main window
// this will give a chance for the error messages
// to be diplayed in the console - all successive
// times the return value from finalizePgm() is
// ignored and the program is terminated.
if( _closeCnt == 1 && cc==0)
{
// send a strong hint that a problem occurred on shutdown
// and prevent the app from receiving events that might cause it to
// crash
deactivate();
return;
}
*/
// When all windows are windows are closed then the app.
// will close - so hiding the application window
// causes the program to close.
//
// Note that simply returning from this callback will
// prevent the application from closing. Because the existence
// of the callback alone is enough to disable default
// event handling.
hide();
}
break;
}
}
bool app::idleCallback()
{ return true; }
bool app::timerCallback()
{
_checkPrintQueue();
return true;
}
void app::error( const char* fmt, ... )
{
va_list vl;
va_start(vl,fmt);
int bufCharCnt = 511;
char buf[bufCharCnt+1];
int n = vsnprintf(buf,bufCharCnt,fmt,vl);
if( n > 0 )
print("%s Error: %s\n",label(),buf);
va_end(vl);
}
void app::vprint(const char* fmt, va_list vl )
{
int bufCharCnt = 511;
char buf[bufCharCnt+1];
int n = vsnprintf(buf,bufCharCnt,fmt,vl);
if( n > 0 )
{
// if the print queue exists (it might not during startup or shutdown) ...
if( cmTsMp1cIsValid(_printqH) )
{
cmThRC_t thRC;
// ... enqueue the text to print
if((thRC = cmTsMp1cEnqueueMsg(_printqH,buf,n+1)) != kOkThRC && _printFl==0 )
{
// Print queue error msg's directly to stdout rather than throught
// the error mechanism - this prevents generating a stack overflow
// when the print queue runs out of space and attempts to print a
// 'queue out of memory' error msg.
// The queue itself does will not print errors because it does
// not have a valid cmRpt_t pointer. See cmMp1cCreate() above.
++_printFl;
cmErrMsg(&_ctx->err,kQueueFailAppRC,"Print enqueue failed.");
--_printFl;
}
}
else
_print(buf); // ... otherwise just send the text directly to the output console
}
}
void app::print( const char* fmt, ... )
{
va_list vl;
va_start(vl,fmt);
vprint(fmt,vl);
va_end(vl);
}
void app::_s_menu_cb(Fl_Widget* wp, void* data)
{
const Fl_Menu_Item* mip;
app* ap;
if((ap=_getApp(wp)) != NULL )
if((mip = ap->_menu->mvalue()) != NULL )
ap->menuCallback(mip,(long int)mip->user_data());
}
void app::_s_menu_btn_cb(Fl_Widget* wp, void* data)
{
const Fl_Menu_Button* bp;
const Fl_Menu_Item* mip;
app* ap;
if((ap=_getApp(wp)) != NULL )
if((bp = static_cast<Fl_Menu_Button*>(wp)) != NULL )
if((mip = bp->mvalue()) != NULL)
ap->menuCallback(mip,(long int)data);
}
void app::_s_btn_cb(Fl_Widget* wp, long data )
{
app* ap;
if((ap = _getApp(wp)) != NULL )
if( wp != NULL )
ap->btnCallback( static_cast<const Fl_Button*>(wp),data);
}
void app::_s_value_cb( Fl_Widget* wp, long data)
{
app* ap;
Fl_Valuator* vp;
if((ap = _getApp(wp)) != NULL )
if((vp = static_cast<Fl_Valuator*>(wp)) != NULL)
ap->valueCallback(vp,data);
}
void app::_s_input_cb( Fl_Widget* wp, long data)
{
app* ap;
Fl_Input* inp;
if((ap = _getApp(wp)) != NULL)
if((inp = static_cast<Fl_Input*>(wp)) != NULL )
ap->inputCallback(inp,data);
}
void app::_s_callback(Fl_Widget* wp, void* data)
{ ((app*)data)->appCallback(wp); }
void app::_s_idle_cb(void *data)
{
app* thisPtr = (app*)data;
if( thisPtr->idleCallback() == false )
Fl::remove_idle(_s_idle_cb,data);
}
void app::_s_timer_cb(void* userPtr)
{
app* thisPtr = (app*)userPtr;
if( thisPtr->timerCallback() )
Fl::repeat_timeout(thisPtr->_timerPeriodSecs,_s_timer_cb,userPtr);
}
void app::_s_print( void* userPtr, const char* text )
{ ((app*)userPtr)->print(text); }
void app::_create_tabs(int titleCnt, const char* titleArray[])
{
// Create a tab view and added it to the upper splitter area
_tabs = new Fl_Tabs(_splt->container1->x(),_splt->container1->y(),_splt->container1->w(),_splt->container1->h());
_splt->container1->add(_tabs);
int tx,ty,th,tw,i;
_tabs->client_area(tx,ty,tw,th);
for(i=0; i<titleCnt; ++i)
{
_tabs->begin();
initializeTab(i,tx,ty,tw,th,titleArray[i]);
_tabs->end();
}
// Create an empty tab group and make it resizable
// to prevent the other tab groups from being resizable.
_tabs->begin();
_tabs->resizable(new Fl_Group(tx,ty+30,1,1));
_tabs->end();
}
app* app::_getApp( Fl_Widget* w )
{
// walk up the widget tree until the top widget is found
Fl_Group* gp = w->parent();
while( gp->parent() != NULL )
gp=gp->parent();
// the user data for the top widget is a pointer app - as set in: callback(_s_callback,this);
return (app*)gp->user_data();
}
cmRC_t app::_s_print_queue_cb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
{
app* ap = (app*)userCbPtr;
ap->_print((const char*)msgDataPtr);
return cmOkRC;
}
void app::_checkPrintQueue()
{
while( cmTsMp1cMsgWaiting(_printqH) )
if( cmTsMp1cDequeueMsg(_printqH, NULL, 0) != kOkThRC )
error("Print dequeue failed.");
}
void app::_print( const char* text )
{
if( _con != NULL )
_con->insert(text);
}

119
src/cmflapp/app.h Normal file
View File

@ -0,0 +1,119 @@
#ifndef app_h
#define app_h
class Fl_HSplitter;
class Fl_Text_Buffer;
class Fl_Text_Display;
class Fl_Box;
class Fl_Tabs;
struct Fl_Menu_Item;
class Fl_Menu_Bar;
class Fl_Group;
class Fl_Button;
class Fl_Valuator;
class Fl_Input;
class drawWnd;
class app : public Fl_Double_Window
{
public:
// widget id's for widgets created by createControls()
enum
{
kFileOpenMId,
kFileNewMId,
kEditCopyMId,
kEditPasteMId,
kBtn1MId,
kBtn2MId,
kBtn3MId,
kMenuBtn1MId,
kMenuBtn2MId,
kValue1MId,
kValue2MId,
kInput1MId
};
app(cmCtx_t* ctx, cmTsMp1cH_t printqH, int w, int h, const char *l, int argc, char *argv[]);
virtual ~app();
// Example tabbed window initialization example function
// which also demonstrates some widgets
void createControls(Fl_Group* grp);
// called once from app() to initialize each tabbed window
virtual void initializeTab(int tabIndex, int x, int y, int w, int h, const char* label);
// Create the application menu
virtual void createMenu( int menuWidth, int menuHeight );
// Widget type specific callbacks
virtual void menuCallback( const Fl_Menu_Item* ip, long int id ); // menu and menu btn callback
virtual void btnCallback( const Fl_Button* bp, int id ); // btn callback
virtual void valueCallback(const Fl_Valuator* vp, int id ); // valuator callback
virtual void inputCallback(const Fl_Input* ip, int id ); // text input callback
virtual void appCallback(Fl_Widget* wp); // app event callback
virtual bool idleCallback(); // return false to stop callback
virtual bool timerCallback(); // return false to stop callback
void error( const char* fmt, ... ); // report on error
// print to the console
virtual void vprint( const char* fmt, va_list vl );
virtual void print( const char* fmt, ... );
protected:
enum
{
kStatusH = 30,
kMenuH = 30,
kCtlH = 30
};
// static callbacks
static void _s_menu_cb( Fl_Widget* wp, void* data); // menu item callback
static void _s_menu_btn_cb(Fl_Widget* wp, void* data); // menu btn callback
static void _s_btn_cb( Fl_Widget* wp, long data); // button callback
static void _s_value_cb( Fl_Widget* wp, long data); // value input or slider callback
static void _s_input_cb( Fl_Widget* wp, long data); // text input callback
static void _s_callback( Fl_Widget* wp, void* data); // main app callback
static void _s_idle_cb( void* data); // idle callback
static void _s_timer_cb( void* userPtr); // timer callback
static void _s_print( void* userPtr, const char* text ); // print text to the console
void _create_tabs(int titleCnt, const char* titleArray[]);
// walk down the widget tree until the app (root) widget is located
static app* _getApp( Fl_Widget* w );
// called internally by cmTsQueueDequeue() to send text to _print()
static cmRC_t _s_print_queue_cb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr );
// called periodically to check the print queue for waiting text.
void _checkPrintQueue();
// send a string of text directly to the output console window
void _print( const char* text );
double _timerPeriodSecs; // repeat period for the timer callback
cmCtx_t* _ctx; //
Fl_HSplitter* _splt; // main splitter window
Fl_Text_Buffer* _buf; // text buffer used by _con
Fl_Text_Display* _con; // text console output window
Fl_Tabs* _tabs; // tabs window
Fl_Menu_Bar* _menu; // app. menu
drawWnd* _draw; // custom widget
cmTsMp1cH_t _printqH; // thread-safe queue for controlling access to the output console from multiple threads
int _printFl; // used to prevent recursion due to throwing printing error
};
#endif

24
src/cmflapp/appErr.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef appErr_h
#define appErr_h
#ifdef __cplusplus
extern "C" {
#endif
enum
{
kOkAppRC,
kQueueFailAppRC,
kFileSysFailAppRC,
kMemFailAppRC,
kTextSysFailAppRC,
kPrefsFailAppRC
};
typedef unsigned cmAppRC_t;
#ifdef __cplusplus
}
#endif
#endif

110
src/cmflapp/main.cpp Normal file
View File

@ -0,0 +1,110 @@
#include <FL/Fl.H>
#include <Fl/fl_draw.H>
#include <FL/Fl_Double_Window.H>
#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 "cmLinkedHeap.h"
#include "cmThread.h"
#include "cmFileSys.h"
#include "cmText.h"
#include "appErr.h"
#include "app.h"
void print( void*, const cmChar_t* text)
{ puts(text); }
cmRC_t print_queue_cb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
{
print(NULL,(const char*)msgDataPtr);
return cmOkRC;
}
int main( int argc, char* argv[] )
{
cmCtx_t ctx;
cmTsMp1cH_t printqH = cmTsMp1cNullHandle;
int appWndW = 1000;
int appWndH = 750;
const char* appPrefDir = "gv";
const char* appTitle = "GV Console";
bool memDebugFl = cmDEBUG_FL;
unsigned memPadByteCnt = memDebugFl ? 8 : 0;
unsigned memAlignByteCnt = 16;
unsigned memFlags = memDebugFl ? (kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl) : 0;
cmCtxSetup(&ctx,appTitle,print,print,NULL,memPadByteCnt,memAlignByteCnt,memFlags);
// initialize the memory mgr
if(cmMdInitialize( memPadByteCnt, memAlignByteCnt, memFlags, &ctx.rpt ) != kOkMmRC )
{
cmErrMsg(&ctx.err,kMemFailAppRC,"Heap initialization failed.");
goto errLabel;
}
// initialize the file system
if( cmFsInitialize( &ctx, appPrefDir ) != kOkFsRC )
cmErrMsg(&ctx.err,kFileSysFailAppRC,"File system initialization failed.");
// initialize the text system
if( cmTsInitialize(&ctx) != kOkTxRC )
cmErrMsg(&ctx.err,kTextSysFailAppRC,"Text system initialization failed.");
// create the print queue
if( cmTsMp1cCreate( &printqH, 8192, print_queue_cb, NULL, NULL ) != kOkThRC )
cmErrMsg(&ctx.err,kQueueFailAppRC,"Print queue creation failed.");
if( cmErrLastRC(&ctx.err) == kOkAppRC )
{
app proj(&ctx, printqH, appWndW, appWndH, appTitle, argc, argv);
Fl::run();
// reset the pgm context and print queue console output to stdout
cmRptSetup(&ctx.rpt,print,print,NULL);
cmTsMp1cSetCbFunc(printqH, print_queue_cb, NULL );
}
// empty any pending text to stdout
while( cmTsMp1cMsgWaiting(printqH) )
if( cmTsMp1cDequeueMsg(printqH, NULL, 0) != kOkThRC )
cmErrMsg(&ctx.err,kQueueFailAppRC,"Print dequeue failed.");
// destroy the print queue
if( cmTsMp1cDestroy(&printqH) != kOkThRC )
cmErrMsg(&ctx.err,kQueueFailAppRC,"Print queue destroy failed.");
// finalize the text system
if( cmTsFinalize() != kOkTxRC )
cmErrMsg(&ctx.err,kTextSysFailAppRC,"Text system finalization failed.");
// finalize the file system
if( cmFsFinalize() != kOkFsRC )
cmErrMsg(&ctx.err,kFileSysFailAppRC,"File system finalize failed.");
// report memory mgr errors
if( cmMdIsValid() )
cmMdReport( kIgnoreNormalMmFl );
// finalize the memory manager
if( cmMdFinalize() != kOkMmRC )
cmErrMsg(&ctx.err,kMemFailAppRC,"Heap finalization failed.");
errLabel:
return 0;
}

View File

@ -1,39 +0,0 @@
#include "cmPrefix.h"
#include "cmGlobal.h"
#include "cmRpt.h"
#include "cmErr.h"
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmLinkedHeap.h"
#include "cmFileSys.h"
#include "cmText.h"
void print( void* arg, const char* text )
{
printf("%s\n",text);
}
int main( int argc, char* argv[] )
{
// initialize the heap check library
bool memDebugFl = cmDEBUG_FL;
unsigned memGuardByteCnt = memDebugFl ? 8 : 0;
unsigned memAlignByteCnt = 16;
unsigned memFlags = memDebugFl ? kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl : 0;
cmCtx_t ctx;
cmCtxSetup(&ctx,"cm test",print,print,NULL,memGuardByteCnt,memAlignByteCnt,memFlags);
cmMdInitialize( memGuardByteCnt, memAlignByteCnt, memFlags, &ctx.rpt );
cmFsInitialize( &ctx, "cm_test" );
cmTsInitialize(&ctx );
cmTsFinalize();
cmFsFinalize();
cmMdReport( kIgnoreNormalMmFl );
cmMdFinalize();
return 0;
}