Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Using HTML+CSS for GUI (WebKit)

This thread is locked; no one can reply to it. rss feed Print
Using HTML+CSS for GUI (WebKit)
Billybob
Member #3,136
January 2003

After reading the Wolfire Blog, I was inspired to incorporate WebKit into my Elite-like 3D game, for use as a UI renderer. WebKit is the HTML rendering engine behind Safari and Google Chrome, and is touted as being fast and bleeding edge. Wolfire displayed beautiful results of its usage as a UI platform in their game Overgrowth.

So, I downloaded Awesomium (WebKit wrapper) and AwesomiumDotNet, and had Allegro.cc rendering in my XNA game in no time:

{"name":"601991","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/1\/11e672c43eedd923beb02d494760e269.png","w":1040,"h":806,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/1\/11e672c43eedd923beb02d494760e269"}601991

It was really easy to use. Literally took minutes to get going once I found what I needed. It still won't load a local HTML file, but I'll work on that.

Why did I do this? WebKit Primer Part 2: CSS transitions. That's why. I doubt I have the graphical skill to make my UI look half as good as that, but it's worth a try.

The library is C++ based, and spits out raw BGRA32 data, so it should be a breeze to get going in an Allegro game.

EDIT: Fixed loading local files. Had to append an extra backslash:

string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
myWebCore.BaseDirectory = path + "\\";

EDIT: And thanks to my lovely DevConsole powered by IronPython, I'm able to fiddle with the HTML in-game. I'll likely replace it with the WebKit console or something, but still awesome 8-)

EDIT: I've attached all the keyboard and mouse events to WebKit. Took a little work, because I wanted to grab them right from the Window's events, instead of XNA, so I had to go find a hack. But, everything seems to be working just fine. In fact, I'm writing this update from within my game 8-) Only problem is the cursor doesn't change. Hmmm ....

GullRaDriel
Member #3,861
September 2003
avatar

Interesting kit, indeed !

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Mokkan
Member #4,355
February 2004
avatar

I certainly find this to be an interesting use for WebKit. Are you planning on using it for the entire GUI, or just parts?

relpatseht
Member #5,034
September 2004
avatar

This is very interesting. I'm definitely going to check this out for my game next year. It seems a wonderful alternative to cleaning up my four year old GUI library.

How is the speed? Any particular quirks you've noticed about setup or rendering?

Billybob
Member #3,136
January 2003

Mokkan said:

Are you planning on using it for the entire GUI, or just parts?

Hopefully the entire GUI. I am concerned that it won't be able to handle 3D labels, though. For example in my game I'd like to have planets within the view labeled by projecting their 3D coordinates to 2D screen coordinates. I don't know if WebKit can update fast enough for that.

Any particular quirks you've noticed about setup or rendering?

My biggest issue right now is it doesn't seem to provide any way to return results to JavaScript in a callback. When JavaScript calls into my engine, Awesomium raises an event. My engine can pull in all the function arguments and such, but there's no way to return a value! :-/ I can't find Awesomium's source code, so I'm poking around to see how difficult it would be to hook up to WebKit directly ...

EDIT:
Looks like the reason you can't return results is because the callbacks are queued up as events. From JavaScript's perspective they are asynchronous. I guess that solves any threading issues, but it also means callbacks can't return values. Bah-hum-bug. The only seems to be to not use such a design pattern, and instead have the engine update properties appropriately.

relpatseht
Member #5,034
September 2004
avatar

I've been digging into this since I last posted. Awesomium went closed source just before the release of 1.5, which is why you can't find it. The source from when it was still lgpl is at git://github.com/pathorn/awesomium.git.

Just after it went closed source. Sirikata started their own version (they had been using Awesomium up until then) called Berkelium. It is still in beta and I have ruled it out because it is a strictly multiprocess design (As in, creating a window in game would literally start up a chromium browser as a sub process. IPC, from what I've seen of it, is too slow/bulky). Berkelium also has no way of getting javascript values.

Anyway, the closed source version of Awesomium doesn't support Linux (yet). Its creator said he'd have Linux support in around July, but that has clearly passed. People have been asking but no word, so my faith is shaky (and my game engine starts getting officially built next month (by which I mean should be mostly feature complete by), so no use waiting).

As a result of all this, I grabbed the most recent version of Awesomium source (from around December of 09. It is not and will not be maintained, according to the Awesomium author) and have been working with that. Looking at the V8 source in Chromium, it seems the V8 engine SHOULD be very easy to bind to C++. The Awesomium source I have already supports getting some values out of JavaScript (just not objects, like the most recent version does.).

So, anyway, I'll be working on getting much better binding into the library and bringing it up to speed (I figure there is no reason to have Lua in an engine if I'm going to be including JavaScript as a dependency anyway).

