In this program, my purpose is to create hybrib web app (like http://nwjs.io/ or http://electron.atom.io/)
- local server coded in Purebasic
- frontend UI coded in HTML5 / Jquery / UI Kit
- communication between webgadget and purebasic app
- Resize window event
- Drag window event
- Supported OS: win7/8/10, mac, linux
- Add PostEvent data
Code: Select all
; **********************************
; JQuery events: https://api.jquery.com/category/events/
; UI KIT (visual framework): http://getuikit.com/index.html
; **********************************
EnableExplicit
Runtime Enumeration
#server : #file : #xml : #dialog : #win : #web
#border1 : #border2 : #border3 : #border4 : #border5 : #border6 : #border7 : #border8 : #toolbar
#maxmimize : #minimize : #close
#connect
EndEnumeration
Enumeration #PB_Event_FirstCustomValue + 678910101
#PB_Event_WebGadget
EndEnumeration
Procedure captureWindow(border=-1, mouseHitX=0, mouseHitY=0, nodeWidth=0, nodeHeight=0)
Static win, x, y, x2, y2, w, h, offsetX, offsetY, captureWindow
Protected refreshingDelay=20 ;laggy refreshing
Select border
Case -1
If captureWindow
x=#PB_Ignore
y=#PB_Ignore
w=#PB_Ignore
h=#PB_Ignore
If captureWindow=#toolbar
x=DesktopMouseX() + offsetX
y=DesktopMouseY() + offsetY
EndIf
If captureWindow=#border1 Or captureWindow=#border4 Or captureWindow=#border6
x=DesktopMouseX() + offsetX
w=(x2-x)
EndIf
If captureWindow=#border1 Or captureWindow=#border2 Or captureWindow=#border3
y=DesktopMouseY() + offsetY
h=(y2-y)
EndIf
If captureWindow=#border3 Or captureWindow=#border5 Or captureWindow=#border8
w=(DesktopMouseX()-WindowX(win)) + offsetX
EndIf
If captureWindow=#border6 Or captureWindow=#border7 Or captureWindow=#border8
h=(DesktopMouseY()-WindowY(win)) + offsetY
EndIf
ResizeWindow(win, x, y, w, h)
refreshingDelay=1 ;smooth refreshing
EndIf
Case 0
captureWindow=0
Debug "drag end"
Default
If captureWindow=0 And border>=#border1 And border<=#toolbar
Debug "drag start"
captureWindow=border
win=EventWindow()
If captureWindow=#toolbar
offsetX=-mouseHitX
offsetY=-mouseHitY
EndIf
If captureWindow=#border1 Or captureWindow=#border4 Or captureWindow=#border6
x2=WindowX(win) + WindowWidth(win)
offsetX=-mouseHitX
EndIf
If captureWindow=#border1 Or captureWindow=#border2 Or captureWindow=#border3
y2=WindowY(win) + WindowHeight(win)
offsetY=-mouseHitY
EndIf
If captureWindow=#border3 Or captureWindow=#border5 Or captureWindow=#border8
offsetX=nodeWidth-mouseHitX
EndIf
If captureWindow=#border6 Or captureWindow=#border7 Or captureWindow=#border8
offsetY=nodeHeight-mouseHitY
EndIf
EndIf
EndSelect
ProcedureReturn refreshingDelay
EndProcedure
CreateRegularExpression(0, "eventType=(?<eventType>[^&]+)" +
"(&eventWhich=(?<eventWhich>[^&]+))+" +
"(&eventGadget=(?<eventGadget>[^&]+))?" +
"(&nodeName=(?<nodeName>[^&]+))?" +
"(&nodeWidth=(?<nodeWidth>[^&]+))?" +
"(&nodeHeight=(?<nodeHeight>[^&]+))?" +
"(&mouseHitX=(?<mouseHitX>[^&]+))?" +
"(&mouseHitY=(?<mouseHitY>[^&]+))?")
Procedure WebServer(port)
InitNetwork()
Protected *Buffer=AllocateMemory(1000)
CreateNetworkServer(#server, port, #PB_Network_TCP, "127.0.0.1")
Repeat
Select NetworkServerEvent()
Case #PB_NetworkEvent_Data
Protected Client=EventClient()
Protected Size=ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
;Debug "msg from " + Client
If Size
Protected Answer$="Status: 200 OK" + #CRLF$ +
"Content-type: text/plain" + #CRLF$ + #CRLF$ +
"** Purebasic Response **" + #CRLF$
SendNetworkString(Client, Answer$)
Protected Buffer$=PeekS(*Buffer, Size, #PB_UTF8)
;Debug Buffer$
If ExamineRegularExpression(0, Buffer$)
If NextRegularExpressionMatch(0)
Protected eventType=#PB_Event_None
Protected eventType$=RegularExpressionNamedGroup(0, "eventType")
Protected eventWhich$=RegularExpressionNamedGroup(0, "eventWhich")
Protected eventGadget=-1
Protected eventGadget$=URLDecoder(RegularExpressionNamedGroup(0, "eventGadget"))
Protected nodeName$=RegularExpressionNamedGroup(0, "nodeName")
Protected nodeWidth=Val(RegularExpressionNamedGroup(0, "nodeWidth"))
Protected nodeHeight=Val(RegularExpressionNamedGroup(0, "nodeHeight"))
Protected mouseHitX=Val(RegularExpressionNamedGroup(0, "mouseHitX"))
Protected mouseHitY=Val(RegularExpressionNamedGroup(0, "mouseHitY"))
If IsRuntime(eventGadget$) : eventGadget=GetRuntimeInteger(eventGadget$) : EndIf
Debug Hex(Client) + ": " + eventType$ + " " + nodeName$ + " " + eventGadget$ + " " + mouseHitX + " " + mouseHitY + " " + nodeWidth + " " + nodeHeight + " " + ""
Select LCase(eventType$)
Case "click", "contextmenu" :
If eventWhich$="1" : eventType=#PB_EventType_LeftClick : Else : eventType=#PB_EventType_RightClick : EndIf
Case "dblclick" :
If eventWhich$="1" : eventType=#PB_EventType_LeftDoubleClick : Else : eventType=#PB_EventType_RightDoubleClick : EndIf
Case "mousedown"
Select eventWhich$
Case "1" : eventType=#PB_EventType_LeftButtonDown
captureWindow(eventGadget, mouseHitX, mouseHitY, nodeWidth, nodeHeight)
Case "2" : eventType=#PB_EventType_MiddleButtonDown
Case "3" : eventType=#PB_EventType_RightButtonDown
captureWindow(0)
EndSelect
Case "mouseup"
Select eventWhich$
Case "1" : eventType=#PB_EventType_LeftButtonUp
captureWindow(0)
Case "2" : eventType=#PB_EventType_MiddleButtonUp
Case "3" : eventType=#PB_EventType_RightButtonUp
EndSelect
Case "focusin" : eventType=#PB_EventType_Focus
Case "focusout" : eventType=#PB_EventType_LostFocus
Case "change" : eventType=#PB_EventType_Change
EndSelect
PostEvent(#PB_Event_WebGadget, EventWindow(), eventGadget, eventType)
EndIf
EndIf
If ConnectionID(Client)
Debug Hex(Client) + ": Disconnected!"
CloseNetworkConnection(Client)
EndIf
EndIf
EndSelect
Protected refreshingDelay=captureWindow()
Delay(refreshingDelay)
ForEver
EndProcedure
Define port=Random(7000, 6000)
Define thread=CreateThread(@WebServer(), port)
Define file$=GetCurrentDirectory() + "test.html"
CreateFile(#file, file$)
WriteStringN(#file, "<!DOCTYPE html> " + #LF$ +
"<html lang='en' class='uk-height-1-1 uk-notouch'> " + #LF$ +
"<head> " + #LF$ +
"<meta http-equiv='X-UA-Compatible' content='IE=edge'> " + #LF$ + ;forces to use most recent IE version (workaround For Windows)
"<meta name='viewport' content='width=device-width, initial-scale=1'> " + #LF$ +
"<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/css/uikit.min.css' /> " + #LF$ +
"<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/css/uikit.gradient.min.css' />" + #LF$ +
"<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script> " + #LF$ +
"<script src='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/js/uikit.min.js'></script> " + #LF$ +
"<script> " + #LF$ +
"var PostToWebServer = function(e) { " + #LF$ +
" if (e.type == 'contextmenu' || e.target.id=='#toolbar') e.preventDefault(); " + #LF$ + ;prevent To use default context menu
" if (e.target.id) event.stopPropagation(); " + #LF$ + ;prevent To receive same event from parent nodes
" $.ajax({ " + #LF$ +
" type: 'POST', " + #LF$ +
" url: 'http://localhost:" + port + "', " + #LF$ +
" data: { " + #LF$ +
" 'eventType':e.type " + #LF$ +
" ,'eventWhich':e.which " + #LF$ +
" ,'eventGadget':e.target.id " + #LF$ +
" ,'nodeName':e.target.nodeName " + #LF$ +
" ,'nodeWidth':e.target.clientWidth " + #LF$ +
" ,'nodeHeight':e.target.clientHeight " + #LF$ +
" ,'mouseHitX':e.offsetX " + #LF$ +
" ,'mouseHitY':e.offsetY " + #LF$ +
" }, " + #LF$ +
" dataType: 'json', " + #LF$ +
" async:true " + #LF$ +
" }) " + #LF$ +
" .done(function(data) " + #LF$ +
" { " + #LF$ +
" /**alert(data); /**/ " + #LF$ +
" }) " + #LF$ +
" }; " + #LF$ +
"$(document).on({ " + #LF$ +
" 'mousedown mouseup click dblclick contextmenu' : PostToWebServer " + #LF$ +
"}); " + #LF$ +
"$(document).on({ 'focus blur change' : PostToWebServer },'input'); " + #LF$ +
"</script> " + #LF$ +
"</head> " + #LF$ +
"<body class='uk-flex uk-flex-column uk-height-1-1'> " + #LF$ +
" <div class='uk-flex' style='height:10px;cursor:n-resize'> " + #LF$ +
" <div id='#border1' class='uk-block-secondary' style='width:10px;cursor:se-resize'></div> " + #LF$ +
" <div id='#border2' class='uk-block-primary uk-flex-item-1'></div> " + #LF$ +
" <div id='#border3' class='uk-block-secondary' style='width:10px;cursor:sw-resize'></div> " + #LF$ +
" </div> " + #LF$ +
" <div class='uk-flex uk-flex-item-1' > " + #LF$ +
" <div id='#border4' class='uk-block-primary' style='width:10px;cursor:w-resize'></div> " + #LF$ +
" <div id='content' class='uk-flex-item-1'> " + #LF$ +
" <nav id='#toolbar' class='uk-navbar uk-navbar-attached'> " + #LF$ +
" <ul class='uk-navbar-nav'><li class='uk-active'><a href='#'>File</a></li></ul> " + #LF$ +
" <div class='uk-navbar-content uk-navbar-flip'> " + #LF$ +
" <a id='#minimize' href='#' class='uk-icon-small uk-icon-minus-circle' style='color:gray'></a> " + #LF$ +
" <a id='#maxmimize' href='#' class='uk-icon-small uk-icon-chevron-circle-up' style='color:gray'></a>" + #LF$ +
" <a id='#close' href='#' class='uk-icon-small uk-icon-times-circle' style='color:gray'></a> " + #LF$ +
" </div> " + #LF$ +
" </nav> " + #LF$ +
" <div class='uk-panel uk-panel-box uk-panel-box-secondary uk-margin-left uk-margin-right uk-margin-top'> " + #LF$ +
" <form class='uk-form'> " + #LF$ +
" <fieldset> " + #LF$ +
" <legend>LOGIN</legend> " + #LF$ +
" <div class='uk-form-row'><input type='text' placeholder='Username'></div> " + #LF$ +
" <div class='uk-form-row'><input type='password' placeholder='Password'></div> " + #LF$ +
" <div class='uk-form-row'> " + #LF$ +
" <button id='#connect' class='uk-button uk-button-large uk-button-primary uk-animation-hover " + #LF$ +
" uk-animation-scale uk-animation-reverse'><i class='uk-icon-refresh uk-icon-spin'></i> Connect</button> " + #LF$ +
" </div> " + #LF$ +
" </fieldset> " + #LF$ +
" </form> " + #LF$ +
" </div> " + #LF$ +
" </div> " + #LF$ +
" <div id='#border5' class='uk-block-primary' style='width:10px;cursor:w-resize'></div> " + #LF$ +
" </div> " + #LF$ +
" <div class='uk-flex' style='height:10px;cursor:n-resize'> " + #LF$ +
" <div id='#border6' class='uk-block-secondary' style='width:10px;cursor:sw-resize'></div> " + #LF$ +
" <div id='#border7' class='uk-block-primary uk-flex-item-1'></div> " + #LF$ +
" <div id='#border8' class='uk-block-secondary' style='width:10px;cursor:se-resize'></div> " + #LF$ +
" </div> " + #LF$ +
"</body> " + #LF$+
"</html>")
CloseFile(#file)
Define xml$="<window id='#win' name='win' text='WEB APP' minwidth='600' minheight='400' width='600' height='400' margin='0' flags='#PB_Window_ScreenCentered | #PB_Window_BorderLess'>" +
" <web id='#web'></web>" +
"</window>"
If CatchXML(#xml, @xml$, StringByteLength(xml$)) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "win")
SmartWindowRefresh(#win, #True)
SetGadgetText(#web, "file:///" + file$)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Debug "quit"
Break
Case #PB_Event_SizeWindow
Case #PB_Event_MoveWindow
Case #PB_Event_DeactivateWindow
Debug "de-activate"
Case #PB_Event_Gadget
Case #PB_Event_WebGadget
Select EventType()
Case #PB_EventType_LostFocus
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=LostFocus"
Case #PB_EventType_Focus
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Focus"
Case #PB_EventType_Change
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Change"
Case #PB_EventType_LeftButtonDown
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-MouseDown"
Case #PB_EventType_LeftButtonUp
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-MouseUp"
Case #PB_EventType_RightButtonDown
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-MouseDown"
Case #PB_EventType_RightButtonUp
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-MouseUp"
Case #PB_EventType_MiddleButtonDown
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Middle-MouseDown"
Case #PB_EventType_MiddleButtonUp
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Middle-MouseDown"
Case #PB_EventType_RightClick
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-Click"
Case #PB_EventType_RightDoubleClick
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-DblClick"
Case #PB_EventType_LeftClick
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-Click"
Select EventGadget()
Case #close : Break ;close window
Case #maxmimize : SetWindowState(#win, #PB_Window_Maximize)
Case #minimize : SetWindowState(#win, #PB_Window_Minimize)
EndSelect
Case #PB_EventType_LeftDoubleClick
Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-DblClick"
EndSelect
EndSelect
ForEver
EndIf