cwUI.h/cpp,cwUiTest.cpp,html/uiTest/ui.js : Implemented 'echo' protocol to send values to the browser. Implemented initial default HTML class attribute assignments.

This commit is contained in:
kevin.larke 2020-04-24 10:20:25 -04:00
parent 9288040004
commit ebfe4dd224
4 changed files with 310 additions and 38 deletions

112
cwUi.cpp
View File

@ -310,7 +310,7 @@ namespace cw
if( i >= p->bufN ) if( i >= p->bufN )
return cwLogError(kBufTooSmallRC,"The UI message formatting buffer is too small. (size:%i bytes)", p->bufN); return cwLogError(kBufTooSmallRC,"The UI message formatting buffer is too small. (size:%i bytes)", p->bufN);
printf("%s\n",p->buf); //printf("%s\n",p->buf);
// send the message // send the message
rc = _websockSend( p, wsSessId, p->buf ); rc = _websockSend( p, wsSessId, p->buf );
@ -403,7 +403,7 @@ namespace cw
goto errLabel; goto errLabel;
} }
printf("%s\n",p->buf); //printf("%s\n",p->buf);
if((rc = _websockSend( p, wsSessId, p->buf )) != kOkRC ) if((rc = _websockSend( p, wsSessId, p->buf )) != kOkRC )
{ {
@ -565,6 +565,31 @@ namespace cw
return ele; return ele;
} }
ele_t* _parse_echo_msg( ui_t* p, const char* msg )
{
unsigned eleUuId = kInvalidId;
ele_t* ele = nullptr;
if( sscanf(msg, "echo %i",&eleUuId) != 1 )
{
cwLogError(kSyntaxErrorRC,"Invalid message from UI: '%s'.", msg );
goto errLabel;
}
// locate the element record
if((ele = _uuIdToEle( p, eleUuId )) == nullptr )
{
cwLogError(kInvalidIdRC,"UI message elment not found.");
goto errLabel;
}
errLabel:
return ele;
}
opId_t _labelToOpId( const char* label ) opId_t _labelToOpId( const char* label )
{ {
typedef struct typedef struct
@ -578,6 +603,7 @@ namespace cw
{ kConnectOpId, "connect" }, { kConnectOpId, "connect" },
{ kInitOpId, "init" }, { kInitOpId, "init" },
{ kValueOpId, "value" }, { kValueOpId, "value" },
{ kEchoOpId, "echo" },
{ kDisconnectOpId, "disconnect" }, { kDisconnectOpId, "disconnect" },
{ kInvalidOpId, "<invalid>" }, { kInvalidOpId, "<invalid>" },
}; };
@ -588,6 +614,32 @@ namespace cw
return kInvalidOpId; return kInvalidOpId;
} }
template< typename T >
rc_t _sendValue( ui_t* p, unsigned wsSessId, unsigned uuId, const char* vFmt, const T& value, int vbufN=32 )
{
rc_t rc = kOkRC;
if( p->sendCbFunc != nullptr )
{
const char* mFmt = "{ \"op\":\"value\", \"uuId\":%i, \"value\":%s }";
const int mbufN = 128;
char vbuf[vbufN];
char mbuf[mbufN];
if( snprintf(vbuf,vbufN,vFmt,value) >= vbufN-1 )
return cwLogError(kBufTooSmallRC,"The value msg buffer is too small.");
if( snprintf(mbuf,mbufN,mFmt,uuId,vbuf) >= mbufN-1 )
return cwLogError(kBufTooSmallRC,"The msg buffer is too small.");
p->sendCbFunc(p->sendCbArg,wsSessId,mbuf,strlen(mbuf));
}
return rc;
}
} }
} }
@ -662,11 +714,15 @@ cw::rc_t cw::ui::destroy( handle_t& h )
cw::rc_t cw::ui::onConnect( handle_t h, unsigned wsSessId ) cw::rc_t cw::ui::onConnect( handle_t h, unsigned wsSessId )
{ {
ui_t* p = _handleToPtr(h);
p->uiCbFunc( p->uiCbArg, wsSessId, kConnectOpId, kInvalidId, kInvalidId, kInvalidId, nullptr );
return kOkRC; return kOkRC;
} }
cw::rc_t cw::ui::onDisconnect( handle_t h, unsigned wsSessId ) cw::rc_t cw::ui::onDisconnect( handle_t h, unsigned wsSessId )
{ {
ui_t* p = _handleToPtr(h);
p->uiCbFunc( p->uiCbArg, wsSessId, kDisconnectOpId, kInvalidId, kInvalidId, kInvalidId, nullptr );
return kOkRC; return kOkRC;
} }
@ -698,6 +754,18 @@ cw::rc_t cw::ui::onReceive( handle_t h, unsigned wsSessId, const void* msg, unsi
} }
break; break;
case kEchoOpId:
if((ele = _parse_echo_msg(p,(const char*)msg)) == nullptr )
cwLogError(kOpFailRC,"UI Echo message parse failed.");
else
{
unsigned parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
p->uiCbFunc( p->uiCbArg, wsSessId, opId, parentEleAppId, ele->uuId, ele->appId, nullptr );
}
break;
case kInvalidOpId: case kInvalidOpId:
cwLogError(kInvalidIdRC,"The UI received a NULL op. id."); cwLogError(kInvalidIdRC,"The UI received a NULL op. id.");
break; break;
@ -874,7 +942,43 @@ cw::rc_t cw::ui::registerAppIds( handle_t h, const appIdMap_t* map, unsigned ma
return rc; return rc;
} }
cw::rc_t cw::ui::sendValueBool( handle_t h, unsigned wsSessId, unsigned uuId, bool value )
{
ui_t* p = _handleToPtr(h);
return _sendValue<int>(p,wsSessId,uuId,"%i",value?1:0);
}
cw::rc_t cw::ui::sendValueInt( handle_t h, unsigned wsSessId, unsigned uuId, int value )
{
ui_t* p = _handleToPtr(h);
return _sendValue<int>(p,wsSessId,uuId,"%i",value);
}
cw::rc_t cw::ui::sendValueUInt( handle_t h, unsigned wsSessId, unsigned uuId, unsigned value )
{
ui_t* p = _handleToPtr(h);
return _sendValue<unsigned>(p,wsSessId,uuId,"%i",value);
}
cw::rc_t cw::ui::sendValueFloat( handle_t h, unsigned wsSessId, unsigned uuId, float value )
{
ui_t* p = _handleToPtr(h);
return _sendValue<float>(p,wsSessId,uuId,"%f",value);
}
cw::rc_t cw::ui::sendValueDouble( handle_t h, unsigned wsSessId, unsigned uuId, double value )
{
ui_t* p = _handleToPtr(h);
return _sendValue<double>(p,wsSessId,uuId,"%f",value);
}
cw::rc_t cw::ui::sendValueString( handle_t h, unsigned wsSessId, unsigned uuId, const char* value )
{
ui_t* p = _handleToPtr(h);
// +10 allows for extra value buffer space for double quotes and slashed
return _sendValue<const char*>(p,wsSessId,uuId,"\"%s\"",value,strlen(value)+10);
}
namespace cw namespace cw
{ {
@ -899,10 +1003,10 @@ namespace cw
{ {
rc_t rc; rc_t rc;
if((rc = ui::destroy(p->uiH)) != kOkRC ) if((rc = websock::destroy(p->wsH)) != kOkRC )
return rc; return rc;
if((rc = websock::destroy(p->wsH)) != kOkRC ) if((rc = ui::destroy(p->uiH)) != kOkRC )
return rc; return rc;
mem::release(p); mem::release(p);

9
cwUi.h
View File

@ -21,6 +21,7 @@ namespace cw
kConnectOpId, kConnectOpId,
kInitOpId, kInitOpId,
kValueOpId, kValueOpId,
kEchoOpId,
kDisconnectOpId kDisconnectOpId
} opId_t; } opId_t;
@ -104,6 +105,12 @@ namespace cw
// Register parent/child/name app id's // Register parent/child/name app id's
rc_t registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN ); rc_t registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN );
rc_t sendValueBool( handle_t h, unsigned wsSessId, unsigned uuId, bool value );
rc_t sendValueInt( handle_t h, unsigned wsSessId, unsigned uuId, int value );
rc_t sendValueUInt( handle_t h, unsigned wsSessId, unsigned uuId, unsigned value );
rc_t sendValueFloat( handle_t h, unsigned wsSessId, unsigned uuId, float value );
rc_t sendValueDouble( handle_t h, unsigned wsSessId, unsigned uuId, double value );
rc_t sendValueString( handle_t h, unsigned wsSessId, unsigned uuId, const char* value );
namespace ws namespace ws
{ {
@ -135,6 +142,8 @@ namespace cw
websock::handle_t websockHandle( handle_t h ); websock::handle_t websockHandle( handle_t h );
ui::handle_t uiHandle( handle_t h ); ui::handle_t uiHandle( handle_t h );
} }
namespace srv namespace srv

