I tried to use both HaxeUI and HaxeFlixel, but what I obtain is HaxeUI's interface over a white background, covering everything underneath. Moreover, even if it was possible to somewhat make HaxeUI and HaxeFlixel work together, it's not clear how to change the UI of HaxeUI when the state change in HaxeFlixel. Here is the code I used:
private function setupGame():Void {
Toolkit.theme = new GradientTheme();
Toolkit.init();
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
if (zoom == -1) {
var ratioX:Float = stageWidth / gameWidth;
var ratioY:Float = stageHeight / gameHeight;
zoom = Math.min(ratioX, ratioY);
gameWidth = Math.ceil(stageWidth / zoom);
gameHeight = Math.ceil(stageHeight / zoom);
}
trace('stage: ${stageWidth}x${stageHeight}, game: ${gameWidth}x${gameHeight}, zoom=$zoom');
addChild(new FlxGame(gameWidth, gameHeight, initialState, zoom, framerate, framerate, skipSplash, startFullscreen));
Toolkit.openFullscreen(function(root:Root) {
var view:IDisplayObject = Toolkit.processXmlResource("assets/xml/haxeui-resource.xml");
root.addChild(view);
});
}
I can guess that, probably, both HaxeUI and HaxeFlixel have their own main loop and that their event handling might not be compatible, but just in case, can someone have a more definitive answer?
Edit:
Actually, it's much better when using openPopup:
Toolkit.openPopup( { x:20, y:150, width:100, height:100 }, function(root:Root) {
var view:IDisplayObject = Toolkit.processXmlResource("assets/xml/haxeui-naming.xml");
root.addChild(view);
});
It's possible to interact with the rest of the screen (managed with HaxeFlixel), but the mouse pointer present in the part of the screen managed with HaxeFlixel remains under the HaxeUI user interface elements.
When using Flixel and HaxeUI together, its almost like running two applications at once. However, they both rely on OpenFL as a back-end and each attach themselves to its display tree.
One technique I'm experimenting with right now is to open a Flixel sub state, and within the sub state, call Toolkit.openFullscreen(). From inside of this, you can set the alpha of the root's background to 0, which allows you to see through it onto the underlying bitmap that Flixel uses to render.
Here is a minimal example of how you might "embed" an editor interface inside a Flixel sub state:
import haxe.ui.toolkit.core.Toolkit;
import haxe.ui.toolkit.core.RootManager;
import haxe.ui.toolkit.themes.DefaultTheme;
import flixel.FlxG;
import flixel.FlxSubState;
// This would typically be a Haxe UI XMLController
import app.MainEditor;
class HaxeUIState extends FlxSubState
{
override public function create()
{
super.create();
// Flixel uses a sprite-based cursor by default,
// so you need to enable the system cursor to be
// able to see what you're clicking.
FlxG.mouse.useSystemCursor = true;
Toolkit.theme = new DefaultTheme();
Toolkit.init();
Toolkit.openFullscreen(function (root) {
var editor = new MainEditor();
// Allows you to see what's going on in the sub state
root.style.backgroundAlpha = 0;
root.addChild(editor.view);
});
}
override public function destroy()
{
super.destroy();
// Switch back to Flixel's cursor
FlxG.mouse.useSystemCursor = true;
// Not sure if this is the "correct" way to close the UI,
// but it works for my purposes. Alternatively you could
// try opening the editor in advance, but hiding it
// until the sub-state opens.
RootManager.instance.destroyAllRoots();
}
// As far as I can tell, the update function continues to get
// called even while Haxe UI is open.
override public function update() {
super.update();
if (FlxG.keys.justPressed.ESCAPE) {
// This will implicitly trigger destroy().
close();
}
}
}
In this way, you can associate different Flixel states with different Haxe UI controllers. (NOTE: They don't strictly have to be sub-states, that's just what worked best in my case.)
When you open a fullscreen or popup with haxeui, the program flow will be blocked (your update() and draw() function won't be called). You should probably have a look at flixel-ui instead.
From my experience haxeflixel and haxeui work well together but they are totally independent projects, and as such, any coordination between flixel states and displayed UI must be added by the coder.
I don't recall having the white background problem you mention, it shouldn't happen unless haxeui root sprite has a solid background, in that case it should be addressed to haxeui project maintainer.
Related
Running ARKit 2.0 with an ARSCNView. iOS12
The application uses multithreading, that's why these functions are being performed on the main thread (just to be sure). I also tried without explicitly performing the functions on the main thread too, with no avail.
I'm using an .aiff sound file but have also tried a .wav. No joy.
I even tried removing audioNode_alarm from the node hierarchy & the sound still plays. I even remove the ARSCNView from the view hierarchy and the sound STILL plays. FFS
From what I can see, I'm doing things EXACTLY as I'm supposed to, to stop the audio from playing. The audio simply will not stop no matter what I try. Can anyone think why?!
weak var audioNode_alarm: SCNNode!
weak var audioPlayer_alarm: SCNAudioPlayer?
func setupAudioNode() {
let audioNode_alarm = SCNNode()
addChildNode(audioNode_alarm)
self.audioNode_alarm = audioNode_alarm
}
func playAlarm() {
DispatchQueue.main.async { [unowned self] in
self.audioNode_alarm.removeAllAudioPlayers()
if let audioSource_alarm = SCNAudioSource(fileNamed: "PATH_TO_MY_ALARM_SOUND.aiff") {
audioSource_alarm.loops = true
audioSource_alarm.load()
audioSource_alarm.isPositional = true
let audioPlayer_alarm = SCNAudioPlayer(source: audioSource_alarm)
self.audioNode_alarm.addAudioPlayer(audioPlayer_alarm)
self.audioPlayer_alarm = audioPlayer_alarm
}
}
}
func stopAlarm() {
DispatchQueue.main.async { [unowned self] in
self.audioNode_alarm?.removeAudioPlayer(self.audioPlayer_alarm!)
self.audioNode_alarm?.removeAllAudioPlayers()
}
}
What I ended up doing is stopping the sound and removing the player by
yourNode.audioPlayers.forEach { audioLocalPlayer in
audioLocalPlayer.audioNode?.engine?.stop()
yourNode.removeAudioPlayer(audioLocalPlayer)
}
According to the documentation SCNAudioPlayer has audioNode, which is supposed to be used "to vary parameters such as volume and reverb in real time during playback".
audioNode is of AVAudioNode type, so if we jump to engine prop and its type definition, we'll find all the controls we need.
I googled and found out, that there is an option to draw on a separate thread using qml.
http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html
But it's not what I need. How can I render in a separate thread using common qt widgets without qml?
If your QWidget inherits from QOpenglWidget you can just call
this->makeCurrent();
But I personally prefer a more efficient and robust way to encapsulate OpenGL context by using QWindow and configuring all the OpenGL related settings there:
Here is an example:
bool MyOpenGLWindow::Create()
{
this->requestActivate();
if(!glContext)
{
glContext= new QOpenGLContext(this);
QSurfaceFormat fmt = requestedFormat();
int maj = fmt.majorVersion();
int min = fmt.minorVersion();
glContext->setFormat( requestedFormat());
glContext->create();
if(glContext->isValid() == false)
{
QString str;
str.sprintf("Failed to create GL:%i.%i context",maj,min);
return false;
}
}
glContext->makeCurrent(this);
//after this line you can work with OpenGL
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
//etc...
Now,remember, every time you spawn (or move existing one) an instance of such a class in a thread you must set the context current.
How can I add an event or other method to listen to keypresses on a gnome shell extension? e.g. show a dialog with each key press showing the pressed key?
I can not find any example. The documentation mentions a keyboard module, but with that common name searching is hard.
Class explanation
...
- General utils
- Keyboard: Manage and define the keyboard events, etc. for gnome shell.
(read above as a quote from the docs linked above. it is styled as code because the quote styling for some reason do not preserve line breaks in this site)
I found some extensions using the bellow code for results similar to what i'm asking, but i, again, failed to find docs for the specific classes and methods:
workViewInjections['_init'] = injectToFunction(WorkspacesView.WorkspacesView.prototype, '_init', function(width, height, x, y, workspaces) {
this._pickWorkspace = false;
this._pickWindow = false;
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPress));
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._onKeyRelease));
connectedSignals.push({ obj: global.stage, id: this._keyPressEventId });
connectedSignals.push({ obj: global.stage, id: this._keyReleaseEventId });
});
Also, no class named keyboard anywhere there...
--
edit1: more searching... i think i may have to use the Clutter api. but again, not much examples or documentation for that. farthest i went was this
edit2: more searching. looking on the gnome shell source code, on the main ui tree, i think the answer is to use the barelly mentioned global object that is available to the extension code. e.g.
global.connect('key-press-event', function(if, i, know, the, signature){} );
I came across this snippet in gcampax's gtk-js-app template some time ago, which may be related to what you're doing:
// Due to limitations of gobject-introspection wrt GdkEvent and GdkEventKey,
// this needs to be a signal handler
this.connect('key-press-event', Lang.bind(this, this._handleKeyPress));
and
_handleKeyPress: function(self, event) {
return this.main_search_bar.handle_event(event);
},
I haven't had a need to use keyboard events yet, and this is Gtk in GJS, but the same limitation may be affecting gnome-shell extensions.
UPDATE
I've been doing some keybinding stuff lately, and if attaching a signal handler to the global object is working, you can do something like this:
global.display.connect("key-press-event", (widget, event, user_data) => {
let [success, keyval] = event.get_keyval(); // integer
let keyname = Gdk.keyval_name(keyval); // string keyname
if (keyname === "Control_L") {
// Dialog code or eg. this.keys_array.push("<Ctrl>");
}
});
There's also some Shell keybinding code here and some shell-global documentation here that might give you more clues. Wish I could help more but I'm wrestling my own GJS atm ;)
ADDENDUM
There is a good answer here with an example class with informative logging, as well as a speculative explanation. I've also found this functionality is exposed over DBus which might be more convenient in some cases:
Bus Name: org.gnome.Shell -> Path: /org/gnome/Shell -> Interface: org.gnome.Shell
Relevant Methods:
GrabAccelerator(String accelerator, UInt32 flags) -> (UInt32 action)
UngrabAccelerator(UInt32 action) -> (Boolean success)
Signal:
AcceleratorActivate(UInt32, Dict of {String, Variant})
For me global.stage.connect("key-press-event", _handleKeyPress) did the trick
I have a widget with list of last news, how to cache only widget output?
OutputCache module caches whole page and for anonymous users, but in fact I need to cache only one shape output.
What solution can be here?
It's not a good idea to cache the Shape object itself, but you can capture the HTML output from a Shape and cache that.
Every Orchard Shape has a corresponding object called the Metadata. This object contains, among other things, some event handlers that can run when the Shape is displaying or after it has been displayed. By using these event handlers, it is possible to cache the output of the Shape on the first call to a driver. Then for future calls to the driver, we can display the cached copy of the output instead of running through the expensive parts of the driver or template rendering.
Example:
using System.Web;
using DemoModule.Models;
using Orchard.Caching;
using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement.Shapes;
namespace DemoModule.Drivers {
public class MyWidgetPartDriver : ContentPartDriver<MyWidgetPart> {
private readonly ICacheManager _cacheManager;
private readonly ISignals _signals;
public MyWidgetPartDriver(
ICacheManager cacheManager,
ISignals signals
) {
_cacheManager = cacheManager;
_signals = signals;
}
public class CachedOutput {
public IHtmlString Output { get; set; }
}
protected override DriverResult Display(MyWidgetPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyWidget", () => {
// The cache key. Build it using whatever is needed to differentiate the output.
var cacheKey = /* e.g. */ string.Format("MyWidget-{0}", part.Id);
// Standard Orchard cache manager. Notice we get this object by reference,
// so we can write to its field to save our cached HTML output.
var cachedOutput = _cacheManager.Get(cacheKey, ctx => {
// Use whatever signals are needed to invalidate the cache.
_signals.When(/* e.g. */ "ExpireCache");
return new CachedOutput();
});
dynamic shape;
if (cachedOutput.Output == null) {
// Output has not yet been cached, so we are going to build the shape normally
// and then cache the output.
/*
... Do normal (potentially expensive) things (call DBs, call services, etc.)
to prep shape ...
*/
// Create shape object.
shape = shapeHelper.Parts_MyWidget(/*...*/);
// Hook up an event handler such that after rendering the (potentially expensive)
// shape template, we capture the output to the cached output object.
((ShapeMetadata) shape.Metadata).OnDisplayed(displayed => cachedOutput.Output = displayed.ChildContent);
} else {
// Found cached output, so simply output it instead of building
// the shape normally.
// This is a dummy shape, the name doesn't matter.
shape = shapeHelper.CachedShape();
// Hook up an event handler to fill the output of this shape with the cached output.
((ShapeMetadata)shape.Metadata).OnDisplaying(displaying => displaying.ChildContent = cachedOutput.Output);
// Replacing the ChildContent of the displaying context will cause the display manager
// to simply use that HTML output and skip template rendering.
}
return shape;
});
}
}
}
EDIT:
Note that this only caches the HTML that is generated from your shape output. Things like Script.Require(), Capture(), and other side effects that you perform in your shape templates will not be played back. This actually bit me because I tried to cache a template that required its own stylesheet, but the stylesheets would only be brought in the first time.
Orchard supplies a service called the CacheManager, which is awesome and cool and makes caching super easy. It is mentioned in the docs, but it isn't a particularly helpful description of how to use it (http://docs.orchardproject.net/Documentation/Caching). Best place to see examples would be in the Orchard core code and third party modules such as Favicon and the twitter widgets (all of them one would hope).
Luckily other nice people have gone to the effort of searching orchards code for you and writing nice little blog posts about it. The developer of the LatestTwitter widget wrote a neat post: http://blog.maartenballiauw.be/post/2011/01/21/Writing-an-Orchard-widget-LatestTwitter.aspx . So did Richard of NogginBox: http://www.nogginbox.co.uk/blog/orchard-caching-by-time . And of course Bertrand has a helpful post on the subject as well: http://weblogs.asp.net/bleroy/archive/2011/02/16/caching-items-in-orchard.aspx
I have a requirement to extend the YUI Panel with some custom functionality that will be in a new file and shared across multiple views.
I am at a bit of a loss as to how best to go about this, can anyone give me any pointers please?
Let's say you want to extend a Panel to create one that has a list in its body. I usually use Y.Base.create for this. It's a more declarative way of extending YUI classes than using a constructor and Y.extend. But I'll stay closer to your example in the YUI forums.
There are a couple of tricks dealing with WidgetStdMod (one of the components of Y.Panel), but mostly it's just about using Y.extend and following the YUI inheritance patterns. I'll try to answer with an example:
function MyPanel() {
MyPanel.superclass.constructor.apply(this, arguments);
}
// hack: call it the same so you get the same css class names
// this is good for demos and tests. probably not for real life
MyPanel.NAME = 'panel';
MyPanel.ATTRS = {
listItems: {
// YUI now clones this array, so all's right with the world
value: []
},
bodyContent: {
// we want this so that WidgetStdMod creates the body node
// and we can insert our list inside it
value: ''
}
};
Y.extend(MyPanel, Y.Panel, {
// always a nice idea to keep templates in the prototype
LIST_TEMPLATE: '<ul class="yui3-panel-list"></ul>',
initializer: function (config) {
// you'll probably want to use progressive enhancement here
this._listContainer = Y.Node.create(this.LIST_TEMPLATE);
// initializer is also the place where you'll want to instantiate other
// objects that will live inside the panel
},
renderUI: function () {
// you're inheriting from Panel, so you'll want to keep its rendering logic
// renderUI/bindUI/syncUI don't call the superclass automatically like
// initializer and destructor
MyPanel.superclass.renderUI.call(this);
// Normally we would append stuff to the body in the renderUI method
// Unfortunately, as of 3.5.0 YUI still removes all content from the body
// during renderUI, so we either hack it or do everything in syncUI
// Hacking WidgetStdModNode is doable but I don't have the code around
// and I haven't memorized it
//var body = this.getStdModNode('body');
},
syncUI: function () {
// same here
MyPanel.superclass.syncUI.call(this);
// insert stuff in the body node
var listContainer = this._listContainer.appendTo(this.getStdModNode('body'));
Y.Array.each(this.get('listItems'), function (item) {
listContainer.append('<li>' + item + '</li>');
});
}
});