Let me know of anything else you find code wise. I'm probably going to try hooking directly into V8 and thus subvert the queue where I can, but all information is still helpful when working with REALLY BIG codebases I've never seen before.

Billybob
Member #3,136
January 2003

Awesomium went closed source just before the release of 1.5, which is why you can't find it. The source from when it was still lgpl is at git://github.com/pathorn/awesomium.git.

That explains it! I had indeed found the repo, but wasn't sure why it was the only one to be found.

The relevant piece of code I found was in ClientObject.cpp:

void NamedCallback::handleCallback(const CppArgumentList& args, CppVariant* result)
{
  Awesomium::JSArguments jsArgs;
  initFromCppArgumentList(args, jsArgs);

  Awesomium::WebCore::Get().queueEvent(new WebViewEvents::InvokeCallback(view, name, jsArgs));
  result->SetNull();
}

WebKit's JS engine calls that when JavaScript code tries to call one of the registered callbacks. i.e. x = Client.GetSomethingImportant();. As you can see, it does not immediately call the Listener's onCallback. Instead, it queues an event. So, from the perspective of JavaScript, the callback returns immediately and doesn't actually execute. :'(

The solution is simple. Rewrite the above function to immediately call the desired engine function, and place the return value into result. The danger is, though, that your engine function will likely be called from a different thread, so now you have to handle multi-threaded locking and such.

I'm a bit torn. Part of me wants to work on this, because I think it would be useful to me in the long-term, and perhaps useful for Allegro 5 UI's. On the other hand, this is a lot of work, and completely halts game-play related work in my game. Hmmm ...

EDIT: Looks like the Awesomium code from that repo is LPGL'd, so we are free to modify it. Might be worth trying to update it a bit to work like the closed-source version, and to support synchronous callbacks.

relpatseht
Member #5,034
September 2004
avatar

From my perspective, making GUI libraries is incredibly boring and horribly unsatisfying (there is never time to get all the features you may need) and, in general, GUI's sort of get pushed off to the side. Making a pre-existing HTML engine work in game, on the other hand, is fun, challenging, feature complete (particularly with those css3 gems), and opens up the possibility of JavaScript in game (which is nice if only because it has a debugger, profiler, can be tested externally, and has a very wide user base).

Not to mention I've got nothing to do but Engine work until school starts and whatever ideas the rest of the team have been cooking up need to be fleshed out.

Although, anything that is a lot of work is extremely risky to a development cycle. Far too many projects have fallen off the back burner while some big new feature was being worked on. Just my $0.2

Anyway, looking a bit more through the Chromium repo and the Awesomium source, it seems the ability is not only already there to bind a class to JavaScript, it's documented with examples!

http://src.chromium.org/viewvc/chrome/trunk/src/webkit/glue/cpp_binding_example.h?view=markup

The entire glue parent directory is mostly the focus of interest. This may not be as overbearing as originally foreseen.

Billybob
Member #3,136
January 2003

opens up the possibility of JavaScript in game (which is nice if only because it has a debugger, profiler, can be tested externally, and has a very wide user base).

That's basically why I wanted to use WebKit as my UI. CodeMirror is a great example. It's an in-browser code editor. A game GUI based on WebKit can literally drop CodeMirror right in and have an in-game code editor. A few more hours of work and you could easily have live scripting updates for your engine. 8-)

You should also be able to use the many DOM inspectors out there to do live inspection on the UI, and live updates there as well. Plus, as you mentioned, you can just test all the UI in a regular browser (minus engine-specific calls).

Quote:

Although, anything that is a lot of work is extremely risky to a development cycle.

To really take advantage of WebKit as a UI, you will need a windowing system built around the WebViews. That's probably the hardest part, in my opinion. Besides the JavaScript issues outlined in the previous posts, the need to design a Windowing system is the other complication keeping me away from using WebKit immediately.

Meh, I'll probably get back to it once I've made more gameplay progress.