View File

@ -18,6 +18,13 @@ namespace cw
const char* uiCfgFn; const char* uiCfgFn;
srv::handle_t wsUiSrvH; srv::handle_t wsUiSrvH;
bool appCheckFl;
unsigned appSelectIndex;
int appInteger;
float appFloat;
int appProgress;
char* appString;
} ui_test_t; } ui_test_t;
enum enum
@ -31,7 +38,8 @@ namespace cw
kOption2Id, kOption2Id,
kOption3Id, kOption3Id,
kStringId, kStringId,
kNumberId, kIntegerId,
kFloatId,
kProgressId, kProgressId,
kPanelDivId, kPanelDivId,
@ -82,7 +90,10 @@ namespace cw
if((rc = createString( uiH, uuid, wsSessId, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC ) if((rc = createString( uiH, uuid, wsSessId, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
goto errLabel; goto errLabel;
if((rc = createNumber( uiH, uuid, wsSessId, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC ) if((rc = createNumber( uiH, uuid, wsSessId, divUuId, "myIntegerId", kIntegerId, "integerClass", "Integer", 10, 0, 100, 1, 0 )) != kOkRC )
goto errLabel;
if((rc = createNumber( uiH, uuid, wsSessId, divUuId, "myFloatId", kFloatId, "floatClass", "Float", 10.0, 0.53, 100.97, 1.0, 5 )) != kOkRC )
goto errLabel; goto errLabel;
if((rc = createProgress( uiH, uuid, wsSessId, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC ) if((rc = createProgress( uiH, uuid, wsSessId, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
@ -107,26 +118,69 @@ namespace cw
case kCheckId: case kCheckId:
printf("Check:%i\n", v->u.b); printf("Check:%i\n", v->u.b);
p->appCheckFl = v->u.b;
break; break;
case kSelectId: case kSelectId:
printf("Selected: optionId:%i\n", v->u.i); printf("Selected: optionId:%i\n", v->u.i);
p->appSelectIndex = v->u.i;
break; break;
case kStringId: case kStringId:
printf("String: %s\n",v->u.s); printf("String: %s\n",v->u.s);
mem::release(p->appString);
if( v->u.s != nullptr )
p->appString = mem::duplStr(v->u.s);
break;
case kNumberId: case kIntegerId:
if( v->tid == kIntTId ) printf("Integer: %i\n",v->u.i);
printf("Number: %i\n",v->u.i); p->appInteger = v->u.i;
else break;
printf("Number: %f\n",v->u.d);
case kFloatId:
printf("Float: %f\n",v->u.f);
p->appFloat = v->u.f;
} }
return rc; return rc;
} }
rc_t _handleUiEchoMsg( ui_test_t* p, unsigned wsSessId, unsigned parentAppId, unsigned uuId, unsigned appId )
{
rc_t rc = kOkRC;
switch( appId )
{
case kCheckId:
sendValueBool( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appCheckFl );
break;
case kSelectId:
sendValueInt( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appSelectIndex );
break;
case kStringId:
sendValueString( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appString );
break;
case kIntegerId:
sendValueInt( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appInteger );
break;
case kFloatId:
sendValueFloat( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appFloat );
break;
case kProgressId:
sendValueInt( uiHandle( p->wsUiSrvH ), wsSessId, uuId, p->appProgress );
break;
}
return rc;
}
// This function is called by the websocket with messages comring from a remote UI. // 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 ) rc_t _uiTestCallback( void* cbArg, unsigned wsSessId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
@ -151,6 +205,10 @@ namespace cw
_handleUiValueMsg( p, wsSessId, parentAppId, uuId, appId, v ); _handleUiValueMsg( p, wsSessId, parentAppId, uuId, appId, v );
break; break;
case kEchoOpId:
_handleUiEchoMsg( p, wsSessId, parentAppId, uuId, appId );
break;
case kInvalidOpId: case kInvalidOpId:
// fall through // fall through
default: default:
@ -176,6 +234,15 @@ cw::rc_t cw::ui::test( )
char sbuf[ sbufN+1 ]; char sbuf[ sbufN+1 ];
ui_test_t* app = mem::allocZ<ui_test_t>(); ui_test_t* app = mem::allocZ<ui_test_t>();
app->appCheckFl = true;
app->appSelectIndex = 1;
app->appInteger = 5;
app->appFloat = 2.56;
app->appProgress = 7;
app->appString = mem::duplStr("fooz");
app->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg"; app->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg";
// create the UI server // create the UI server
@ -208,6 +275,7 @@ cw::rc_t cw::ui::test( )
if( app->wsUiSrvH.isValid() ) if( app->wsUiSrvH.isValid() )
rc1 = srv::destroy(app->wsUiSrvH); rc1 = srv::destroy(app->wsUiSrvH);
mem::release(app->appString);
mem::release(app); mem::release(app);
return rcSelect(rc,rc1); return rcSelect(rc,rc1);

View File

@ -232,8 +232,13 @@ function ui_send_value( ele, typeId, value )
function ui_send_bool_value( ele, value ) { ui_send_value(ele,'b',value); } 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_int_value( ele, value ) { ui_send_value(ele,'i',value); }
function ui_send_float_value( ele, value ) { ui_send_value(ele,'f',value); }
function ui_send_string_value( ele, value ) { ui_send_value(ele,'s',value); } function ui_send_string_value( ele, value ) { ui_send_value(ele,'s',value); }
function ui_send_echo( ele )
{
ws_send("echo " + ele.id )
}
function ui_print_children( eleId ) function ui_print_children( eleId )
{ {
@ -261,7 +266,7 @@ function ui_get_parent( parentId )
} }
function ui_create_ele( parent_ele, ele_type, d ) function ui_create_ele( parent_ele, ele_type, d, dfltClassName )
{ {
// create the ctl object // create the ctl object
var ele = dom_create_ele(ele_type); var ele = dom_create_ele(ele_type);
@ -272,12 +277,17 @@ function ui_create_ele( parent_ele, ele_type, d )
{ {
ele.id = d.uuId; ele.id = d.uuId;
if(d.hasOwnProperty('className') )
ele.className = d.className;
else
ele.className = dfltClassName;
if(d.hasOwnProperty('appId')) if(d.hasOwnProperty('appId'))
ele.appId = d.appId; ele.appId = d.appId;
else else
ele.appId = null; ele.appId = null;
console.log("Created: " + ele_type + " parent:" + d.parentUuId + " id:" + ele.id + " appId:" + ele.appId) //console.log("Created: " + ele_type + " parent:" + d.parentUuId + " id:" + ele.id + " appId:" + ele.appId)
parent_ele.appendChild(ele); parent_ele.appendChild(ele);
@ -286,12 +296,12 @@ function ui_create_ele( parent_ele, ele_type, d )
return ele return ele
} }
function ui_create_ctl( parent_ele, ele_type, label, d ) function ui_create_ctl( parent_ele, ele_type, label, d, dfltEleClassName )
{ {
// create an enclosing div // create an enclosing div
var div_ele = dom_create_ele("div"); var div_ele = dom_create_ele("div");
div_ele.className = d.clas; div_ele.className = dfltEleClassName + "Div"
parent_ele.appendChild( div_ele ); parent_ele.appendChild( div_ele );
@ -307,18 +317,25 @@ function ui_create_ctl( parent_ele, ele_type, label, d )
div_ele.appendChild(label_ele) div_ele.appendChild(label_ele)
} }
return ui_create_ele( label_ele, ele_type, d ); return ui_create_ele( label_ele, ele_type, d, dfltEleClassName );
} }
function ui_set_class_name( ele, d, dfltClassName )
{
if( d.hasOwnProperty("className") )
ele.className = d.className;
else
ele.className = dfltClassName
return ele
}
function ui_create_div( parent_ele, d ) 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, "uiDiv" );
if( div_ele != null ) if( div_ele != null )
{ {
div_ele.className = d.clas
var p_ele = dom_create_ele("p") var p_ele = dom_create_ele("p")
if( d.title != null && d.title.length > 0 ) if( d.title != null && d.title.length > 0 )
@ -332,12 +349,12 @@ function ui_create_div( parent_ele, d )
function ui_create_title( parent_ele, d ) function ui_create_title( parent_ele, d )
{ {
return ui_create_ele( parent_ele, "label", d ); return ui_create_ele( parent_ele, "label", d, "uiTitle" );
} }
function ui_create_button( parent_ele, d ) function ui_create_button( parent_ele, d )
{ {
var ele = ui_create_ctl( parent_ele, "button", null, d ); var ele = ui_create_ctl( parent_ele, "button", null, d, "uiButton" );
if( ele != null ) if( ele != null )
{ {
@ -350,7 +367,7 @@ function ui_create_button( parent_ele, d )
function ui_create_check( parent_ele, d ) function ui_create_check( parent_ele, d )
{ {
var ele = ui_create_ctl( parent_ele, "input", d.title, d ) var ele = ui_create_ctl( parent_ele, "input", d.title, d, "uiCheck" )
if( ele != null ) if( ele != null )
{ {
@ -370,18 +387,18 @@ function ui_on_select( ele )
function ui_create_select( parent_ele, d ) function ui_create_select( parent_ele, d )
{ {
var sel_ele = ui_create_ctl( parent_ele, "select", d.title, d ); var sel_ele = ui_create_ctl( parent_ele, "select", d.title, d, "uiSelect" );
sel_ele.onchange = function() { ui_on_select(this) } sel_ele.onchange = function() { ui_on_select(this) }
return sel_ele; return sel_ele;
} }
function ui_create_option( parent_ele, d ) function ui_create_option( parent_ele, d )
{ {
var opt_ele = ui_create_ele( parent_ele, "option", d ); var opt_ele = ui_create_ele( parent_ele, "option", d, "uiOption" );
if( opt_ele != null ) if( opt_ele != null )
{ {
opt_ele.className = d.clas; opt_ele.className = d.className;
opt_ele.innerHTML = d.title; opt_ele.innerHTML = d.title;
} }
@ -390,13 +407,15 @@ function ui_create_option( parent_ele, d )
function ui_create_string( parent_ele, d ) function ui_create_string( parent_ele, d )
{ {
var ele = ui_create_ctl( parent_ele, "input", d.title, d ); var ele = ui_create_ctl( parent_ele, "input", d.title, d, "uiString" );
if( ele != null ) if( ele != null )
{ {
ele.value = d.value; ele.value = d.value;
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ ui_send_string_value(this, this.value); }} ); ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ ui_send_string_value(this, this.value); }} );
} }
return ele;
} }
function ui_number_keyup( e ) function ui_number_keyup( e )
@ -421,7 +440,14 @@ function ui_number_keyup( e )
{ {
ele.style.borderColor = "" ele.style.borderColor = ""
ui_send_int_value(ele,ele.value); if( ele.decpl == 0 )
{
ui_send_int_value(ele,ele.value);
}
else
{
ui_send_float_value(ele,ele.value);
}
} }
} }
} }
@ -429,7 +455,7 @@ function ui_number_keyup( e )
function ui_create_number( parent_ele, d ) function ui_create_number( parent_ele, d )
{ {
var ele = ui_create_ctl( parent_ele, "input", d.title, d ); var ele = ui_create_ctl( parent_ele, "input", d.title, d, "uiNumber" );
if( ele != null ) if( ele != null )
{ {
@ -452,7 +478,7 @@ function ui_set_progress( ele_id, value )
function ui_create_progress( parent_ele, d ) function ui_create_progress( parent_ele, d )
{ {
var ele = ui_create_ctl( parent_ele, "progress", d.title, d ); var ele = ui_create_ctl( parent_ele, "progress", d.title, d, "uiProgress" );
if( ele != null ) if( ele != null )
{ {
@ -464,6 +490,62 @@ function ui_create_progress( parent_ele, d )
return ele return ele
} }
function ui_set_value( d )
{
console.log(d)
var ele = dom_id_to_ele(d.uuId.toString())
if( ele == null )
console.log("ele not found");
else
if( !ele.hasOwnProperty("uiEleType") )
console.log("No type");
if( ele != null && ele.hasOwnProperty("uiEleType"))
{
console.log("found: "+ele.uiEleType)
switch( ele.uiEleType )
{
case "div":
break;
case "title":
ele.innerHTML = d.value
break;
case "button":
break;
case "check":
console.log(d)
dom_set_checkbox(ele.id,d.value)
break;
case "select":
ele.selectedIndex = d.value
break;
case "option":
break;
case "string":
ele.value = d.value
break;
case "number":
ele.value = d.value
break;
case "progress":
ele.value = d.value
break;
default:
ui_error("Unknown UI element type: " + d.type )
}
}
}
function ui_create( d ) function ui_create( d )
{ {
@ -521,6 +603,12 @@ function ui_create( d )
ui_error("Unknown UI element type: " + d.type ) ui_error("Unknown UI element type: " + d.type )
} }
if( ele != null )
{
ele.uiEleType = d.type;
ui_send_echo(ele);
}
} }
} }
@ -546,6 +634,9 @@ function ws_on_msg( jsonMsg )
ui_create( d ) ui_create( d )
break; break;
case 'value':
ui_set_value( d )
break;
default: default:
ui_error("Unknown UI operation. " + d.op ) ui_error("Unknown UI operation. " + d.op )