cwUi : Initial UI creation from resource file.
This commit is contained in:
parent
80cd776337
commit
2372f153b3
18
README.md
18
README.md
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
# To Do
|
# To Do
|
||||||
|
|
||||||
|
- implement floating point UI numbers
|
||||||
- UI needs a special UUID (not kInvalidId) to specify the 'root' UI element. See note in cwUi._createFromObj()
|
- UI needs a special UUID (not kInvalidId) to specify the 'root' UI element. See note in cwUi._createFromObj()
|
||||||
- Look at 'BUG' warnings in cwNumericConvert.h.
|
- Look at 'BUG' warnings in cwNumericConvert.h.
|
||||||
- cwObject must be able to parse without dynamic memory allocation into a fixed buffer
|
- cwObject must be able to parse without dynamic memory allocation into a fixed buffer
|
||||||
@ -33,7 +34,24 @@ This is easy to reproduce by simply decreasing the size of the buffers in the pr
|
|||||||
|
|
||||||
- (DONE) implement kTcpFl in cwTcpSocket.cpp
|
- (DONE) implement kTcpFl in cwTcpSocket.cpp
|
||||||
|
|
||||||
|
# UI Control Creation Protocol
|
||||||
|
|
||||||
|
The UI elements have four identifiers:
|
||||||
|
|
||||||
|
uuId - An integer which is unique among all identifiers for a given cwUi object.
|
||||||
|
appId - A constant (enumerated) id assigned by the application. Unique among siblings.
|
||||||
|
jsId - A string id used by Javascript to identify a control. Unique among siblings.
|
||||||
|
jsUuId - An integer which is unique among all identifers for the browser representation of a given cwUi object.
|
||||||
|
|
||||||
|
The 'jsId' is selected by the application when the object is created.
|
||||||
|
The 'jsUuId' is generated by the JS client when the UI element is created.
|
||||||
|
The 'uuId' is generated by the UI server when the JS client registers the control.
|
||||||
|
The 'appId' is assigned by the UI server when the JS client regsiters the control.
|
||||||
|
|
||||||
|
Client sends 'init' message.
|
||||||
|
Server sends 'create' messages.
|
||||||
|
Client sends 'register' messages.
|
||||||
|
Server send' 'id_assign' messages.
|
||||||
|
|
||||||
|
|
||||||
# Development Setup
|
# Development Setup
|
||||||
|
514
cwUi.cpp
514
cwUi.cpp
@ -14,6 +14,15 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
|
typedef struct appIdMapRecd_str
|
||||||
|
{
|
||||||
|
struct appIdMapRecd_str* link;
|
||||||
|
unsigned parentAppId;
|
||||||
|
unsigned appId;
|
||||||
|
char* jsId;
|
||||||
|
} appIdMapRecd_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct ele_str
|
typedef struct ele_str
|
||||||
{
|
{
|
||||||
struct ele_str* parent; // pointer to parent ele - or nullptr if this ele is attached to the root ui ele
|
struct ele_str* parent; // pointer to parent ele - or nullptr if this ele is attached to the root ui ele
|
||||||
@ -24,17 +33,29 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct ui_str
|
typedef struct ui_str
|
||||||
{
|
{
|
||||||
websockSrv::handle_t wssH;
|
websockSrv::handle_t wssH; // websock server handle
|
||||||
unsigned eleAllocN;
|
unsigned eleAllocN; // size of eleA[]
|
||||||
unsigned eleN;
|
unsigned eleN; // count of ele's in use
|
||||||
ele_t** eleA;
|
ele_t** eleA; // eleA[ eleAllocN ]
|
||||||
uiCallback_t cbFunc;
|
uiCallback_t cbFunc; // app. cb func
|
||||||
void* cbArg;
|
void* cbArg; // app. cb func arg.
|
||||||
|
appIdMapRecd_t* appIdMap; // map of application parent/child/js id's
|
||||||
|
char* buf; // buf[bufN] output message formatting buffer
|
||||||
|
unsigned bufN; //
|
||||||
} ui_t;
|
} ui_t;
|
||||||
|
|
||||||
ui_t* _handleToPtr( handle_t h )
|
ui_t* _handleToPtr( handle_t h )
|
||||||
{ return handleToPtr<handle_t,ui_t>(h); }
|
{ return handleToPtr<handle_t,ui_t>(h); }
|
||||||
|
|
||||||
|
void _print_eles( ui_t* p )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
{
|
||||||
|
ele_t* e = p->eleA[i];
|
||||||
|
printf("%15s u:%i : u:%i a:%i %s\n",e->parent==nullptr?"<null>" : e->parent->jsId,e->parent==nullptr? -1 :e->parent->uuId,e->uuId,e->appId,e->jsId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc_t _destroy( ui_t* p )
|
rc_t _destroy( ui_t* p )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -49,12 +70,67 @@ namespace cw
|
|||||||
mem::release(p->eleA[i]);
|
mem::release(p->eleA[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appIdMapRecd_t* m = p->appIdMap;
|
||||||
|
while( m!=nullptr )
|
||||||
|
{
|
||||||
|
appIdMapRecd_t* m0 = m->link;
|
||||||
|
mem::release(m->jsId);
|
||||||
|
mem::release(m);
|
||||||
|
m = m0;
|
||||||
|
}
|
||||||
|
|
||||||
mem::release(p->eleA);
|
mem::release(p->eleA);
|
||||||
mem::release(p);
|
mem::release(p);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appIdMapRecd_t* _findAppIdMap( ui_t* p, unsigned parentAppId, const char* jsId )
|
||||||
|
{
|
||||||
|
appIdMapRecd_t* m = p->appIdMap;
|
||||||
|
for(; m != nullptr; m=m->link)
|
||||||
|
if( m->parentAppId==parentAppId && textCompare(jsId,m->jsId)==0 )
|
||||||
|
return m;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
appIdMapRecd_t* _findAppIdMap( ui_t* p, unsigned parentAppId, unsigned appId )
|
||||||
|
{
|
||||||
|
appIdMapRecd_t* m = p->appIdMap;
|
||||||
|
for(; m != nullptr; m=m->link)
|
||||||
|
if( m->parentAppId==parentAppId && m->appId==appId )
|
||||||
|
return m;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _allocAppIdMap( ui_t* p, unsigned parentAppId, unsigned appId, const char* jsId )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// The 'jsId' must be valid (or there is no reason to create the map.
|
||||||
|
// (since it will ultimately be used to locate the appId give the parentAppId and jsId)
|
||||||
|
if( jsId == nullptr || strlen(jsId) == 0 )
|
||||||
|
return cwLogError(kInvalidIdRC,"Registered parent/child app id's must have a valid 'jsId'.");
|
||||||
|
|
||||||
|
// verify that the parent/child pair is unique
|
||||||
|
if( _findAppIdMap(p,parentAppId,appId) != nullptr )
|
||||||
|
return cwLogError(kDuplicateRC,"An attempt was made to register a duplicate parent/child appid pair. parentId:%i appId:%i jsId:'%s'.",parentAppId,appId,cwStringNullGuard(jsId));
|
||||||
|
|
||||||
|
// verify that the parent/js pair is unique
|
||||||
|
if( _findAppIdMap(p,parentAppId,jsId) != nullptr )
|
||||||
|
return cwLogError(kDuplicateRC,"An attempt was made to register a duplicate parent app id/js id pair. parentId:%i appId:%i jsId:'%s'.",parentAppId,appId,cwStringNullGuard(jsId));
|
||||||
|
|
||||||
|
// allocate and link in a new appId map record
|
||||||
|
appIdMapRecd_t* m = mem::allocZ<appIdMapRecd_t>();
|
||||||
|
m->parentAppId = parentAppId;
|
||||||
|
m->appId = appId;
|
||||||
|
m->jsId = mem::duplStr(jsId);
|
||||||
|
m->link = p->appIdMap;
|
||||||
|
p->appIdMap = m;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
ele_t* _createEle( ui_t* p, ele_t* parent, unsigned appId, const char* jsId )
|
ele_t* _createEle( ui_t* p, ele_t* parent, unsigned appId, const char* jsId )
|
||||||
{
|
{
|
||||||
ele_t* e = mem::allocZ<ele_t>();
|
ele_t* e = mem::allocZ<ele_t>();
|
||||||
@ -75,6 +151,7 @@ namespace cw
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a uuId return a pointer to the associated element.
|
||||||
ele_t* _uuIdToEle( ui_t* p, unsigned uuId, bool errorFl=true )
|
ele_t* _uuIdToEle( ui_t* p, unsigned uuId, bool errorFl=true )
|
||||||
{
|
{
|
||||||
if( uuId >= p->eleN )
|
if( uuId >= p->eleN )
|
||||||
@ -86,10 +163,26 @@ namespace cw
|
|||||||
return p->eleA[ uuId ];
|
return p->eleA[ uuId ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a parent UuId and a javascript id find the associated ele
|
||||||
rc_t _websockSend( ui_t* p, const char* msg )
|
ele_t* _parentUuId_JsId_ToEle( ui_t* p, unsigned parentUuId, const char* jsId, bool errorFl=true )
|
||||||
{
|
{
|
||||||
return websock::send( websockSrv::websockHandle( p->wssH ), kUiProtocolId, msg, strlen(msg) );
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( ((p->eleA[i]->parent==nullptr && parentUuId == kRootUuId) || (p->eleA[i]->parent != nullptr && parentUuId == p->eleA[i]->parent->uuId)) && (strcmp(p->eleA[i]->jsId,jsId) == 0))
|
||||||
|
return p->eleA[i];
|
||||||
|
|
||||||
|
if( errorFl )
|
||||||
|
cwLogError(kInvalidIdRC,"The element with parent uuid:%i and jsId:%s is not found.",parentUuId,jsId);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned _findElementUuId( ui_t* p, const char* jsId )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->eleN; ++i)
|
||||||
|
if( strcmp(p->eleA[i]->jsId,jsId) == 0 )
|
||||||
|
return p->eleA[i]->uuId;
|
||||||
|
|
||||||
|
return kInvalidId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _findEleJsId( ui_t* p, unsigned uuId )
|
const char* _findEleJsId( ui_t* p, unsigned uuId )
|
||||||
@ -101,6 +194,12 @@ namespace cw
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _websockSend( ui_t* p, unsigned wsSessId, const char* msg )
|
||||||
|
{
|
||||||
|
return websock::send( websockSrv::websockHandle( p->wssH ), kUiProtocolId, wsSessId, msg, strlen(msg) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Print the attribute data value.
|
// Print the attribute data value.
|
||||||
template< typename T0 >
|
template< typename T0 >
|
||||||
unsigned format_attribute_data( char* buf, unsigned n, T0 t0 )
|
unsigned format_attribute_data( char* buf, unsigned n, T0 t0 )
|
||||||
@ -135,69 +234,137 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
template< typename... 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 )
|
rc_t _createOneEle( ui_t* p, unsigned& uuIdRef, const char* eleTypeStr, unsigned wsSessId, 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' } }
|
// { op:create, parent:my_parent_id, value:{ button:{ jsId:my_jsId, appId:appId, uuId:uuId, class:clas, title:'my title' } }
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const char* parentJsId = "";
|
const char* parentJsId = "";
|
||||||
ele_t* newEle = nullptr;
|
ele_t* newEle = nullptr;
|
||||||
ele_t* parentEle = nullptr;
|
ele_t* parentEle = nullptr;
|
||||||
const unsigned bufN = 1024;
|
//const unsigned bufN = 1024; // TODO: use preallocated buffer
|
||||||
char buf[ bufN ];
|
//char buf[ bufN ];
|
||||||
|
|
||||||
uuIdRef = kInvalidId;
|
uuIdRef = kInvalidId;
|
||||||
|
|
||||||
//
|
if( parentUuId == kInvalidId )
|
||||||
if( parentUuId != kInvalidId )
|
parentUuId = kRootUuId;
|
||||||
{
|
|
||||||
|
// get the parent element
|
||||||
if(( parentEle = _uuIdToEle(p, parentUuId )) == nullptr )
|
if(( parentEle = _uuIdToEle(p, parentUuId )) == nullptr )
|
||||||
return cwLogError( kInvalidArgRC, "Unable to locate the parent element (id:%i).", parentUuId );
|
return cwLogError( kInvalidArgRC, "Unable to locate the parent element (id:%i).", parentUuId );
|
||||||
|
|
||||||
|
// get the parent jsId
|
||||||
parentJsId = parentEle->jsId;
|
parentJsId = parentEle->jsId;
|
||||||
}
|
|
||||||
|
|
||||||
|
// create the local representation of the new element
|
||||||
newEle = _createEle( p, parentEle, appId, jsId );
|
newEle = _createEle( p, parentEle, appId, jsId );
|
||||||
|
|
||||||
unsigned i = snprintf( buf, bufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":{ \"%s\":{ \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i, \"class\":\"%s\", \"title\":\"%s\" ", parentJsId, eleTypeStr, jsId, appId, newEle->uuId, clas, title );
|
// form the create json message string
|
||||||
|
unsigned i = snprintf( p->buf, p->bufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":{ \"%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)...);
|
// add the UI specific attributes
|
||||||
|
i += format_attributes(p->buf+i, p->bufN-i, 0, std::forward<ARGS>(args)...);
|
||||||
|
|
||||||
toText(buf+i, bufN-i, "}}}");
|
// terminate the message
|
||||||
|
i += toText(p->buf+i, p->bufN-i, "}}}");
|
||||||
|
|
||||||
printf("%s\n",buf);
|
if( i >= p->bufN )
|
||||||
|
return cwLogError(kBufTooSmallRC,"The UI message formatting buffer is too small. (size:%i bytes)", p->bufN);
|
||||||
|
|
||||||
rc = _websockSend( p, buf );
|
printf("%s\n",p->buf);
|
||||||
|
|
||||||
|
// send the message
|
||||||
|
rc = _websockSend( p, wsSessId, p->buf );
|
||||||
|
|
||||||
uuIdRef = newEle->uuId;
|
uuIdRef = newEle->uuId;
|
||||||
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _decorateObj( ui_t* p, object_t* o )
|
||||||
rc_t _createFromObj( ui_t* p, object_t* o, unsigned parentUuId )
|
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
object_t* pid;
|
const object_t* oo;
|
||||||
|
ele_t* parent_ele;
|
||||||
|
const char* jsId;
|
||||||
|
|
||||||
// BUG BUG BUG - if kInvalidId is used both to indicate a NULL valid
|
// find the parent pair
|
||||||
// and the root object then there is no way to override the parent
|
if((oo = o->find( "parent", kNoRecurseFl | kOptionalFl)) != nullptr )
|
||||||
// that is coded into the file with the root object. A special
|
|
||||||
// rootId needs to be created.
|
|
||||||
|
|
||||||
if((pid = o->find("parent",false)) != nullptr && parentUuId == kInvalidId )
|
|
||||||
{
|
{
|
||||||
// get the parent JS id from the cfg object
|
|
||||||
|
|
||||||
// get the parent uuid from the JS id (verify that there is no ambiguity)
|
|
||||||
|
|
||||||
// delete the 'parent' pair
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// form the msg string
|
// find the parent JsId
|
||||||
|
if((rc = oo->value(jsId)) != kOkRC )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the parent element
|
||||||
|
//if((parent_ele = _jsIdToEle( p, jsId )) == nullptr )
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _createFromObj( ui_t* p, object_t* o, unsigned wsSessId, unsigned parentUuId )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* parentJsId = "";
|
||||||
|
const int kBufN = 512; // TODO: preallocate this buffer as part of ui_t.
|
||||||
|
char buf0[ kBufN ];
|
||||||
|
char buf1[ kBufN ];
|
||||||
|
|
||||||
|
// if a parentUuid was given ...
|
||||||
|
if( parentUuId != kInvalidId )
|
||||||
|
{
|
||||||
|
// ... then find the associated JS id
|
||||||
|
if((parentJsId = _findEleJsId( p, parentUuId )) == nullptr )
|
||||||
|
return cwLogError(kInvalidIdRC, "The JS id associated with the uuid '%i' could not be found for an resource object.", parentUuId );
|
||||||
|
}
|
||||||
|
else // if no parentUuid was given then look for one in the resource
|
||||||
|
{
|
||||||
|
// get the parent JS id from the cfg object
|
||||||
|
rc = o->get("parent",parentJsId,kNoRecurseFl | kOptionalFl);
|
||||||
|
|
||||||
|
switch(rc)
|
||||||
|
{
|
||||||
|
case kOkRC:
|
||||||
|
// get a pointer to the jsId from the local list (the copy in the object is about to be deleted)
|
||||||
|
parentJsId = _findEleJsId( p, _findElementUuId(p,parentJsId));
|
||||||
|
|
||||||
|
//remove the parent link
|
||||||
|
o->find("parent")->parent->free();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kLabelNotFoundRC:
|
||||||
|
parentJsId = _findEleJsId( p, kRootUuId );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
rc = cwLogError(rc,"The resource object parent id '%s' could not be found.", parentJsId );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// form the msg string from the resource
|
||||||
|
if( o->to_string( buf0, kBufN ) >= kBufN )
|
||||||
|
return cwLogError(kBufTooSmallRC,"The resource object string buffer is too small (buf bytes:%i).",kBufN);
|
||||||
|
|
||||||
|
printf("buf0: %s\n",buf0);
|
||||||
|
if( snprintf( buf1, kBufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":%s }", parentJsId, buf0 ) >= kBufN )
|
||||||
|
return cwLogError(kBufTooSmallRC,"The resource object string buffer is too small (buf bytes:%i).",kBufN);
|
||||||
|
|
||||||
|
|
||||||
// send the msg string
|
// send the msg string
|
||||||
|
printf("buf1: %s\n",buf1);
|
||||||
|
|
||||||
|
rc = _websockSend( p, wsSessId, buf1 );
|
||||||
|
|
||||||
|
|
||||||
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +388,7 @@ namespace cw
|
|||||||
|
|
||||||
if( s == nullptr || sscanf(msg, "value %i %c ",&eleUuId,&argType) != 2 )
|
if( s == nullptr || sscanf(msg, "value %i %c ",&eleUuId,&argType) != 2 )
|
||||||
{
|
{
|
||||||
cwLogError(kSyntaxErrorRC,"Invalid message from UI: %s.", msg );
|
cwLogError(kSyntaxErrorRC,"Invalid message from UI: '%s'.", msg );
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,13 +445,122 @@ namespace cw
|
|||||||
return ele;
|
return ele;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _websockCb( void* cbArg, unsigned protocolId, unsigned connectionId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
|
rc_t _send_app_id_msg( ui_t* p, unsigned wsSessId, ele_t* ele )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
unsigned i = snprintf(p->buf,p->bufN,"{ \"op\":\"set_app_id\", \"parentUuId\":%i, \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i }", ele->parent->uuId, ele->jsId, ele->parent->appId, ele->appId );
|
||||||
|
|
||||||
|
if( i >= p->bufN )
|
||||||
|
return cwLogError(kBufTooSmallRC,"The 'app_id' msg formatting buffer is too small (%i bytes).", p->bufN);
|
||||||
|
|
||||||
|
if((rc = _websockSend( p, wsSessId, p->buf )) != kOkRC )
|
||||||
|
return cwLogError(rc,"'app_id' msg transmission failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ele_t* _handle_register_msg( ui_t* p, unsigned wsSessId, const char* msg )
|
||||||
|
{
|
||||||
|
printf("%s\n",msg);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ele_t* _handle_register_msg0( ui_t* p, unsigned wsSessId, const char* msg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned parentUuId = kInvalidId;
|
||||||
|
ele_t* parentEle = nullptr;
|
||||||
|
ele_t* ele = nullptr;
|
||||||
|
|
||||||
|
const char* s0 = nextNonWhiteChar(msg + strlen("register"));
|
||||||
|
|
||||||
|
const char* jsId = nextNonWhiteChar(nextWhiteChar(s0));
|
||||||
|
|
||||||
|
// verifity the message tokens
|
||||||
|
if( s0 == nullptr || jsId == nullptr )
|
||||||
|
{
|
||||||
|
cwLogError(kSyntaxErrorRC, "'register' msg format error: '%s' is not a valid message.", cwStringNullGuard(msg) );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the parentUuId parsing
|
||||||
|
if((rc = string_to_number<unsigned>(s0,parentUuId)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(kSyntaxErrorRC, "'register' msg parentUuId format error: '%s' does not contain a valid parentUuId.", cwStringNullGuard(msg) );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the parent ele
|
||||||
|
if((parentEle = _uuIdToEle( p, parentUuId)) == nullptr )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidIdRC,"UI register msg parent element not found.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the child element does not already exist
|
||||||
|
if(( ele = _parentUuId_JsId_ToEle( p, parentUuId, jsId, false )) == nullptr )
|
||||||
|
{
|
||||||
|
// look up the parent/jsId pair map
|
||||||
|
appIdMapRecd_t* m = _findAppIdMap( p, parentEle->appId, jsId );
|
||||||
|
|
||||||
|
// create the ele
|
||||||
|
ele = _createEle( p, parentEle, m==nullptr ? kInvalidId : m->appId, jsId );
|
||||||
|
|
||||||
|
printf("creating: parent uuid:%i js:%s \n", parentUuId,jsId);
|
||||||
|
|
||||||
|
// notify the app of the new ele's uuid and appId
|
||||||
|
if( m != nullptr )
|
||||||
|
_send_app_id_msg( p, wsSessId, ele );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("parent uuid:%i js:%s already exists.\n", parentUuId,jsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ele != nullptr )
|
||||||
|
_send_app_id_msg( p, wsSessId, ele );
|
||||||
|
|
||||||
|
return ele;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
opId_t _labelToOpId( const char* label )
|
||||||
|
{
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
opId_t id;
|
||||||
|
const char* label;
|
||||||
|
} map_t;
|
||||||
|
|
||||||
|
map_t mapA[] =
|
||||||
|
{
|
||||||
|
{ kConnectOpId, "connect" },
|
||||||
|
{ kInitOpId, "init" },
|
||||||
|
{ kValueOpId, "value" },
|
||||||
|
{ kRegisterOpId, "register" },
|
||||||
|
{ kDisconnectOpId, "disconnect" },
|
||||||
|
{ kEndAppIdUpdateOpId, "end_app_id_update" },
|
||||||
|
{ kInvalidOpId, "<invalid>" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for(unsigned i=0; mapA[i].id != kInvalidOpId; ++i)
|
||||||
|
if( textCompare(label,mapA[i].label,strlen(mapA[i].label)) == 0 )
|
||||||
|
return mapA[i].id;
|
||||||
|
|
||||||
|
return kInvalidOpId;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _websockCb( void* cbArg, unsigned protocolId, unsigned wsSessId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
|
||||||
{
|
{
|
||||||
ui_t* p = (ui_t*)cbArg;
|
ui_t* p = (ui_t*)cbArg;
|
||||||
opId_t opId = kInvalidOpId;
|
opId_t opId = kInvalidOpId;
|
||||||
unsigned eleUuId = kInvalidId;
|
|
||||||
unsigned eleAppId = kInvalidId;
|
|
||||||
unsigned parentEleAppId = kInvalidId;
|
|
||||||
value_t value;
|
value_t value;
|
||||||
|
|
||||||
switch( msg_type )
|
switch( msg_type )
|
||||||
@ -301,32 +577,63 @@ namespace cw
|
|||||||
{
|
{
|
||||||
ele_t* ele;
|
ele_t* ele;
|
||||||
|
|
||||||
if( textCompare((const char*)msg,"init",strlen("init")) == 0 )
|
opId = _labelToOpId((const char*)msg);
|
||||||
|
|
||||||
|
switch( opId )
|
||||||
{
|
{
|
||||||
opId = kInitOpId;
|
case kInitOpId:
|
||||||
}
|
// Pass on the 'init' msg to the app.
|
||||||
else
|
p->cbFunc( p->cbArg, wsSessId, opId, kInvalidId, kInvalidId, kInvalidId, nullptr );
|
||||||
{
|
|
||||||
opId = kValueOpId;
|
// The UI is initialized - begin the id update process
|
||||||
|
if( _websockSend( p, wsSessId, "{ \"op\":\"begin_app_id_update\" }" ) != kOkRC )
|
||||||
|
cwLogError(kOpFailRC,"'begin_app_id_update' transmit failed.");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kValueOpId:
|
||||||
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
|
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
|
||||||
cwLogError(kOpFailRC,"UI Value message parse failed.");
|
cwLogError(kOpFailRC,"UI Value message parse failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
eleUuId = ele->uuId;
|
unsigned parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
|
||||||
eleAppId = ele->appId;
|
|
||||||
parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
|
p->cbFunc( p->cbArg, wsSessId, opId, parentEleAppId, ele->uuId, ele->appId, &value );
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case kRegisterOpId:
|
||||||
|
_handle_register_msg(p, wsSessId, (const char*)msg );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kEndAppIdUpdateOpId:
|
||||||
|
_print_eles( p );
|
||||||
|
cwLogInfo("App Id Update Complete.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case kInvalidOpId:
|
||||||
|
cwLogError(kInvalidIdRC,"The UI received a NULL op. id.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cwLogError(kInvalidIdRC,"The UI received an unknown op. id.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
} // switch opId
|
||||||
|
|
||||||
|
} // kMessageTId
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cwLogError(kInvalidOpRC,"Unknown websock message type:%i.", msg_type );
|
cwLogError(kInvalidOpRC,"Unknown websock message type:%i.", msg_type );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p->cbFunc != nullptr )
|
|
||||||
p->cbFunc( p->cbArg, connectionId, opId, parentEleAppId, eleUuId, eleAppId, &value );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,9 +647,11 @@ cw::rc_t cw::ui::createUi(
|
|||||||
const char* dfltPageFn,
|
const char* dfltPageFn,
|
||||||
unsigned websockTimeOutMs,
|
unsigned websockTimeOutMs,
|
||||||
unsigned rcvBufByteN,
|
unsigned rcvBufByteN,
|
||||||
unsigned xmtBufByteN )
|
unsigned xmtBufByteN,
|
||||||
|
unsigned fmtBufByteN)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
ele_t* ele;
|
||||||
|
|
||||||
websock::protocol_t protocolA[] =
|
websock::protocol_t protocolA[] =
|
||||||
{
|
{
|
||||||
@ -355,6 +664,9 @@ cw::rc_t cw::ui::createUi(
|
|||||||
if((rc = destroyUi(h)) != kOkRC )
|
if((rc = destroyUi(h)) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if( cbFunc == nullptr )
|
||||||
|
return cwLogError(kInvalidArgRC,"The UI callback function must be a valid pointer.");
|
||||||
|
|
||||||
ui_t* p = mem::allocZ<ui_t>();
|
ui_t* p = mem::allocZ<ui_t>();
|
||||||
|
|
||||||
if((rc = websockSrv::create(p->wssH, _websockCb, p, physRootDir, dfltPageFn, port, protocolA, protocolN, websockTimeOutMs )) != kOkRC )
|
if((rc = websockSrv::create(p->wssH, _websockCb, p, physRootDir, dfltPageFn, port, protocolA, protocolN, websockTimeOutMs )) != kOkRC )
|
||||||
@ -368,6 +680,15 @@ cw::rc_t cw::ui::createUi(
|
|||||||
p->eleN = 0;
|
p->eleN = 0;
|
||||||
p->cbFunc = cbFunc;
|
p->cbFunc = cbFunc;
|
||||||
p->cbArg = cbArg;
|
p->cbArg = cbArg;
|
||||||
|
p->buf = mem::allocZ<char>(fmtBufByteN);
|
||||||
|
p->bufN = fmtBufByteN;
|
||||||
|
|
||||||
|
// create the root element
|
||||||
|
if((ele = _createEle(p, nullptr, kRootEleAppId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId )
|
||||||
|
{
|
||||||
|
cwLogError(kOpFailRC,"The UI root element creation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
h.set(p);
|
h.set(p);
|
||||||
|
|
||||||
@ -431,10 +752,11 @@ unsigned cw::ui::findElementAppId( handle_t h, unsigned parentUuId, const char*
|
|||||||
unsigned cw::ui::findElementUuId( handle_t h, unsigned parentUuId, const char* jsId )
|
unsigned cw::ui::findElementUuId( handle_t h, unsigned parentUuId, const char* jsId )
|
||||||
{
|
{
|
||||||
ui_t* p = _handleToPtr(h);
|
ui_t* p = _handleToPtr(h);
|
||||||
|
ele_t* ele;
|
||||||
|
|
||||||
|
if((ele = _parentUuId_JsId_ToEle(p, parentUuId, jsId )) != nullptr )
|
||||||
|
return ele->uuId;
|
||||||
|
|
||||||
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;
|
return kInvalidId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,8 +776,15 @@ const char* cw::ui::findElementJsId( handle_t h, unsigned uuId )
|
|||||||
return _findEleJsId(p,uuId);
|
return _findEleJsId(p,uuId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned cw::ui::findElementUuId( handle_t h, const char* jsId )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parentUuId)
|
return _findElementUuId(p,jsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId)
|
||||||
{
|
{
|
||||||
ui_t* p = _handleToPtr(h);
|
ui_t* p = _handleToPtr(h);
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -464,12 +793,14 @@ cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parent
|
|||||||
if((rc = objectFromFile( fn, o )) != kOkRC )
|
if((rc = objectFromFile( fn, o )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = _createFromObj( p, o, parentUuId )) != kOkRC )
|
//o->print();
|
||||||
|
|
||||||
|
if((rc = _createFromObj( p, o, wsSessId, parentUuId )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
if(rc != kOkRC )
|
if(rc != kOkRC )
|
||||||
rc = cwLogError(rc,"UI from configuration the file '%s' failed.", cwStringNullGuard(fn));
|
rc = cwLogError(rc,"UI instantiation from the configuration file '%s' failed.", cwStringNullGuard(fn));
|
||||||
|
|
||||||
if( o != nullptr )
|
if( o != nullptr )
|
||||||
o->free();
|
o->free();
|
||||||
@ -477,7 +808,7 @@ cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parent
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentUuId)
|
cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned wsSessId, unsigned parentUuId)
|
||||||
{
|
{
|
||||||
ui_t* p = _handleToPtr(h);
|
ui_t* p = _handleToPtr(h);
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -486,12 +817,12 @@ cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentU
|
|||||||
if((rc = objectFromString( text, o )) != kOkRC )
|
if((rc = objectFromString( text, o )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = _createFromObj( p, o, parentUuId )) != kOkRC )
|
if((rc = _createFromObj( p, o, wsSessId, parentUuId )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
if(rc != kOkRC )
|
if(rc != kOkRC )
|
||||||
rc = cwLogError(rc,"UI from configuration the string '%s' failed.", cwStringNullGuard(text));
|
rc = cwLogError(rc,"UI instantiation failed from the configuration from string: '%s'.", cwStringNullGuard(text));
|
||||||
|
|
||||||
if( o != nullptr )
|
if( o != nullptr )
|
||||||
o->free();
|
o->free();
|
||||||
@ -499,34 +830,34 @@ cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentU
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::ui::createDiv( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
cw::rc_t cw::ui::createDiv( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{ return _createOneEle( _handleToPtr(h), uuIdRef, "div", parentUuId, jsId, appId, clas, title ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "div", wsSessId, 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 )
|
cw::rc_t cw::ui::createTitle( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", wsSessId, 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 )
|
cw::rc_t cw::ui::createButton( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{ return _createOneEle( _handleToPtr(h), uuIdRef, "button", parentUuId, jsId, appId, clas, title ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "button", wsSessId, 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 )
|
cw::rc_t cw::ui::createCheck( handle_t h, unsigned& uuIdRef, unsigned wsSessId, 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 ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "check", wsSessId, 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 )
|
cw::rc_t cw::ui::createSelect( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{ return _createOneEle( _handleToPtr(h), uuIdRef, "select", parentUuId, jsId, appId, clas, title ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "select", wsSessId, 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 )
|
cw::rc_t cw::ui::createOption( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", wsSessId, 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 )
|
cw::rc_t cw::ui::createString( handle_t h, unsigned& uuIdRef, unsigned wsSessId, 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 ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "string", wsSessId, 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 )
|
cw::rc_t cw::ui::createNumber( handle_t h, unsigned& uuIdRef, unsigned wsSessId, 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 ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "number", wsSessId, 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 )
|
cw::rc_t cw::ui::createProgress( handle_t h, unsigned& uuIdRef, unsigned wsSessId, 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 ); }
|
{ return _createOneEle( _handleToPtr(h), uuIdRef, "progress", wsSessId, 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 )
|
cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
|
||||||
{
|
{
|
||||||
rc_t rc= kOkRC;
|
rc_t rc= kOkRC;
|
||||||
return rc;
|
return rc;
|
||||||
@ -534,4 +865,19 @@ cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned parentUuI
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN )
|
||||||
|
{
|
||||||
|
ui_t* p = _handleToPtr(h);
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<mapN; ++i)
|
||||||
|
if((rc = _allocAppIdMap( p, map[i].parentAppId, map[i].appId, map[i].jsId )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
51
cwUi.h
51
cwUi.h
@ -21,6 +21,8 @@ namespace cw
|
|||||||
kConnectOpId,
|
kConnectOpId,
|
||||||
kInitOpId,
|
kInitOpId,
|
||||||
kValueOpId,
|
kValueOpId,
|
||||||
|
kRegisterOpId,
|
||||||
|
kEndAppIdUpdateOpId,
|
||||||
kDisconnectOpId
|
kDisconnectOpId
|
||||||
} opId_t;
|
} opId_t;
|
||||||
|
|
||||||
@ -35,6 +37,13 @@ namespace cw
|
|||||||
kStringTId
|
kStringTId
|
||||||
} dtypeId_t;
|
} dtypeId_t;
|
||||||
|
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kRootUuId = 0,
|
||||||
|
kRootEleAppId,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
dtypeId_t tid;
|
dtypeId_t tid;
|
||||||
@ -49,7 +58,7 @@ namespace cw
|
|||||||
} u;
|
} u;
|
||||||
} value_t;
|
} value_t;
|
||||||
|
|
||||||
typedef rc_t (*uiCallback_t)( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* value );
|
typedef rc_t (*uiCallback_t)( void* cbArg, unsigned websockSessionId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* value );
|
||||||
|
|
||||||
rc_t createUi( handle_t& h,
|
rc_t createUi( handle_t& h,
|
||||||
unsigned port,
|
unsigned port,
|
||||||
@ -59,7 +68,8 @@ namespace cw
|
|||||||
const char* dfltPageFn = "index.html",
|
const char* dfltPageFn = "index.html",
|
||||||
unsigned websockTimeOutMs = 50,
|
unsigned websockTimeOutMs = 50,
|
||||||
unsigned rcvBufByteN = 1024,
|
unsigned rcvBufByteN = 1024,
|
||||||
unsigned xmtBufByteN = 1024);
|
unsigned xmtBufByteN = 1024,
|
||||||
|
unsigned fmtBufByteN = 4096 );
|
||||||
|
|
||||||
rc_t destroyUi( handle_t& h );
|
rc_t destroyUi( handle_t& h );
|
||||||
|
|
||||||
@ -71,18 +81,31 @@ namespace cw
|
|||||||
unsigned findElementUuId( handle_t h, unsigned parentUuId, unsigned appId );
|
unsigned findElementUuId( handle_t h, unsigned parentUuId, unsigned appId );
|
||||||
const char* findElementJsId( handle_t h, unsigned uuId );
|
const char* findElementJsId( handle_t h, unsigned uuId );
|
||||||
|
|
||||||
rc_t createFromFile( handle_t h, const char* fn, unsigned parentUuId=kInvalidId);
|
// Return the uuid of the first matching 'jsId'.
|
||||||
rc_t createFromText( handle_t h, const char* text, unsigned parentUuId=kInvalidId);
|
unsigned findElementUuId( handle_t h, const char* jsId );
|
||||||
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 createFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId=kInvalidId);
|
||||||
rc_t createButton( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
rc_t createFromText( handle_t h, const char* text, unsigned wsSessId, unsigned parentUuId=kInvalidId);
|
||||||
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 createDiv( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
rc_t createSelect( 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 wsSessId, 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 createButton( handle_t h, unsigned& uuIdRef, unsigned wsSessId, 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 createCheck( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool 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 createSelect( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
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 createOption( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
rc_t createText( 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 wsSessId, 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 wsSessId, 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 wsSessId, 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 wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
|
||||||
|
|
||||||
|
typedef struct appIdMap_str
|
||||||
|
{
|
||||||
|
unsigned parentAppId;
|
||||||
|
unsigned appId;
|
||||||
|
const char* jsId;
|
||||||
|
} appIdMap_t;
|
||||||
|
|
||||||
|
// Register parent/child/js app id's
|
||||||
|
rc_t registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
cwUiTest.cpp
46
cwUiTest.cpp
@ -13,6 +13,7 @@ namespace cw
|
|||||||
typedef struct ui_test_str
|
typedef struct ui_test_str
|
||||||
{
|
{
|
||||||
handle_t uiH;
|
handle_t uiH;
|
||||||
|
const char* uiCfgFn;
|
||||||
} ui_test_t;
|
} ui_test_t;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -30,49 +31,51 @@ namespace cw
|
|||||||
kProgressId
|
kProgressId
|
||||||
};
|
};
|
||||||
|
|
||||||
rc_t _uiTestCreateUi( ui_test_t* p, unsigned connId )
|
rc_t _uiTestCreateUi( ui_test_t* p, unsigned wsSessId )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned uuid = kInvalidId;
|
unsigned uuid = kInvalidId;
|
||||||
unsigned selUuId = kInvalidId;
|
unsigned selUuId = kInvalidId;
|
||||||
unsigned divUuId = kInvalidId;
|
unsigned divUuId = kInvalidId;
|
||||||
|
|
||||||
if((rc = createDiv( p->uiH, divUuId, kInvalidId, "myDivId", kDivId, "divClass", "My Panel" )) != kOkRC )
|
if((rc = createDiv( p->uiH, divUuId, wsSessId, kInvalidId, "myDivId", kDivId, "divClass", "My Panel" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createButton( p->uiH, uuid, divUuId, "myBtnId", kBtnId, "btnClass", "Push Me" )) != kOkRC )
|
if((rc = createButton( p->uiH, uuid, wsSessId, divUuId, "myBtnId", kBtnId, "btnClass", "Push Me" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createCheck( p->uiH, uuid, divUuId, "myCheckId", kCheckId, "checkClass", "Check Me", true )) != kOkRC )
|
if((rc = createCheck( p->uiH, uuid, wsSessId, divUuId, "myCheckId", kCheckId, "checkClass", "Check Me", true )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createSelect( p->uiH, selUuId, divUuId, "mySelId", kSelectId, "selClass", "Select" )) != kOkRC )
|
if((rc = createSelect( p->uiH, selUuId, wsSessId, divUuId, "mySelId", kSelectId, "selClass", "Select" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt0Id", kOption0Id, "optClass", "Option 0" )) != kOkRC )
|
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt0Id", kOption0Id, "optClass", "Option 0" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt1Id", kOption1Id, "optClass", "Option 1" )) != kOkRC )
|
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt1Id", kOption1Id, "optClass", "Option 1" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt2Id", kOption2Id, "optClass", "Option 2" )) != kOkRC )
|
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt2Id", kOption2Id, "optClass", "Option 2" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createString( p->uiH, uuid, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
|
if((rc = createString( p->uiH, uuid, wsSessId, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createNumber( p->uiH, uuid, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC )
|
if((rc = createNumber( p->uiH, uuid, wsSessId, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = createProgress( p->uiH, uuid, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
|
if((rc = createProgress( p->uiH, uuid, wsSessId, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = createFromFile( p->uiH, p->uiCfgFn, wsSessId )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _handleUiValueMsg( ui_test_t* p, unsigned connId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
rc_t _handleUiValueMsg( ui_test_t* p, unsigned wsSessId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
@ -105,26 +108,31 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _uiTestCallback( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
// This function is called by the websocket with messages comring from a remote UI.
|
||||||
|
rc_t _uiTestCallback( void* cbArg, unsigned wsSessId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
|
||||||
{
|
{
|
||||||
ui_test_t* p = (ui_test_t*)cbArg;
|
ui_test_t* p = (ui_test_t*)cbArg;
|
||||||
|
|
||||||
switch( opId )
|
switch( opId )
|
||||||
{
|
{
|
||||||
case kConnectOpId:
|
case kConnectOpId:
|
||||||
cwLogInfo("Connect: connId:%i.",connId);
|
cwLogInfo("Connect: wsSessId:%i.",wsSessId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kDisconnectOpId:
|
case kDisconnectOpId:
|
||||||
cwLogInfo("Disconnect: connId:%i.",connId);
|
cwLogInfo("Disconnect: wsSessId:%i.",wsSessId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kInitOpId:
|
case kInitOpId:
|
||||||
_uiTestCreateUi(p,connId);
|
_uiTestCreateUi(p,wsSessId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kRegisterOpId:
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case kValueOpId:
|
case kValueOpId:
|
||||||
_handleUiValueMsg( p, connId, parentAppId, uuId, appId, v );
|
_handleUiValueMsg( p, wsSessId, parentAppId, uuId, appId, v );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kInvalidOpId:
|
case kInvalidOpId:
|
||||||
@ -141,7 +149,7 @@ namespace cw
|
|||||||
cw::rc_t cw::ui::test( )
|
cw::rc_t cw::ui::test( )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const char* physRootDir = "/home/kevin/src/cw_rt/html/uiTest";
|
const char* physRootDir = "/home/kevin/src/cwtest/src/libcw/html/uiTest";
|
||||||
const char* dfltPageFn = "index.html";
|
const char* dfltPageFn = "index.html";
|
||||||
int port = 5687;
|
int port = 5687;
|
||||||
unsigned rcvBufByteN = 2048;
|
unsigned rcvBufByteN = 2048;
|
||||||
@ -151,6 +159,8 @@ cw::rc_t cw::ui::test( )
|
|||||||
char sbuf[ sbufN+1 ];
|
char sbuf[ sbufN+1 ];
|
||||||
ui_test_t* ui = mem::allocZ<ui_test_t>();
|
ui_test_t* ui = mem::allocZ<ui_test_t>();
|
||||||
|
|
||||||
|
ui->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg";
|
||||||
|
|
||||||
if((rc = createUi(ui->uiH, port, _uiTestCallback, ui, physRootDir, dfltPageFn, websockTimeOutMs, rcvBufByteN, xmtBufByteN )) != kOkRC )
|
if((rc = createUi(ui->uiH, port, _uiTestCallback, ui, physRootDir, dfltPageFn, websockTimeOutMs, rcvBufByteN, xmtBufByteN )) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
var _ws = null;
|
var _ws = null;
|
||||||
var _dfltParentId = "uiDivId";
|
var _rootJsId = "uiDivId";
|
||||||
|
var _nextEleId = 0;
|
||||||
|
|
||||||
function set_app_title( suffix, className )
|
function set_app_title( suffix, className )
|
||||||
{
|
{
|
||||||
@ -164,8 +165,6 @@ function uiNumberSet( r )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function dom_id_to_ele( id )
|
|
||||||
{ return document.getElementById(id); }
|
|
||||||
|
|
||||||
function dom_child_by_id( parentEle, child_id )
|
function dom_child_by_id( parentEle, child_id )
|
||||||
{
|
{
|
||||||
@ -194,11 +193,6 @@ function dom_set_option_by_text( ele_id, text )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
function dom_set_number( ele_id, val )
|
||||||
@ -206,14 +200,53 @@ function dom_set_number( ele_id, val )
|
|||||||
dom_id_to_ele(ele_id).value = val
|
dom_id_to_ele(ele_id).value = val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
function dom_id_to_ele( id )
|
||||||
|
{ return document.getElementById(id); }
|
||||||
|
|
||||||
|
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_create_ele( ele_type )
|
||||||
|
{
|
||||||
|
ele = document.createElement(ele_type);
|
||||||
|
ele.id = _nextEleId;
|
||||||
|
_nextEleId += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
function ui_error( msg )
|
function ui_error( msg )
|
||||||
{
|
{
|
||||||
console.log("Error: " + msg )
|
console.log("Error: " + msg )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ui_send_value( ele, typeId, value )
|
||||||
|
{
|
||||||
|
if( ele.hasOwnProperty('uuId') )
|
||||||
|
ws_send("value " + ele.uuId + " " + typeId + " : " + value)
|
||||||
|
else
|
||||||
|
ui_error("A value msg send failed because the value had no UuId.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function ui_send_bool_value( ele, value ) { ui_send_value(ele,'b',value); }
|
||||||
|
function ui_send_int_value( ele, value ) { ui_send_value(ele,'i',value); }
|
||||||
|
function ui_send_string_value( ele, value ) { ui_send_value(ele,'s',value); }
|
||||||
|
|
||||||
|
function ui_send_register( ele )
|
||||||
|
{
|
||||||
|
ws_send("register " + ele.parentJsId + " " + ele.jsId + " " + ele.id + " " + ele.uuId + " " + ele.appId )
|
||||||
|
}
|
||||||
|
|
||||||
function ui_print_children( eleId )
|
function ui_print_children( eleId )
|
||||||
{
|
{
|
||||||
var childrenL = document.getElementById(eleId).children
|
var childrenL = dom_id_to_ele(eleId).children
|
||||||
|
|
||||||
for(var i=0; i<childrenL.length; i++)
|
for(var i=0; i<childrenL.length; i++)
|
||||||
{
|
{
|
||||||
@ -224,9 +257,9 @@ function ui_print_children( eleId )
|
|||||||
function ui_get_parent( parentId )
|
function ui_get_parent( parentId )
|
||||||
{
|
{
|
||||||
if( parentId==null || parentId.trim().length == 0 )
|
if( parentId==null || parentId.trim().length == 0 )
|
||||||
parentId = _dfltParentId
|
parentId = _rootJsId
|
||||||
|
|
||||||
parent_ele = document.getElementById(parentId);
|
parent_ele = dom_id_to_ele(parentId);
|
||||||
|
|
||||||
if( parent_ele == null )
|
if( parent_ele == null )
|
||||||
{
|
{
|
||||||
@ -240,16 +273,26 @@ function ui_get_parent( parentId )
|
|||||||
function ui_create_ele( parent_ele, ele_type, d )
|
function ui_create_ele( parent_ele, ele_type, d )
|
||||||
{
|
{
|
||||||
// create the ctl object
|
// create the ctl object
|
||||||
var ele = document.createElement(ele_type);
|
var ele = dom_create_ele(ele_type);
|
||||||
|
|
||||||
if( ele == null )
|
if( ele == null )
|
||||||
ui_error("'%s' element create failed.", ele_type);
|
ui_error("'%s' element create failed.", ele_type);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ele.id = d.jsId;
|
ele.jsId = d.jsId;
|
||||||
ele.uuId = d.uuId;
|
|
||||||
ele.appId = d.appId;
|
ele.parentJsId = d.parentJsId;
|
||||||
|
|
||||||
|
ele.uuId = d.hasOwnProperty("uuId") ? d.uuId : null
|
||||||
|
|
||||||
|
ele.appId = d.hasOwnProperty("appId") ? d.appId : null
|
||||||
|
|
||||||
|
console.log("Created: " + ele_type + " parent:" + d.parentJsId + " id:" + ele.id + " appId:" + ele.appId + " uuId:" + ele.uuId)
|
||||||
|
|
||||||
parent_ele.appendChild(ele);
|
parent_ele.appendChild(ele);
|
||||||
|
|
||||||
|
ui_send_register( ele );
|
||||||
|
|
||||||
}
|
}
|
||||||
return ele
|
return ele
|
||||||
}
|
}
|
||||||
@ -257,7 +300,7 @@ function ui_create_ele( parent_ele, ele_type, d )
|
|||||||
function ui_create_ctl( parent_ele, ele_type, label, d )
|
function ui_create_ctl( parent_ele, ele_type, label, d )
|
||||||
{
|
{
|
||||||
// create an enclosing div
|
// create an enclosing div
|
||||||
var div_ele = document.createElement("div");
|
var div_ele = dom_create_ele("div");
|
||||||
|
|
||||||
div_ele.className = d.clas;
|
div_ele.className = d.clas;
|
||||||
|
|
||||||
@ -268,7 +311,7 @@ function ui_create_ctl( parent_ele, ele_type, label, d )
|
|||||||
// if label is not null then create an enclosing 'label' element
|
// if label is not null then create an enclosing 'label' element
|
||||||
if( label != null )
|
if( label != null )
|
||||||
{
|
{
|
||||||
label_ele = document.createElement("label");
|
label_ele = dom_create_ele("label");
|
||||||
|
|
||||||
label_ele.innerHTML = label;
|
label_ele.innerHTML = label;
|
||||||
|
|
||||||
@ -283,12 +326,11 @@ function ui_create_div( parent_ele, d )
|
|||||||
{
|
{
|
||||||
var div_ele = ui_create_ele( parent_ele, "div", d );
|
var div_ele = ui_create_ele( parent_ele, "div", d );
|
||||||
|
|
||||||
|
|
||||||
if( div_ele != null )
|
if( div_ele != null )
|
||||||
{
|
{
|
||||||
div_ele.className = d.clas
|
div_ele.className = d.clas
|
||||||
|
|
||||||
var p_ele = document.createElement("p")
|
var p_ele = dom_create_ele("p")
|
||||||
|
|
||||||
if( d.title != null && d.title.length > 0 )
|
if( d.title != null && d.title.length > 0 )
|
||||||
p_ele.innerHTML = d.title
|
p_ele.innerHTML = d.title
|
||||||
@ -296,7 +338,7 @@ function ui_create_div( parent_ele, d )
|
|||||||
div_ele.appendChild( p_ele )
|
div_ele.appendChild( p_ele )
|
||||||
}
|
}
|
||||||
|
|
||||||
return div_ele
|
return div_ele;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui_create_title( parent_ele, d )
|
function ui_create_title( parent_ele, d )
|
||||||
@ -311,10 +353,10 @@ function ui_create_button( parent_ele, d )
|
|||||||
if( ele != null )
|
if( ele != null )
|
||||||
{
|
{
|
||||||
ele.innerHTML = d.title;
|
ele.innerHTML = d.title;
|
||||||
ele.onclick = function() { _ws.send("value " + this.uuId + " i : 1"); }
|
ele.onclick = function() { ui_send_int_value(this,1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
return ele
|
return ele;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui_create_check( parent_ele, d )
|
function ui_create_check( parent_ele, d )
|
||||||
@ -327,15 +369,14 @@ function ui_create_check( parent_ele, d )
|
|||||||
|
|
||||||
dom_set_checkbox(ele.id, d.value );
|
dom_set_checkbox(ele.id, d.value );
|
||||||
|
|
||||||
ele.onclick = function() { _ws.send("value" + this.uuId + " b : " + dom_get_checkbox(this.id)); }
|
ele.onclick = function() { ui_send_bool_value(this,dom_get_checkbox(this.id)); }
|
||||||
}
|
}
|
||||||
|
return ele;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui_on_select( ele )
|
function ui_on_select( ele )
|
||||||
{
|
{
|
||||||
var s = "value " + ele.uuId + " i : " + ele.options[ ele.selectedIndex ].appId
|
ui_send_int_value(ele,ele.options[ ele.selectedIndex ].appId);
|
||||||
|
|
||||||
_ws.send( s );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui_create_select( parent_ele, d )
|
function ui_create_select( parent_ele, d )
|
||||||
@ -365,7 +406,7 @@ function ui_create_string( parent_ele, d )
|
|||||||
if( ele != null )
|
if( ele != null )
|
||||||
{
|
{
|
||||||
ele.value = d.value;
|
ele.value = d.value;
|
||||||
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ _ws.send("value" + this.uuId + " s : " + this.value + "\0");} } );
|
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ ui_send_string_value(this, this.value); }} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +418,9 @@ function ui_number_keyup( e )
|
|||||||
var ele = dom_id_to_ele(e.target.id)
|
var ele = dom_id_to_ele(e.target.id)
|
||||||
console.log(ele.value)
|
console.log(ele.value)
|
||||||
if( ele != null )
|
if( ele != null )
|
||||||
_ws.send("value" + ele.uuId + " i : " + ele.value);
|
{
|
||||||
|
ui_send_int_value(ele,ele.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +437,7 @@ function ui_create_number( parent_ele, d )
|
|||||||
ele.decpl = d.decpl;
|
ele.decpl = d.decpl;
|
||||||
ele.addEventListener('keyup', ui_number_keyup );
|
ele.addEventListener('keyup', ui_number_keyup );
|
||||||
}
|
}
|
||||||
|
return ele;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui_set_progress( ele_id, value )
|
function ui_set_progress( ele_id, value )
|
||||||
@ -415,70 +458,130 @@ function ui_create_progress( parent_ele, d )
|
|||||||
ele.minValue = d.min;
|
ele.minValue = d.min;
|
||||||
ui_set_progress( ele.id, d.value );
|
ui_set_progress( ele.id, d.value );
|
||||||
}
|
}
|
||||||
|
return ele
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ui_create( parentId, ele_type, d )
|
function ui_create( parentId, ele_type, d )
|
||||||
{
|
{
|
||||||
var parent_ele = ui_get_parent(parentId);
|
var parent_ele = ui_get_parent(parentId);
|
||||||
|
var ele = null;
|
||||||
|
|
||||||
if( parent_ele != null )
|
if( parent_ele != null )
|
||||||
{
|
{
|
||||||
|
d.parentJsId = parentId
|
||||||
|
|
||||||
switch( ele_type )
|
switch( ele_type )
|
||||||
{
|
{
|
||||||
case "div":
|
case "div":
|
||||||
ui_create_div( parent_ele, d )
|
ele = ui_create_div( parent_ele, d )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "title":
|
case "title":
|
||||||
ui_create_title( parent_ele, d )
|
ele = ui_create_title( parent_ele, d )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "button":
|
case "button":
|
||||||
ui_create_button( parent_ele, d )
|
ele = ui_create_button( parent_ele, d )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "check":
|
case "check":
|
||||||
ui_create_check( parent_ele, d )
|
ele = ui_create_check( parent_ele, d )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "select":
|
case "select":
|
||||||
ui_create_select( parent_ele, d );
|
ele = ui_create_select( parent_ele, d );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "option":
|
case "option":
|
||||||
ui_create_option( parent_ele, d );
|
ele = ui_create_option( parent_ele, d );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "string":
|
case "string":
|
||||||
ui_create_string( parent_ele, d );
|
ele = ui_create_string( parent_ele, d );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "number":
|
case "number":
|
||||||
ui_create_number( parent_ele, d );
|
ele = ui_create_number( parent_ele, d );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "progress":
|
case "progress":
|
||||||
ui_create_progress( parent_ele, d );
|
ele = ui_create_progress( parent_ele, d );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ui_error("Unknown UI element type: " + ele_type )
|
ui_error("Unknown UI element type: " + ele_type )
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if( d.hasOwnProperty("children") )
|
||||||
function ws_send( d )
|
{
|
||||||
|
for (const ele_type in d.children)
|
||||||
|
ui_create( d.jsId, ele_type, d.children[ele_type] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ui_uuid_to_ele( uuId, ele=null )
|
||||||
|
{
|
||||||
|
if( ele == null )
|
||||||
|
ele = dom_id_to_ele( _rootJsId )
|
||||||
|
|
||||||
|
if( ele.hasOwnProperty('uuId') )
|
||||||
|
{
|
||||||
|
if( ele.uuId == uuId )
|
||||||
|
return ele
|
||||||
|
|
||||||
|
for(var i=0; i<ele.childElementCount; ++i)
|
||||||
|
ui_uuid_to_ele( uuId, ele.children[i] )
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_error("The element with uuid: " + uuId + " was not found.")
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Do breadth first search for ele's without uuId's
|
||||||
|
function ui_next_ele_to_register( parentEle )
|
||||||
|
{
|
||||||
|
for(var i=0; i<parentEle.childElementCount; ++i)
|
||||||
|
{
|
||||||
|
var ele = parentEle.children[i]
|
||||||
|
|
||||||
|
if( ele.hasOwnProperty('uuId') && ele.uuId==null)
|
||||||
|
return ele
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i=0; i<parentEle.childElementCount; ++i)
|
||||||
|
{
|
||||||
|
var ele = ui_next_ele_to_register( parentEle.children[i])
|
||||||
|
|
||||||
|
if( ele != null )
|
||||||
|
return ele
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
function ui_set_app_uuId( d )
|
||||||
|
{
|
||||||
|
console.log(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ws_send( s )
|
||||||
{
|
{
|
||||||
s = JSON.stringify(d)
|
|
||||||
//console.log(s)
|
//console.log(s)
|
||||||
_ws.send(s)
|
|
||||||
|
_ws.send(s+"\0")
|
||||||
}
|
}
|
||||||
|
|
||||||
function ws_on_msg( jsonMsg )
|
function ws_on_msg( jsonMsg )
|
||||||
{
|
{
|
||||||
//console.log(jsonMsg)
|
console.log(jsonMsg)
|
||||||
|
|
||||||
d = JSON.parse(jsonMsg.data);
|
d = JSON.parse(jsonMsg.data);
|
||||||
|
|
||||||
switch( d.op )
|
switch( d.op )
|
||||||
@ -486,12 +589,18 @@ function ws_on_msg( jsonMsg )
|
|||||||
case 'create':
|
case 'create':
|
||||||
for (const ele_type in d.children)
|
for (const ele_type in d.children)
|
||||||
{
|
{
|
||||||
ui_create( d.parent, ele_type, d.value[ele_type] )
|
ui_create( d.parent, ele_type, d.children[ele_type] )
|
||||||
//console.log(`${ele_type}: ${d.value[ele_type]}`);
|
//console.log(`${ele_type}: ${d.value[ele_type]}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'set_app_id':
|
||||||
|
ui_set_app_uuId(d)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ui_error("Unknown UI operation. " + d.op )
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -507,12 +616,35 @@ function ws_on_close()
|
|||||||
set_app_title( "Disconnected", "title_disconnected" );
|
set_app_title( "Disconnected", "title_disconnected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ws_form_url(urlSuffix)
|
||||||
|
{
|
||||||
|
var pcol;
|
||||||
|
var u = document.URL;
|
||||||
|
|
||||||
|
pcol = "ws://";
|
||||||
|
if (u.substring(0, 4) === "http")
|
||||||
|
u = u.substr(7);
|
||||||
|
|
||||||
|
u = u.split("/");
|
||||||
|
|
||||||
|
return pcol + u[0] + "/" + urlSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
_ws = new WebSocket("ws://127.0.0.1:5687/","ui_protocol")
|
rootEle = dom_id_to_ele(_rootJsId);
|
||||||
|
rootEle.uuId = 0;
|
||||||
|
rootEle.id = _nextEleId;
|
||||||
|
_nextEleId += 1;
|
||||||
|
|
||||||
|
console.log(ws_form_url(""))
|
||||||
|
|
||||||
|
_ws = new WebSocket(ws_form_url(""),"ui_protocol")
|
||||||
|
|
||||||
_ws.onmessage = ws_on_msg
|
_ws.onmessage = ws_on_msg
|
||||||
_ws.onopen = ws_on_open
|
_ws.onopen = ws_on_open
|
||||||
_ws.onclose = ws_on_close;
|
_ws.onclose = ws_on_close;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
parent: "uiDivId"
|
||||||
|
|
||||||
div: {
|
div: {
|
||||||
|
|
||||||
title:"My panel",
|
jsId: "panelDivId",
|
||||||
|
class: "myPanelClass",
|
||||||
|
title: "My resource based panel",
|
||||||
|
|
||||||
children: {
|
children: {
|
||||||
|
|
||||||
button:{ id:myBtnId, title:"Push Me" },
|
button:{ jsId: myBtn1Id, title:"Push Me" },
|
||||||
check:{ id:myCheckId, title:"Check Me" },
|
check:{ jsId: myCheck1Id, title:"Check Me" },
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user