EDIT: Here's CodeMirror running in-game:
{"name":"602031","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/3\/938cd1e920071258878a7af5e474b488.png","w":1040,"h":806,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/3\/938cd1e920071258878a7af5e474b488"}602031
Pretty neat stuff. Slap a file browser on it, and a button to do a "live-update" and I've got myself a handy development platform inside the game. 8-)

relpatseht
Member #5,034
September 2004
avatar

Pretty cool stuff, for sure. I've been working at it, but so far the whole day has gone toward just getting a working chromium build. (I had one, but I want a beta so it's a bit more stable). I keep running out of diskspace during checkout and build, or swapspace during linking. A bunch of minor problems, but when each little step takes hours, the day just disappears.

Everything should be worked out though so I should have a nice build ready tomorrow morning.

Personally, I was looking for using WebKit more for only UI related things. I'm not sure WebViews would be an entirely useful feature from my standpoint.

Billybob
Member #3,136
January 2003

Personally, I was looking for using WebKit more for only UI related things. I'm not sure WebViews would be an entirely useful feature from my standpoint.

From the perspective of Awesomium, you create two things, a WebCore object, and a WebView. The WebCore is just a manager of sorts. A WebView object is the actual rendering entity. It's kind of like a tab in Chrome. So if you want to use WebKit at all, you create at least one WebView. For very simple UIs you could just create a single WebView that fills the entire screen. In that case, your UI would be a single HTML file that gets loaded into that WebView. I want to be able to separate things into windows that can be moved around, so I will personally manage multiple WebViews (one per window).

I imagine you could actually build a window manager in HTML+JavaScript, with each window being an iframe. In that case, a single WebView would suffice.

bamccaig
Member #7,536
July 2006
avatar

Using HTML+CSS for a GUI sounds like a really good idea. In practice, I think that both could be replaced with equivalents better designed with GUIs in mind (XML+some styling language uninfluenced by HTML). In fact, I think it's the basis behind Mozilla's XUL technology[1].

I think with my background in Web technologies it would be a lot easier for me to write a GUI using that than it would using something like Win32, GTK+, or QT (albeit, macros aside, I was quite pleased with QT when I was experimenting with it).

Show us teh codez that accomplish what you've done already!

Billybob said:

I imagine you could actually build a window manager in HTML+JavaScript, with each window being an iframe.

You'd only need an iframe if you wanted each window to be a static .html file. You can instead just use a floating div and dynamically fill its contents. Assuming jQuery UI works with what you're doing, you can even get really pretty dialogs with almost no effort.

For example:

#SelectExpand
1<?xml version="1.0" encoding="utf-8"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <title>Dialog Example</title> 7 <link href="theme/jquery-ui-1.8.custom.css" rel="stylesheet" type="text/css" /> 8 <style type="text/css"> 9 .class { display: none; } 10 </style> 11 </head> 12 <body> 13 <div> 14 <button id="createLoginButton">Create Login</button> 15 </div> 16 <div class="class loginDialog" title="Login"> 17 <div> 18 <label class="usernameLabel">Username:</label> 19 <input type="text" class="usernameTextbox" /> 20 </div> 21 <div> 22 <label class="passwordLabel">Password:</label> 23 <input type="password" class="passwordTextbox" /> 24 </div> 25 <div> 26 <button class="loginButton">Login</button> 27 </div> 28 </div> 29 <div class="class alertDialog" title="Alert"> 30 <p class="messageParagraph"></p> 31 <button class="okButton">OK</button> 32 </div> 33 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 34 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script> 35 <script type="text/javascript"><!-- 36 jQuery.noConflict(); 37 38 jQuery(function() { 39 jQuery("#createLoginButton").click(function() { 40 createLoginDialog(getNextId()); 41 }); 42 }); 43 44 function newDialog(className) 45 { 46 var dialog = jQuery(".class." + className).clone(); 47 48 if(dialog.length != 1) 49 throw new Error("Couldn't find dialog class."); 50 51 dialog.attr("class", dialog.attr("class").replace( 52 /(^class| class)/, "")); 53 54 return dialog; 55 } 56 57 function createAlertDialog(msg) 58 { 59 var alert = newDialog("alertDialog"); 60 61 alert.dialog(); 62 63 alert.find(".messageParagraph").text(msg); 64 65 alert.find(".okButton").click(function() { 66 var e = jQuery(this); 67 68 e.parents(".alertDialog").dialog("destroy"); 69 }); 70 } 71 72 function createLoginDialog(id) 73 { 74 var login = newDialog("loginDialog"); 75 var labels = [ 76 { "labelClass" : "usernameLabel", "fieldClass" : "usernameTextbox" }, 77 { "labelClass" : "passwordLabel", "fieldClass" : "passwordTextbox" } 78 ]; 79 80 login.attr("id", id); 81 82 for(var i=0; i<labels.length; i++) 83 { 84 login.find("." + labels[i].fieldClass).attr("name", id + labels[i]); 85 login.find("." + labels[i].labelClass).attr("for", id + labels[i]); 86 } 87 88 login.find(".loginButton").click(function() { 89 var e = jQuery(this); 90 var login = e.parents(".loginDialog"); 91 var username = login.find(".usernameTextbox").val(); 92 var password = login.find(".passwordTextbox").val(); 93 94 password = password.replace(/./g, "*"); 95 96 createAlertDialog("dialog=" + login.attr("id") + 97 " username=" + username + 98 " password=" + password); 99 100 e.parents(".loginDialog").dialog("destroy"); 101 }); 102 103 login.dialog(); 104 } 105 106 var getNextId = (function() { 107 var id = 0; 108 109 return function() { return id++; }; 110 }()); 111 112 --></script> 113 </body> 114</html>

