cwUi* : Initial implementation.
This commit is contained in:
parent
545f8b808f
commit
78b351b753
466
cwUi.cpp
Normal file
466
cwUi.cpp
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwThread.h"
|
||||||
|
#include "cwWebSock.h"
|
||||||
|
#include "cwWebSockSvr.h"
|
||||||
|
#include "cwUi.h"
|
||||||
|
#include "cwText.h"
|
||||||
|
#include "cwNumericConvert.h"
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
typedef struct ele_str
|
||||||
|
{
|
||||||
|
struct ele_str* parent; // pointer to parent ele - or nullptr if this ele is attached to the root ui ele
|
||||||
|
unsigned uuId; // UI unique id - automatically generated and unique among all elements that are part of this ui_t object.
|
||||||
|
unsigned appId; // application assigned id - application assigned id
|
||||||
|
char* jsId; // javascript id
|
||||||
|
} ele_t;
|
||||||
|
|
||||||
|
typedef struct ui_str
|
||||||
|
{
|
||||||
|
websockSrv::handle_t wssH;
|
||||||
|
unsigned eleAllocN;
|
||||||
|
unsigned eleN;
|
||||||
|
ele_t** eleA;
|
||||||
|
uiCallback_t cbFunc;
|
||||||
|
void* cbArg;
|
||||||
|
} ui_t;
|
||||||
|
|
||||||
|
ui_t* _handleToPtr( handle_t h )
|
||||||
|
{ return handleToPtr<handle_t,ui_t>(h); }
|
||||||
|
|
||||||
|
rc_t _destroy( ui_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( p->wssH.isValid() )
|
||||||
|
if((rc = websockSrv::destroy(p->wssH)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
{
|
||||||
|
mem::release(p->eleA[i]->jsId);
|
||||||
|
mem::release(p->eleA[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::release(p->eleA);
|
||||||
|
mem::release(p);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ele_t* _createEle( ui_t* p, ele_t* parent, unsigned appId, const char* jsId )
|
||||||
|
{
|
||||||
|
ele_t* e = mem::allocZ<ele_t>();
|
||||||
|
e->parent = parent;
|
||||||
|
e->uuId = p->eleN;
|
||||||
|
e->appId = appId;
|
||||||
|
e->jsId = mem::duplStr(jsId);
|
||||||
|
|
||||||
|
if( p->eleN == p->eleAllocN )
|
||||||
|
{
|
||||||
|
p->eleAllocN += 100;
|
||||||
|
p->eleA = mem::resizeZ<ele_t*>(p->eleA,p->eleAllocN);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->eleA[ p->eleN ] = e;
|
||||||
|
p->eleN += 1;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ele_t* _uuIdToEle( ui_t* p, unsigned uuId, bool errorFl=true )
|
||||||
|
{
|
||||||
|
if( uuId >= p->eleN )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidIdRC,"The element uuid:%i is not valid.",uuId);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p->eleA[ uuId ];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _websockSend( ui_t* p, const char* msg )
|
||||||
|
{
|
||||||
|
return websock::send( websockSrv::websockHandle( p->wssH ), kUiProtocolId, msg, strlen(msg) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _findEleJsId( ui_t* p, unsigned uuId )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( p->eleA[i]->uuId == uuId )
|
||||||
|
return p->eleA[i]->jsId;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the attribute data value.
|
||||||
|
template< typename T0 >
|
||||||
|
unsigned format_attribute_data( char* buf, unsigned n, T0 t0 )
|
||||||
|
{
|
||||||
|
return toText(buf,n,t0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override format_attribute_data() for char. string data so that strings are wrapped in quotes.
|
||||||
|
template<>
|
||||||
|
unsigned format_attribute_data( char* buf, unsigned n, const char* t )
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
i += toText(buf+i, n-i, "\"" );
|
||||||
|
i += toText(buf+i, n-i, t );
|
||||||
|
i += toText(buf+i, n-i, "\"" );
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminating condition for format_attributes()
|
||||||
|
unsigned format_attributes(char* buf, unsigned n, unsigned i)
|
||||||
|
{ return i; }
|
||||||
|
|
||||||
|
template<typename T0, typename T1, typename... ARGS>
|
||||||
|
unsigned format_attributes(char* buf, unsigned n, unsigned i, T0 t0, T1 t1, ARGS&&... args)
|
||||||
|
{
|
||||||
|
i += toText(buf+i, n-i, ",\"" );
|
||||||
|
i += toText(buf+i, n-i, t0 );
|
||||||
|
i += toText(buf+i, n-i, "\":" );
|
||||||
|
i += format_attribute_data(buf+i, n-i, t1 );
|
||||||
|
|
||||||
|
return format_attributes(buf,n,i,std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename... ARGS>
|
||||||
|
rc_t _createOneEle( ui_t* p, unsigned& uuIdRef, const char* eleTypeStr, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, ARGS&&... args )
|
||||||
|
{
|
||||||
|
// { op:create, parent:my_parent_id, value:{ button:{ jsId:my_jsId, appId:appId, uuId:uuId, class:clas, title:'my title' } }
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* parentJsId = "";
|
||||||
|
ele_t* newEle = nullptr;
|
||||||
|
ele_t* parentEle = nullptr;
|
||||||
|
const unsigned bufN = 1024;
|
||||||
|
char buf[ bufN ];
|
||||||
|
|
||||||
|
uuIdRef = kInvalidId;
|
||||||
|
|
||||||
|
//
|
||||||
|
if( parentUuId != kInvalidId )
|
||||||
|
{
|
||||||
|
if(( parentEle = _uuIdToEle(p, parentUuId )) == nullptr )
|
||||||
|
return cwLogError( kInvalidArgRC, "Unable to locate the parent element (id:%i).", parentUuId );
|
||||||
|
|
||||||
|
parentJsId = parentEle->jsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
newEle = _createEle( p, parentEle, appId, jsId );
|
||||||
|
|
||||||
|
unsigned i = snprintf( buf, bufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"value\":{ \"%s\":{ \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i, \"class\":\"%s\", \"title\":\"%s\" ", parentJsId, eleTypeStr, jsId, appId, newEle->uuId, clas, title );
|
||||||
|
|
||||||
|
i = format_attributes(buf, bufN, i, std::forward<ARGS>(args)...);
|
||||||
|
|
||||||
|
toText(buf+i, bufN-i, "}}}");
|
||||||
|
|
||||||
|
printf("%s\n",buf);
|
||||||
|
|
||||||
|
rc = _websockSend( p, buf );
|
||||||
|
|
||||||
|
uuIdRef = newEle->uuId;
|
||||||
|
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ele_t* _parse_value_msg( ui_t* p, value_t& valueRef, const char* msg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char argType = 0;
|
||||||
|
ele_t* ele = nullptr;
|
||||||
|
unsigned eleUuId = kInvalidId;
|
||||||
|
|
||||||
|
valueRef.tid = kInvalidTId;
|
||||||
|
|
||||||
|
if( msg == nullptr )
|
||||||
|
{
|
||||||
|
cwLogWarning("Empty message received from UI.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate the colon prior to the value
|
||||||
|
const char* s = strchr(msg,':');
|
||||||
|
|
||||||
|
if( s == nullptr || sscanf(msg, "value %i %c ",&eleUuId,&argType) != 2 )
|
||||||
|
{
|
||||||
|
cwLogError(kSyntaxErrorRC,"Invalid message from UI: %s.", msg );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance s past the colon
|
||||||
|
s += 1;
|
||||||
|
|
||||||
|
// parse the argument
|
||||||
|
switch( argType )
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
if((rc = string_to_number<bool>(s,valueRef.u.b)) == kOkRC )
|
||||||
|
valueRef.tid = kBoolTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
if((rc = string_to_number<int>(s,valueRef.u.i)) == kOkRC )
|
||||||
|
valueRef.tid = kIntTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
if((rc = string_to_number<unsigned>(s,valueRef.u.u)) == kOkRC )
|
||||||
|
valueRef.tid = kUIntTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
if((rc = string_to_number<float>(s,valueRef.u.f)) == kOkRC )
|
||||||
|
valueRef.tid = kFloatTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
if((rc = string_to_number<double>(s,valueRef.u.d)) == kOkRC )
|
||||||
|
valueRef.tid = kDoubleTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if((valueRef.u.s = nextNonWhiteChar(s)) == nullptr )
|
||||||
|
valueRef.tid = kStringTId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
rc = cwLogError(kInvalidIdRC,"Unknown value type '%c' in message from UI.", argType );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate the element record
|
||||||
|
if((ele = _uuIdToEle( p, eleUuId )) == nullptr )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidIdRC,"UI message elment not found.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
return ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _websockCb( void* cbArg, unsigned protocolId, unsigned connectionId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
|
||||||
|
{
|
||||||
|
ui_t* p = (ui_t*)cbArg;
|
||||||
|
opId_t opId = kInvalidOpId;
|
||||||
|
unsigned eleUuId = kInvalidId;
|
||||||
|
unsigned eleAppId = kInvalidId;
|
||||||
|
unsigned parentEleAppId = kInvalidId;
|
||||||
|
value_t value;
|
||||||
|
|
||||||
|
switch( msg_type )
|
||||||
|
{
|
||||||
|
case websock::kConnectTId:
|
||||||
|
opId = kConnectOpId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case websock::kDisconnectTId:
|
||||||
|
opId = kDisconnectOpId;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case websock::kMessageTId:
|
||||||
|
{
|
||||||
|
ele_t* ele;
|
||||||
|
|
||||||
|
if( textCompare((const char*)msg,"init",strlen("init")) == 0 )
|
||||||
|
{
|
||||||
|
opId = kInitOpId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opId = kValueOpId;
|
||||||
|
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
|
||||||
|
cwLogError(kOpFailRC,"UI Value message parse failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eleUuId = ele->uuId;
|
||||||
|
eleAppId = ele->appId;
|
||||||
|
parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cwLogError(kInvalidOpRC,"Unknown websock message type:%i.", msg_type );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->cbFunc != nullptr )
|
||||||
|
p->cbFunc( p->cbArg, connectionId, opId, parentEleAppId, eleUuId, eleAppId, &value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createUi(
|
||||||
|
handle_t& h,
|
||||||
|
unsigned port,
|
||||||
|
uiCallback_t cbFunc,
|
||||||
|
void* cbArg,
|
||||||
|
const char* physRootDir,
|
||||||
|
const char* dfltPageFn,
|
||||||
|
unsigned websockTimeOutMs,
|
||||||
|
unsigned rcvBufByteN,
|
||||||
|
unsigned xmtBufByteN )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
websock::protocol_t protocolA[] =
|
||||||
|
{
|
||||||
|
{ "http", kHttpProtocolId, 0, 0 },
|
||||||
|
{ "ui_protocol", kUiProtocolId, rcvBufByteN, xmtBufByteN }
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned protocolN = sizeof(protocolA)/sizeof(protocolA[0]);
|
||||||
|
|
||||||
|
if((rc = destroyUi(h)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
ui_t* p = mem::allocZ<ui_t>();
|
||||||
|
|
||||||
|
if((rc = websockSrv::create(p->wssH, _websockCb, p, physRootDir, dfltPageFn, port, protocolA, protocolN, websockTimeOutMs )) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"Internal websock server creation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->eleAllocN = 100;
|
||||||
|
p->eleA = mem::allocZ<ele_t*>( p->eleAllocN );
|
||||||
|
p->eleN = 0;
|
||||||
|
p->cbFunc = cbFunc;
|
||||||
|
p->cbArg = cbArg;
|
||||||
|
|
||||||
|
h.set(p);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
{
|
||||||
|
_destroy(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::start( handle_t h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
if((rc = websockSrv::start(p->wssH)) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Internal websock server start failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::stop( handle_t h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
if((rc = websockSrv::pause(p->wssH)) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Internal websock server stop failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::destroyUi( handle_t& h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
if( !h.isValid() )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
if((rc = _destroy(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
h.clear();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::ui::findElementAppId( handle_t h, unsigned parentUuId, const char* jsId )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( p->eleA[i]->parent->uuId==parentUuId && strcmp(p->eleA[i]->jsId,jsId) == 0 )
|
||||||
|
return p->eleA[i]->appId;
|
||||||
|
return kInvalidId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::ui::findElementUuId( handle_t h, unsigned parentUuId, const char* jsId )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( p->eleA[i]->parent->uuId==parentUuId && strcmp(p->eleA[i]->jsId,jsId) == 0 )
|
||||||
|
return p->eleA[i]->uuId;
|
||||||
|
return kInvalidId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::ui::findElementUuId( handle_t h, unsigned parentUuId, unsigned appId )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( p->eleA[i]->parent->uuId==parentUuId && p->eleA[i]->appId == appId )
|
||||||
|
return p->eleA[i]->uuId;
|
||||||
|
return kInvalidId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* cw::ui::findElementJsId( handle_t h, unsigned uuId )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
return _findEleJsId(p,uuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createDiv( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "div", parentUuId, jsId, appId, clas, title ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createTitle( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createButton( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "button", parentUuId, jsId, appId, clas, title ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createCheck( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "check", parentUuId, jsId, appId, clas, title, "value", value ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createSelect( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "select", parentUuId, jsId, appId, clas, title ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createOption( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createString( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "string", parentUuId, jsId, appId, clas, title, "value", value ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createNumber( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decpl )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "number", parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue, "step", stepValue, "decpl", decpl ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createProgress( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue )
|
||||||
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "progress", parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
|
{
|
||||||
|
rc_t rc= kOkRC;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
89
cwUi.h
Normal file
89
cwUi.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef cwUI_H
|
||||||
|
#define cwUI_H
|
||||||
|
|
||||||
|
#include "cwUiDecls.h"
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
typedef handle<struct ui_str> handle_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kHttpProtocolId = 1,
|
||||||
|
kUiProtocolId = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
kInvalidOpId,
|
||||||
|
kConnectOpId,
|
||||||
|
kInitOpId,
|
||||||
|
kValueOpId,
|
||||||
|
kDisconnectOpId
|
||||||
|
} opId_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
kInvalidTId,
|
||||||
|
kBoolTId,
|
||||||
|
kIntTId,
|
||||||
|
kUIntTId,
|
||||||
|
kFloatTId,
|
||||||
|
kDoubleTId,
|
||||||
|
kStringTId
|
||||||
|
} dtypeId_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
dtypeId_t tid;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
int i;
|
||||||
|
unsigned u;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
const char* s;
|
||||||
|
} u;
|
||||||
|
} value_t;
|
||||||
|
|
||||||
|
typedef rc_t (*uiCallback_t)( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* value );
|
||||||
|
|
||||||
|
rc_t createUi( handle_t& h,
|
||||||
|
unsigned port,
|
||||||
|
uiCallback_t cbFunc,
|
||||||
|
void* cbArg,
|
||||||
|
const char* physRootDir,
|
||||||
|
const char* dfltPageFn = "index.html",
|
||||||
|
unsigned websockTimeOutMs = 50,
|
||||||
|
unsigned rcvBufByteN = 1024,
|
||||||
|
unsigned xmtBufByteN = 1024);
|
||||||
|
|
||||||
|
rc_t destroyUi( handle_t& h );
|
||||||
|
|
||||||
|
rc_t start( handle_t h );
|
||||||
|
rc_t stop( handle_t h );
|
||||||
|
|
||||||
|
unsigned findElementAppId( handle_t h, unsigned parentUuId, const char* jsId );
|
||||||
|
unsigned findElementUuId( handle_t h, unsigned parentUuId, const char* jsId );
|
||||||
|
unsigned findElementUuId( handle_t h, unsigned parentUuId, unsigned appId );
|
||||||
|
const char* findElementJsId( handle_t h, unsigned uuId );
|
||||||
|
|
||||||
|
rc_t createDiv( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
rc_t createTitle( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
rc_t createButton( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
rc_t createCheck( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value );
|
||||||
|
rc_t createSelect( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
rc_t createOption( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
rc_t createString( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value );
|
||||||
|
rc_t createNumber( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decPl );
|
||||||
|
rc_t createProgress( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue );
|
||||||
|
rc_t createText( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
12
cwUiDecls.h
Normal file
12
cwUiDecls.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef cwUiDecls_H
|
||||||
|
#define cwUiDecls_H
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
184
cwUiTest.cpp
Normal file
184
cwUiTest.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwUi.h"
|
||||||
|
#include "cwUiTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
typedef struct ui_test_str
|
||||||
|
{
|
||||||
|
handle_t uiH;
|
||||||
|
} ui_test_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kDivId,
|
||||||
|
kBtnId,
|
||||||
|
kCheckId,
|
||||||
|
kSelectId,
|
||||||
|
kOption0Id,
|
||||||
|
kOption1Id,
|
||||||
|
kOption2Id,
|
||||||
|
kOption3Id,
|
||||||
|
kStringId,
|
||||||
|
kNumberId,
|
||||||
|
kProgressId
|
||||||
|
};
|
||||||
|
|
||||||
|
rc_t _uiTestCreateUi( ui_test_t* p, unsigned connId )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned uuid = kInvalidId;
|
||||||
|
unsigned selUuId = kInvalidId;
|
||||||
|
unsigned divUuId = kInvalidId;
|
||||||
|
|
||||||
|
if((rc = createDiv( p->uiH, divUuId, kInvalidId, "myDivId", kDivId, "divClass", "My Panel" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createButton( p->uiH, uuid, divUuId, "myBtnId", kBtnId, "btnClass", "Push Me" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createCheck( p->uiH, uuid, divUuId, "myCheckId", kCheckId, "checkClass", "Check Me", true )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createSelect( p->uiH, selUuId, divUuId, "mySelId", kSelectId, "selClass", "Select" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt0Id", kOption0Id, "optClass", "Option 0" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt1Id", kOption1Id, "optClass", "Option 1" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt2Id", kOption2Id, "optClass", "Option 2" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createString( p->uiH, uuid, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createNumber( p->uiH, uuid, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createProgress( p->uiH, uuid, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _handleUiValueMsg( ui_test_t* p, unsigned connId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
switch( appId )
|
||||||
|
{
|
||||||
|
case kBtnId:
|
||||||
|
printf("Click!\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCheckId:
|
||||||
|
printf("Check:%i\n", v->u.b);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSelectId:
|
||||||
|
printf("Selected: optionId:%i\n", v->u.i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kStringId:
|
||||||
|
printf("String: %s\n",v->u.s);
|
||||||
|
|
||||||
|
case kNumberId:
|
||||||
|
if( v->tid == kIntTId )
|
||||||
|
printf("Number: %i\n",v->u.i);
|
||||||
|
else
|
||||||
|
printf("Number: %f\n",v->u.d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _uiTestCallback( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
||||||
|
{
|
||||||
|
ui_test_t* p = (ui_test_t*)cbArg;
|
||||||
|
|
||||||
|
switch( opId )
|
||||||
|
{
|
||||||
|
case kConnectOpId:
|
||||||
|
cwLogInfo("Connect: connId:%i.",connId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDisconnectOpId:
|
||||||
|
cwLogInfo("Disconnect: connId:%i.",connId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kInitOpId:
|
||||||
|
_uiTestCreateUi(p,connId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kValueOpId:
|
||||||
|
_handleUiValueMsg( p, connId, parentAppId, uuId, appId, v );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kInvalidOpId:
|
||||||
|
// fall through
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::test( )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* physRootDir = "/home/kevin/src/cw_rt/html/uiTest";
|
||||||
|
const char* dfltPageFn = "index.html";
|
||||||
|
int port = 5687;
|
||||||
|
unsigned rcvBufByteN = 2048;
|
||||||
|
unsigned xmtBufByteN = 2048;
|
||||||
|
unsigned websockTimeOutMs = 50;
|
||||||
|
const unsigned sbufN = 31;
|
||||||
|
char sbuf[ sbufN+1 ];
|
||||||
|
ui_test_t* ui = mem::allocZ<ui_test_t>();
|
||||||
|
|
||||||
|
if((rc = createUi(ui->uiH, port, _uiTestCallback, ui, physRootDir, dfltPageFn, websockTimeOutMs, rcvBufByteN, xmtBufByteN )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if((rc = start(ui->uiH)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
printf("'quit' to exit\n");
|
||||||
|
|
||||||
|
// readline loop
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
printf("? ");
|
||||||
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||||
|
{
|
||||||
|
printf("Sending:%s",sbuf);
|
||||||
|
|
||||||
|
if( strcmp(sbuf,"quit\n") == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
rc_t rc1 = kOkRC;
|
||||||
|
if( ui->uiH.isValid() )
|
||||||
|
rc1 = destroyUi(ui->uiH);
|
||||||
|
|
||||||
|
mem::release(ui);
|
||||||
|
|
||||||
|
return rcSelect(rc,rc1);
|
||||||
|
}
|
7
cwUiTest.h
Normal file
7
cwUiTest.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
rc_t test();
|
||||||
|
}
|
||||||
|
}
|
9
html/uiTest/css/ui.css
Normal file
9
html/uiTest/css/ui.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.title_disconnected {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_connected {
|
||||||
|
color: green;
|
||||||
|
}
|
22
html/uiTest/index.html
Normal file
22
html/uiTest/index.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>UI Test App</title>
|
||||||
|
<script type="text/javascript" src="js/ui.js"></script>
|
||||||
|
<link href="css/ui.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<script text="text/javascript">
|
||||||
|
window.addEventListener("load",main, false )
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p id="appTitleId">Disconnected</p>
|
||||||
|
|
||||||
|
<div id="uiDivId" class="uiAppDiv">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
518
html/uiTest/js/ui.js
Normal file
518
html/uiTest/js/ui.js
Normal file
@ -0,0 +1,518 @@
|
|||||||
|
var _ws = null;
|
||||||
|
var _dfltParentId = "uiDivId";
|
||||||
|
|
||||||
|
function set_app_title( suffix, className )
|
||||||
|
{
|
||||||
|
var ele = document.getElementById('appTitleId');
|
||||||
|
ele.innerHTML = "UI Test:" + suffix
|
||||||
|
ele.className = className
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function uiOnError( msg, r)
|
||||||
|
{
|
||||||
|
console.log("Error:" + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiGetParent( r )
|
||||||
|
{
|
||||||
|
parent_ele = document.getElementById(r.parent_id);
|
||||||
|
|
||||||
|
if( parent_ele == null )
|
||||||
|
{
|
||||||
|
uiOnError("Parent not found. parent_id:" + r.parent_id,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiCreateEle( r )
|
||||||
|
{
|
||||||
|
var parent_ele;
|
||||||
|
|
||||||
|
if((parent_ele = uiGetParent(r)) != null )
|
||||||
|
{
|
||||||
|
ele = document.createElement(r.ele_type)
|
||||||
|
ele.id = r.ele_id;
|
||||||
|
ele.className = r.value;
|
||||||
|
|
||||||
|
parent_ele.appendChild(ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiRemoveChildren( r )
|
||||||
|
{
|
||||||
|
ele = document.getElementById(r.ele_id)
|
||||||
|
|
||||||
|
while (ele.firstChild)
|
||||||
|
{
|
||||||
|
ele.removeChild(ele.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiDivCreate( r )
|
||||||
|
{ uiCreateEle(r) }
|
||||||
|
|
||||||
|
function uiLabelCreate( r )
|
||||||
|
{
|
||||||
|
var parent_ele;
|
||||||
|
|
||||||
|
if((parent_ele = uiGetParent(r)) != null )
|
||||||
|
{
|
||||||
|
ele = document.createElement("label")
|
||||||
|
ele.htmlFor = r.ele_id
|
||||||
|
ele.innerHTML = r.value;
|
||||||
|
parent_ele.appendChild(ele)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiSelectCreate( r )
|
||||||
|
{
|
||||||
|
uiCreateEle(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiSelectClear( r )
|
||||||
|
{ uiRemoveChildren(r) }
|
||||||
|
|
||||||
|
function uiSelectInsert( r )
|
||||||
|
{
|
||||||
|
var select_ele;
|
||||||
|
|
||||||
|
if((select_ele = uiGetParent(r)) != null )
|
||||||
|
{
|
||||||
|
var option = document.createElement('option');
|
||||||
|
|
||||||
|
option.id = r.ele_id;
|
||||||
|
option.innerHTML = r.value;
|
||||||
|
option.value = r.ele_id;
|
||||||
|
option.onclick = function() { uiOnSelectClick(this) }
|
||||||
|
|
||||||
|
select_ele.appendChild(option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiSelectChoose( r )
|
||||||
|
{
|
||||||
|
var select_ele;
|
||||||
|
|
||||||
|
if((select_ele = uiGetParent(r)) != null )
|
||||||
|
{
|
||||||
|
if( select_ele.hasChildNodes())
|
||||||
|
{
|
||||||
|
var children = select_ele.childNodes
|
||||||
|
for(var i=0; i<children.length; i++)
|
||||||
|
{
|
||||||
|
if( children[i].id == r.ele_id )
|
||||||
|
{
|
||||||
|
select_ele.selectedIndex = i
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiOnSelectClick( ele )
|
||||||
|
{
|
||||||
|
cmdstr = "mode ui ele_type select op choose parent_id "+ele.parentElement.id+" option_id " + ele.id
|
||||||
|
websocket.send(cmdstr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiNumberOnKeyUp( e )
|
||||||
|
{
|
||||||
|
if( e.keyCode == 13 )
|
||||||
|
{
|
||||||
|
//console.log(e)
|
||||||
|
cmdstr = "mode ui ele_type number op change parent_id "+e.srcElement.parentElement.id+" ele_id " + e.srcElement.id + " value " + e.srcElement.value
|
||||||
|
websocket.send(cmdstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function uiNumberCreate( r )
|
||||||
|
{
|
||||||
|
var parent_ele;
|
||||||
|
|
||||||
|
if((parent_ele = uiGetParent(r)) != null )
|
||||||
|
{
|
||||||
|
ele = document.createElement("input")
|
||||||
|
ele.id = r.ele_id
|
||||||
|
ele.setAttribute('type','number')
|
||||||
|
ele.addEventListener('keyup',uiNumberOnKeyUp)
|
||||||
|
parent_ele.appendChild(ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uiNumberSet( r )
|
||||||
|
{
|
||||||
|
var ele;
|
||||||
|
|
||||||
|
console.log("ele_id:" + r.ele_id + " parent_id:" + r.parent_id + " value:" + r.value)
|
||||||
|
|
||||||
|
if((ele = document.getElementById(r.parent_id)) != null)
|
||||||
|
{
|
||||||
|
switch( r.ele_id )
|
||||||
|
{
|
||||||
|
case "0": ele.min = r.value; break;
|
||||||
|
case "1": ele.max = r.value; break;
|
||||||
|
case "2": ele.step = r.value; break;
|
||||||
|
case "3": ele.value = r.value; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dom_id_to_ele( id )
|
||||||
|
{ return document.getElementById(id); }
|
||||||
|
|
||||||
|
function dom_child_by_id( parentEle, child_id )
|
||||||
|
{
|
||||||
|
var childrenL = parentEle.children
|
||||||
|
for(var i=0; i<childrenL.length; i++)
|
||||||
|
{
|
||||||
|
if( childrenL[i].id == child_id )
|
||||||
|
{
|
||||||
|
return childrenL[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dom_set_option_by_text( ele_id, text )
|
||||||
|
{
|
||||||
|
var ele = dom_id_to_ele(ele_id);
|
||||||
|
|
||||||
|
for (var i = 0; i < ele.options.length; i++)
|
||||||
|
{
|
||||||
|
if (ele.options[i].text === text)
|
||||||
|
{
|
||||||
|
ele.selectedIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dom_set_checkbox( ele_id, fl )
|
||||||
|
{ dom_id_to_ele(ele_id).checked = fl }
|
||||||
|
|
||||||
|
function dom_get_checkbox( ele_id )
|
||||||
|
{ return dom_id_to_ele(ele_id).checked }
|
||||||
|
|
||||||
|
|
||||||
|
function dom_set_number( ele_id, val )
|
||||||
|
{
|
||||||
|
dom_id_to_ele(ele_id).value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_error( msg )
|
||||||
|
{
|
||||||
|
console.log("Error: " + msg )
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_print_children( eleId )
|
||||||
|
{
|
||||||
|
var childrenL = document.getElementById(eleId).children
|
||||||
|
|
||||||
|
for(var i=0; i<childrenL.length; i++)
|
||||||
|
{
|
||||||
|
console.log( childrenL[i] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_get_parent( parentId )
|
||||||
|
{
|
||||||
|
if( parentId==null || parentId.trim().length == 0 )
|
||||||
|
parentId = _dfltParentId
|
||||||
|
|
||||||
|
parent_ele = document.getElementById(parentId);
|
||||||
|
|
||||||
|
if( parent_ele == null )
|
||||||
|
{
|
||||||
|
ui_error("Parent element id: " + parentId + " not found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ui_create_ele( parent_ele, ele_type, d )
|
||||||
|
{
|
||||||
|
// create the ctl object
|
||||||
|
var ele = document.createElement(ele_type);
|
||||||
|
|
||||||
|
if( ele == null )
|
||||||
|
ui_error("'%s' element create failed.", ele_type);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ele.id = d.jsId;
|
||||||
|
ele.uuId = d.uuId;
|
||||||
|
ele.appId = d.appId;
|
||||||
|
parent_ele.appendChild(ele);
|
||||||
|
}
|
||||||
|
return ele
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_ctl( parent_ele, ele_type, label, d )
|
||||||
|
{
|
||||||
|
// create an enclosing div
|
||||||
|
var div_ele = document.createElement("div");
|
||||||
|
|
||||||
|
div_ele.className = d.clas;
|
||||||
|
|
||||||
|
parent_ele.appendChild( div_ele );
|
||||||
|
|
||||||
|
var label_ele = div_ele
|
||||||
|
|
||||||
|
// if label is not null then create an enclosing 'label' element
|
||||||
|
if( label != null )
|
||||||
|
{
|
||||||
|
label_ele = document.createElement("label");
|
||||||
|
|
||||||
|
label_ele.innerHTML = label;
|
||||||
|
|
||||||
|
div_ele.appendChild(label_ele)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ui_create_ele( label_ele, ele_type, d );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ui_create_div( parent_ele, d )
|
||||||
|
{
|
||||||
|
var div_ele = ui_create_ele( parent_ele, "div", d );
|
||||||
|
|
||||||
|
|
||||||
|
if( div_ele != null )
|
||||||
|
{
|
||||||
|
div_ele.className = d.clas
|
||||||
|
|
||||||
|
var p_ele = document.createElement("p")
|
||||||
|
|
||||||
|
if( d.title != null && d.title.length > 0 )
|
||||||
|
p_ele.innerHTML = d.title
|
||||||
|
|
||||||
|
div_ele.appendChild( p_ele )
|
||||||
|
}
|
||||||
|
|
||||||
|
return div_ele
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_title( parent_ele, d )
|
||||||
|
{
|
||||||
|
return ui_create_ele( parent_ele, "label", d );
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_button( parent_ele, d )
|
||||||
|
{
|
||||||
|
var ele = ui_create_ctl( parent_ele, "button", null, d );
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
{
|
||||||
|
ele.innerHTML = d.title;
|
||||||
|
ele.onclick = function() { _ws.send("value " + this.uuId + " i : 1"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return ele
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_check( parent_ele, d )
|
||||||
|
{
|
||||||
|
var ele = ui_create_ctl( parent_ele, "input", d.title, d )
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
{
|
||||||
|
ele.type = "checkbox";
|
||||||
|
|
||||||
|
dom_set_checkbox(ele.id, d.value );
|
||||||
|
|
||||||
|
ele.onclick = function() { _ws.send("value" + this.uuId + " b : " + dom_get_checkbox(this.id)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_on_select( ele )
|
||||||
|
{
|
||||||
|
var s = "value " + ele.uuId + " i : " + ele.options[ ele.selectedIndex ].appId
|
||||||
|
|
||||||
|
_ws.send( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_select( parent_ele, d )
|
||||||
|
{
|
||||||
|
var sel_ele = ui_create_ctl( parent_ele, "select", d.title, d );
|
||||||
|
sel_ele.onchange = function() { ui_on_select(this) }
|
||||||
|
return sel_ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_option( parent_ele, d )
|
||||||
|
{
|
||||||
|
var opt_ele = ui_create_ele( parent_ele, "option", d );
|
||||||
|
|
||||||
|
if( opt_ele != null )
|
||||||
|
{
|
||||||
|
opt_ele.className = d.clas;
|
||||||
|
opt_ele.innerHTML = d.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opt_ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_string( parent_ele, d )
|
||||||
|
{
|
||||||
|
var ele = ui_create_ctl( parent_ele, "input", d.title, d );
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
{
|
||||||
|
ele.value = d.value;
|
||||||
|
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ _ws.send("value" + this.uuId + " s : " + this.value + "\0");} } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_number_keyup( e )
|
||||||
|
{
|
||||||
|
console.log(e)
|
||||||
|
if( e.keyCode===13 )
|
||||||
|
{
|
||||||
|
var ele = dom_id_to_ele(e.target.id)
|
||||||
|
console.log(ele.value)
|
||||||
|
if( ele != null )
|
||||||
|
_ws.send("value" + ele.uuId + " i : " + ele.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_number( parent_ele, d )
|
||||||
|
{
|
||||||
|
var ele = ui_create_ctl( parent_ele, "input", d.title, d );
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
{
|
||||||
|
ele.value = d.value;
|
||||||
|
ele.maxValue = d.max;
|
||||||
|
ele.minValue = d.min;
|
||||||
|
ele.stepValue = d.step;
|
||||||
|
ele.decpl = d.decpl;
|
||||||
|
ele.addEventListener('keyup', ui_number_keyup );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_set_progress( ele_id, value )
|
||||||
|
{
|
||||||
|
var ele = dom_id_to_ele(ele_id);
|
||||||
|
|
||||||
|
ele.value = Math.round( ele.max * (value - ele.minValue) / (ele.maxValue - ele.minValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_create_progress( parent_ele, d )
|
||||||
|
{
|
||||||
|
var ele = ui_create_ctl( parent_ele, "progress", d.title, d );
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
{
|
||||||
|
ele.max = 100;
|
||||||
|
ele.maxValue = d.max;
|
||||||
|
ele.minValue = d.min;
|
||||||
|
ui_set_progress( ele.id, d.value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ui_create( parentId, ele_type, d )
|
||||||
|
{
|
||||||
|
var parent_ele = ui_get_parent(parentId);
|
||||||
|
|
||||||
|
if( parent_ele != null )
|
||||||
|
{
|
||||||
|
switch( ele_type )
|
||||||
|
{
|
||||||
|
case "div":
|
||||||
|
ui_create_div( parent_ele, d )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "title":
|
||||||
|
ui_create_title( parent_ele, d )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "button":
|
||||||
|
ui_create_button( parent_ele, d )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "check":
|
||||||
|
ui_create_check( parent_ele, d )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "select":
|
||||||
|
ui_create_select( parent_ele, d );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "option":
|
||||||
|
ui_create_option( parent_ele, d );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "string":
|
||||||
|
ui_create_string( parent_ele, d );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "number":
|
||||||
|
ui_create_number( parent_ele, d );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "progress":
|
||||||
|
ui_create_progress( parent_ele, d );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ui_error("Unknown UI element type: " + ele_type )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ws_send( d )
|
||||||
|
{
|
||||||
|
s = JSON.stringify(d)
|
||||||
|
//console.log(s)
|
||||||
|
_ws.send(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_on_msg( jsonMsg )
|
||||||
|
{
|
||||||
|
//console.log(jsonMsg)
|
||||||
|
d = JSON.parse(jsonMsg.data);
|
||||||
|
|
||||||
|
switch( d.op )
|
||||||
|
{
|
||||||
|
case 'create':
|
||||||
|
for (const ele_type in d.value)
|
||||||
|
{
|
||||||
|
ui_create( d.parent, ele_type, d.value[ele_type] )
|
||||||
|
//console.log(`${ele_type}: ${d.value[ele_type]}`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_on_open()
|
||||||
|
{
|
||||||
|
set_app_title( "Connected", "title_connected" );
|
||||||
|
_ws.send("init")
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_on_close()
|
||||||
|
{
|
||||||
|
set_app_title( "Disconnected", "title_disconnected" );
|
||||||
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
|
{
|
||||||
|
_ws = new WebSocket("ws://127.0.0.1:5687/","ui_protocol")
|
||||||
|
|
||||||
|
_ws.onmessage = ws_on_msg
|
||||||
|
_ws.onopen = ws_on_open
|
||||||
|
_ws.onclose = ws_on_close;
|
||||||
|
}
|
||||||
|
|
15
html/uiTest/ui.cfg
Normal file
15
html/uiTest/ui.cfg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
div: {
|
||||||
|
title:"My panel",
|
||||||
|
|
||||||
|
children: {
|
||||||
|
|
||||||
|
button:{ id:myBtnId, title:"Push Me" },
|
||||||
|
select:{ id:mySelectId, title:"Selector", optionL: { myId0:"Option 0", myId2:"Option 1", myId3:"Option 3" }}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user