Note: for the above to work you will need to generate a jQuery UI theme (there are many to choose from and there's a UI to customize). Or just follow the link above to see it live on my site. :)

Billybob
Member #3,136
January 2003

bamccaig said:

Show us teh codez that accomplish what you've done already!

I'm working in C#, but the interface to Awesomium is the same. It looks like a lot of code below, but that's only because it contains a really basic window manager:

#SelectExpand
1namespace Midnight.Entities 2{ 3 public class WebKitManager : Entity 4 { 5 public static WebCore WebCore; 6 public static List<WebKitWindow> Windows = new List<WebKitWindow>(); 7 8 public WebKitManager() 9 : base(0, 2) 10 { 11 if (WebCore == null) 12 { 13 WebCoreOptions options = new WebCoreOptions(); 14 options.LogLevel = LogLevel.Verbose; 15 options.PixelFormat = PixelFormat.Bgra; 16 17 WebCore = new WebCore(options); 18 19 string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName); 20 WebCore.BaseDirectory = path + "\\Content\\UI\\"; 21 22 InputSystem.MouseMove += new MouseEventHandler(InputSystem_MouseMove); 23 InputSystem.MouseDown += new MouseEventHandler(InputSystem_MouseDown); 24 InputSystem.MouseUp += new MouseEventHandler(InputSystem_MouseUp); 25 InputSystem.MouseWheel += new MouseEventHandler(InputSystem_MouseWheel); 26 } 27 } 28 29 void InputSystem_MouseWheel(object sender, MouseEventArgs e) 30 { 31 WebKitWindow wnd = WindowUnderPoint(e.Location); 32 33 if (wnd != null && wnd.Focused) 34 { 35 wnd.WebView.InjectMouseWheel(e.Delta); 36 } 37 } 38 39 void InputSystem_MouseDown(object sender, MouseEventArgs e) 40 { 41 WebKitWindow wnd = WindowUnderPoint(e.Location); 42 AwesomiumDotNet.MouseButton btn; 43 44 if(e.Button == Midnight.AdvancedInputSystem.MouseButton.Left) 45 btn = AwesomiumDotNet.MouseButton.Left; 46 else if(e.Button == Midnight.AdvancedInputSystem.MouseButton.Middle) 47 btn = AwesomiumDotNet.MouseButton.Middle; 48 else if(e.Button == Midnight.AdvancedInputSystem.MouseButton.Right) 49 btn = AwesomiumDotNet.MouseButton.Right; 50 else 51 return; 52 53 if (wnd == null) 54 { 55 DefocusAll(); 56 return; 57 } 58 else if (!wnd.Focused) 59 wnd.Focused = true; 60 61 wnd.WebView.InjectMouseDown(btn); 62 } 63 64 void InputSystem_MouseUp(object sender, MouseEventArgs e) 65 { 66 WebKitWindow wnd = WindowUnderPoint(e.Location); 67 AwesomiumDotNet.MouseButton btn; 68 69 if (e.Button == Midnight.AdvancedInputSystem.MouseButton.Left) 70 btn = AwesomiumDotNet.MouseButton.Left; 71 else if (e.Button == Midnight.AdvancedInputSystem.MouseButton.Middle) 72 btn = AwesomiumDotNet.MouseButton.Middle; 73 else if (e.Button == Midnight.AdvancedInputSystem.MouseButton.Right) 74 btn = AwesomiumDotNet.MouseButton.Right; 75 else 76 return; 77 78 if (wnd != null && wnd.Focused) 79 { 80 wnd.WebView.InjectMouseUp(btn); 81 } 82 } 83 84 public static WebKitWindow WindowUnderPoint(Point point) 85 { 86 foreach (WebKitWindow wnd in Windows) 87 { 88 if (point.X >= wnd.X && point.X < (wnd.X + wnd.Width) && point.Y >= wnd.Y && point.Y < (wnd.Y + wnd.Height)) 89 return wnd; 90 } 91 92 return null; 93 } 94 95 void InputSystem_MouseMove(object sender, MouseEventArgs e) 96 { 97 foreach (WebKitWindow wnd in Windows) 98 wnd.WebView.InjectMouseMove(e.X - wnd.X, e.Y - wnd.Y); 99 } 100 101 public override void Update(GameTime gameTime) 102 { 103 WebCore.Update(); 104 105 base.Update(gameTime); 106 } 107 108 public override void Draw(GameTime gameTime) 109 { 110 Windows.RemoveAll(delegate(WebKitWindow wnd) { return wnd.Closed; }); 111 112 foreach (WebKitWindow wnd in Windows) 113 wnd.Draw(); 114 115 base.Draw(gameTime); 116 } 117 118 public static void HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) 119 { 120 switch (msg) 121 { 122 case InputSystem.WM_KEYDOWN: 123 case InputSystem.WM_KEYUP: 124 case InputSystem.WM_SYSKEYDOWN: 125 case InputSystem.WM_SYSKEYUP: 126 case InputSystem.WM_CHAR: 127 //case InputSystem.WM_IMECHAR: 128 case InputSystem.WM_SYSCHAR: 129 { 130 foreach(WebKitWindow wnd in Windows) 131 { 132 if(wnd.Focused) 133 wnd.WebView.InjectKeyboardEvent(new WebKeyboardEvent(msg, (uint)(wParam.ToInt32()), (int)(lParam.ToInt32()))); 134 } 135 break; 136 } 137 } 138 } 139 140 public static void DefocusAll() 141 { 142 foreach (WebKitWindow wnd in Windows) 143 wnd.Focused = false; 144 } 145 146 public static void OpenUrl(string url) 147 { 148 WebKitWindow wnd = new WebKitWindow(800, 600); 149 Windows.Add(wnd); 150 wnd.WebView.LoadUrl(url); 151 } 152 153 public static void OpenFile(string filepath) 154 { 155 WebKitWindow wnd = new WebKitWindow(800, 600); 156 Windows.Add(wnd); 157 wnd.WebView.LoadFile(filepath); 158 } 159 160 public static void OpenHtml(string html) 161 { 162 WebKitWindow wnd = new WebKitWindow(400, 400); 163 wnd.X = 200; 164 wnd.Y = 200; 165 Windows.Add(wnd); 166 wnd.WebView.LoadHtml(html); 167 } 168 } 169 170 public class WebKitWindow 171 { 172 public WebView WebView; 173 Texture2D Texture; 174 175 bool focused = false; 176 public bool Closed = false; 177 178 public int Width, Height; 179 public int X, Y; 180 public bool Focused 181 { 182 get { return focused; } 183 set 184 { 185 if (value && !focused) 186 { 187 WebKitManager.DefocusAll(); 188 focused = value; 189 WebView.Focus(); 190 } 191 else if (!value && focused) 192 { 193 focused = value; 194 WebView.Unfocus(); 195 } 196 } 197 } 198 199 public WebKitWindow(int width, int height) 200 { 201 this.Width = width; 202 this.Height = height; 203 204 WebView = WebKitManager.WebCore.CreateWebView(width, height, true); 205 Texture = new Texture2D(Entity.GraphicsDevice, width, height, 1, TextureUsage.None, SurfaceFormat.Color); 206 207 WebView.Unfocus(); 208 209 WebView.CreateObject("WebKitManager"); 210 WebView.SetObjectCallback("WebKitManager", "OpenHtml"); 211 WebView.CreateObject("Window"); 212 WebView.SetObjectCallback("Window", "SetPosition"); 213 WebView.Callback += new EventHandler<CallbackEventArgs>(WebView_Callback); 214 } 215 216 void WebView_Callback(object sender, CallbackEventArgs e) 217 { 218 if (e.ObjectName == "WebKitManager" && e.CallbackName == "OpenHtml" && e.Args.Count > 0) 219 { 220 if (e.Args[0].IsString()) 221 WebKitManager.OpenHtml(e.Args[0].ToString()); 222 } 223 else if (e.ObjectName == "Window" && e.CallbackName == "SetPosition" && e.Args.Count > 1) 224 { 225 if (e.Args[0].IsInteger() && e.Args[1].IsInteger()) 226 { 227 X = e.Args[0].ToInteger(); 228 Y = e.Args[1].ToInteger(); 229 } 230 } 231 } 232 233 public void Close() 234 { 235 WebView.Dispose(); 236 Closed = true; 237 } 238 239 public void Draw() 240 { 241 if (WebView.IsDirty()) 242 { 243 byte[] buffer = new byte[Width * Height * 4]; 244 245 WebView.Render(buffer, Width * 4, 4); 246 Texture.SetData(buffer); 247 } 248 249 Game1.game.spriteBatch.Begin(SpriteBlendMode.AlphaBlend); 250 Game1.game.spriteBatch.Draw(Texture, new Rectangle(X, Y, Width, Height), Focused ? Color.White : Color.Gray); 251 Game1.game.spriteBatch.End(); 252 } 253 } 254}

The main thing is creating the WebCore, WebViews, passing them keyboard and mouse events, and updating the WebView textures when necessary.

Quote:

In practice, I think that both could be replaced with equivalents better designed with GUIs in mind

That would certainly make writing GUIs easier, but the great thing about using WebKit is it allows you to drop in existing libraries and software like jQuery. Plus, WebKit is probably more optimized than anything I could ever write. Personally, I'd write something to translate from something like XUL into HTML+CSS. That way you get the best of both worlds.

EDIT:
Here's your UI running in my game, bamccaig. ;D

{"name":"602057","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/1\/21a3dd38df2b7de223ba539212f78b0a.png","w":1040,"h":806,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/1\/21a3dd38df2b7de223ba539212f78b0a"}602057
{"name":"602056","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/a\/ea4f468780aa03dd4d2f59e62d5e1217.png","w":1040,"h":806,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/a\/ea4f468780aa03dd4d2f59e62d5e1217"}602056

bamccaig
Member #7,536
July 2006
avatar

I primarily write C# and JavaScript so I just wanted to knitpick on your code a little bit. :-X

Billybob said:

WebCoreOptions options = new WebCoreOptions();
options.LogLevel = LogLevel.Verbose;
options.PixelFormat = PixelFormat.Bgra;

WebCore = new WebCore(options);

this.WebCore = new WebCore(new WebCoreOptions
{
    LogLevel = LogLevel.Verbose,
    PixelFormat = PixelFormat.Bgra
});

Billybob said:

WebCore.BaseDirectory = path + "\\Content\\UI\\";

this.WebCore.BaseDirectory = path + @"\Content\UI\";

Billybob said:

WebKitWindow wnd = WindowUnderPoint(e.Location);

var wnd = WindowUnderPoint(e.Location);

Billybob said:

Windows.RemoveAll(delegate(WebKitWindow wnd) { return wnd.Closed; });

this.Windows.RemoveAll(wnd => wnd.Closed);

Or maybe...

this.Windows.RemoveAll((WebKitWindow wnd) => wnd.Closed);

Billybob said:

WebKitWindow wnd = new WebKitWindow(800, 600);

var wnd = new WebKitWindow(800, 600);

No guarantee that all of that applies.

Billybob said:

Here's your UI running in my game, bamccaig. ;D

Cool. ;D ...Wait, how do you know my password?! >:(

Billybob
Member #3,136
January 2003

bamccaig said:

I primarily write C# and JavaScript so I just wanted to knitpick on your code a little bit.

Those were some helpful comments :) I know all of the syntax, but I guess I forget to use it most of the time :P I especially like being able to set member variables with the new operator. That is a darned handy feature for keeping compact code.

Quote:

Wait, how do you know my password?!

That's a feature of WebKit :P

Go to: