Could someone explain how do buttons on widget work? - awesome-wm

I'm extremely confused about how to do this. The documentation of Awesome is not clear to me at all, nor following stuff from the rc.lua helps. All I wanna do is to pop up the calendar upon clicking the textclock widget (with LMB), though I don't know how to start with it because the documentation has no examples (or at least I could not find it after spending 1 hour of googling), and the rc.lua has many different lines and arguments in each of them, making me unable to do anything.
My idea was
awful.button({}, 1, function() wibox.widget.calendar.year(os.date('*t')) end)
, but I have no clue how to attach this to the textclock widget. Also, I'm not quite sure if that is going to work anyway (that is, after I manage to attach it to the textclock). I'd wanna avoid adding too many widgets that I can interact with, and keep it simple, with as few as possible.
Thank you in advance, and I hope I didn't make anyone pull their hair out...

AwesomeWM concept of "buttons" can be split into 2 APIs. First of all, there is the button widget, which actually doesn't do much and is just a glorified wibox.widget.imagebox. This is the part not super relevant to your question.
The other part, which is relevant, is the event model. There are 2 ways to get something to happen when you click on a widget. The first one are the signals. Each widget has a button::press, button::release, mouse::enter and mouse::leave signals. You can attach a function to a signal this way:
mytextclock:connect_signal("button::press", function(self, lx, ly, button, mods, metadata)
wibox.widget.calendar.year(os.date('*t'))
end)
That API is more rich than a simple button. You get a lot of geometry and layout information you don't get from awful.button. However, it is overkill for simple buttons, thus awful.button.
Each widget has a :buttons() method in AwesomeWM < v4.4 or a .buttons object property in AwesomeWM >= v4.4. There are several examples in rc.lua of how to add some awful.buttons to these widget. Here are the snippets for the mylayoutbox widget:
For < v4.4:
s.mylayoutbox:buttons(gears.table.join(
awful.button({ }, 1, function () awful.layout.inc( 1) end),
awful.button({ }, 3, function () awful.layout.inc(-1) end),
awful.button({ }, 4, function () awful.layout.inc( 1) end),
awful.button({ }, 5, function () awful.layout.inc(-1) end)))
for >= v4.4:
s.mylayoutbox = awful.widget.layoutbox {
screen = s
}
s.mylayoutbox.buttons = {
awful.button({ }, 1, function () awful.layout.inc( 1) end),
awful.button({ }, 3, function () awful.layout.inc(-1) end),
awful.button({ }, 4, function () awful.layout.inc(-1) end),
awful.button({ }, 5, function () awful.layout.inc( 1) end),
}
-- That works too.
s.mylayoutbox:add_button(awful.button({ }, 1, function () awful.layout.inc( 1) end))
As for the lack of examples in the documentation. That's a fair point. I will add some.

Related

a-frame Trigger event using aframe-alongpath-component

In a-frame using aframe-alongpath-component i would like to count each loop of an animation.
I think event movingended is not triggered with a loop?!
How can i use alongpath-trigger-activated when element is reaching a-curve-point X (maybe endpoint)?
My assumption was wrong. With every loop movingended is triggered.
let ball = document.createElement('a-sphere');
ball.setAttribute('id', `Ball_${a}`);
ball.setAttribute('class', 'clickable');
ball.setAttribute('src', `#tBall_${a}`);
ball.setAttribute(`alongpath`, `curve: .track${a}; dur: ${pathDuration}; delay: ${startdelay}; loop: true ;`);
ball.addEventListener("movingended", (e) => {
console.log("moving ended:" + bad_hits);
bad_hits++;
});
So i don't need alongpath-trigger-activated. But to answer my question:
let track = document.createElement('a-curve');
track.setAttribute('class', `track${a}`);
scene.append(track);
...
let point5 = document.createElement('a-curve-point');
point5.setAttribute('position', '0 3 -5');
point5.setAttribute('class', 'trigger');
point5.addEventListener("alongpath-trigger-activated", () => {
console.log("point 5 alongpath-trigger-activated");
});
track.append(point5);

Change awesomewm theme programmatically

I have several wallpapers and a theme/colour palette for each one, I'm trying to find a way to assign a keyboard shortcut to change the theme from one to another.
I have no problems setting each individual theme, but cannot for the life of me figure out a way to set the theme once awesomewm has started running without killing the current instance and then making a new one.
I think once the theme has been assigned and awesomewm has been instansiated the values are fixed, if that's the case I don't think it will be possible to do.
I think one of possible ways is recreate all you widgets after theme changes. Not sure for whole code, but here is quick example how to rebuild panel by hotkey for awesome v4.0.
Some modifications for screen building functions first
local function build_panel(s)
-- destroy old panel
if s.mywibox then s.mywibox:remove() end
-- create a promptbox for given screen
s.mypromptbox = awful.widget.prompt()
-- create a layoutbox for given screen
s.mylayoutbox = awful.widget.layoutbox(s)
s.mylayoutbox:buttons(awful.util.table.join(
awful.button({ }, 1, function () awful.layout.inc( 1) end),
awful.button({ }, 3, function () awful.layout.inc(-1) end),
awful.button({ }, 4, function () awful.layout.inc( 1) end),
awful.button({ }, 5, function () awful.layout.inc(-1) end))
)
-- create a taglist widget
s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
-- create a tasklist widget
s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
-- create panel wibox
s.mywibox = awful.wibar({ position = "top", screen = s })
-- add widgets to the panel wibox
s.mywibox:setup {
layout = wibox.layout.align.horizontal,
{ layout = wibox.layout.fixed.horizontal, mylauncher, s.mytaglist, s.mypromptbox },
s.mytasklist,
{ layout = wibox.layout.fixed.horizontal, mykeyboardlayout, wibox.widget.systray(), mytextclock, s.mylayoutbox },
}
end
awful.screen.connect_for_each_screen(function(s)
-- wallpaper
set_wallpaper(s)
-- tags
awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])
-- panel setup
build_panel(s)
end)
And add action to globalkeys
awful.key(
{ modkey }, "z",
function()
-- change theme settings
beautiful.bg_normal = "#ff2020"
beautiful.fg_normal = "#2020ff"
-- rebuild panel widgets
build_panel(mouse.screen)
end,
{description="theme colors change", group="awesome"}
),
I wanted the same and achieved that by writing a little script which is mapped to a shortcut. If you want to do it on your own, than you can follow these steps:
Create a folder which includes your themes.
Write a script (or use mine) which copys the files to your ~/.config/awesome folder.
Add a shortcut or something like that to execute the script.
The script should copy the files inside of your theme-folder to the config folder of awesome (~/.config/awesome).
After that you can see/use your theme after executing the script and restarting awesomewm (Default shortcut: modkey + shift + r
Your rc.lua file should only read files of your awesome-config-directory. You are just "overwriting" them by copying the files of your theme-folder. I hope the explanation is fine if not just comment on this answer.

Triggering mouse/touch events in Matter.js

How would one go about adding programmatically triggered touch/mouse events in Matter.js? I have a few collision events set up for the engine, but can not trigger a mouseup event that stops the current dragging action. I've tried various combinations of targeting the canvas element, the mouse/mouseConstraint, and the non-static body.
If you, like me, came here trying to figure out how to be able to click on a Matter.js body object, let me give you one way. My goal in my project was to assign some attributes to my rectangle objects and call a function when they were clicked on.
The first thing to do was to distinguish between dragging and clicking, so I wrote(using Jquery):
$("body").on("mousedown", function(e){
mouseX1 = e.pageX;
mouseY1 = e.pageY;
});
$("body").on("mouseup", function(e){
mouseX2 = e.pageX;
mouseY2 = e.pageY;
if((mouseX1 == mouseX2) && (mouseY1 == mouseY2)){
//alert("click!\n" + mouseX2 + " " + mouseY2 +"\n");
var bodiesUnder = Matter.Query.point(books, { x: mouseX2, y: mouseY2 });
//alert("click!\n" + mouseX2 + " " + mouseY2 +"\n");
if (bodiesUnder.length > 0) {
var bodyToClick = bodiesUnder[0];
alert(bodyToClick.title2);
}
}
});
This was accomplished when listening for "mouseup" and asking if ((mouseX1 == mouseX2) && (mouseY1 == mouseY2)).
Second- the juicy part- create a var array to hold the objects, or 'bodies', we are going to dig up under the mouse. Thankfully there's this function:
var bodiesUnder = Matter.Query.point(books, { x: mouseX2, y: mouseY2 });
For the first element in here I entered "books". For you this needs to be the name of an array you've put all your objects, or 'bodies' into. If you don't have them in an array, it's not hard to throw them all in, like so:
var books = [book1, book2, book3];
Once that was all done, I was able to alert(book1.title2) to see what the title of that book (body) is. My bodies were coded as follows:
var book2 = Bodies.rectangle(390, 200, 66, 70, {
render : {
sprite : {
texture: "img/tradingIcon.jpg"
}
},
restitution : 0.3,
title1 : 'Vanessa and Terry',
title2 : 'Trading'
});
Hope that helps! This one had me hung up for a whole day.
It turns out I had incorrectly configured the Matter.Mouse module, and was re-assigning the mouse input that had already been set in MouseConstraint. The following works in regards to my original question:
Matter.mouseConstraint.mouse.mouseup(event);

Matter.js Gravity Point

Is it possible to create a single gravity / force point in matter.js that is at the center of x/y coordinates?
I have managed to do it with d3.js but wanted to enquire about matter.js as it has the ability to use multiple polyshapes.
http://bl.ocks.org/mbostock/1021841
The illustrious answer has arisen:
not sure if there is any interest in this. I'm a fan of what you have created. In my latest project, I used matter-js but I needed elements to gravitate to a specific point, rather than into a general direction. That was very easily accomplished. I was wondering if you are interested in that feature as well, it would not break anything.
All one has to do is setting engine.world.gravity.isPoint = true and then the gravity vector is used as point, rather than a direction. One might set:
engine.world.gravity.x = 355;
engine.world.gravity.y = 125;
engine.world.gravity.isPoint = true;
and all objects will gravitate to that point.
If this is not within the scope of this engine, I understand. Either way, thanks for the great work.
You can do this with the matter-attractors plugin. Here's their basic example:
Matter.use(
'matter-attractors' // PLUGIN_NAME
);
var Engine = Matter.Engine,
Events = Matter.Events,
Runner = Matter.Runner,
Render = Matter.Render,
World = Matter.World,
Body = Matter.Body,
Mouse = Matter.Mouse,
Common = Matter.Common,
Bodies = Matter.Bodies;
// create engine
var engine = Engine.create();
// create renderer
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: Math.min(document.documentElement.clientWidth, 1024),
height: Math.min(document.documentElement.clientHeight, 1024),
wireframes: false
}
});
// create runner
var runner = Runner.create();
Runner.run(runner, engine);
Render.run(render);
// create demo scene
var world = engine.world;
world.gravity.scale = 0;
// create a body with an attractor
var attractiveBody = Bodies.circle(
render.options.width / 2,
render.options.height / 2,
50,
{
isStatic: true,
// example of an attractor function that
// returns a force vector that applies to bodyB
plugin: {
attractors: [
function(bodyA, bodyB) {
return {
x: (bodyA.position.x - bodyB.position.x) * 1e-6,
y: (bodyA.position.y - bodyB.position.y) * 1e-6,
};
}
]
}
});
World.add(world, attractiveBody);
// add some bodies that to be attracted
for (var i = 0; i < 150; i += 1) {
var body = Bodies.polygon(
Common.random(0, render.options.width),
Common.random(0, render.options.height),
Common.random(1, 5),
Common.random() > 0.9 ? Common.random(15, 25) : Common.random(5, 10)
);
World.add(world, body);
}
// add mouse control
var mouse = Mouse.create(render.canvas);
Events.on(engine, 'afterUpdate', function() {
if (!mouse.position.x) {
return;
}
// smoothly move the attractor body towards the mouse
Body.translate(attractiveBody, {
x: (mouse.position.x - attractiveBody.position.x) * 0.25,
y: (mouse.position.y - attractiveBody.position.y) * 0.25
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/matter-attractors#0.1.6/build/matter-attractors.min.js"></script>
Historical note: the "gravity point" functionality was proposed as a feature in MJS as PR #132 but it was closed, with the author of MJS (liabru) offering the matter-attractors plugin as an alternate. At the time of writing, this answer misleadingly seems to indicate that functionality from the PR was in fact merged.
Unfortunately, the attractors library is 6 years outdated at the time of writing and raises a warning when using a newer version of MJS than 0.12.0. From discussion in issue #11, it sounds like it's OK to ignore the warning and use this plugin with, for example, 0.18.0. Here's the warning:
matter-js: Plugin.use: matter-attractors#0.1.4 is for matter-js#^0.12.0 but installed on matter-js#0.18.0.
Behavior seemed fine on cursory glance, but I'll keep 0.12.0 in the above example to silence it anyway. If you do update to a recent version, note that Matter.World is deprecated and should be replaced with Matter.Composite and engine.gravity.

Changes to one variable propagates to another

For example I have two ArrayCollection's - firstAC and secondAC. If I do secondAC = firstAC, and than I make changes to secondAC (prehaps put a filterfunction on it) it somehow propagates to firstAC, would anyone tell me why that happens in Flex or Actionscript 3?
What can I do if I only want secondAC to get all data from firstAC but then when I make changes to secondAC it does not show in firstAC?
Thanxs a bunch for answers!
Ladislav
When you write secondAC = firstAC, you simply state that secondAC and firstAC are references to the same array collection.
What you want is to clone the first collection (as in, copy all elements one by one).
You should be able to do it with something like :
secondAC = new ArrayCollection();
secondAC.addAll(firstAC);
I have no idea of Flex or Actionscript, but looks like firstAC and secondAC point to the same array, therefore that's expected.
What you should do is just create another array, copy members, and they will be two real different entities.
Instead of secondAC = firstAC, you can try secondAC.addAll(firstAC).
In ECMAScript languages (AS1-3, JavaScript, et al.), when you use
var foo = //some value which is not a String or a Number
what you are really saying is "foo now points to the same object as that other variable." This means that in this situation, both arrays will be the same value:
var foo:Array = [ 1, 2, 3 ];
foo = bar;
bar.push( 4 );
trace( foo ); // 1, 2, 3, 4
This also works for functions:
var foo:Array = [ 1, 2, 3 ];
adder( foo );
function adder( bar:Array ):void {
bar.push( 4 );
}
trace( foo ); // 1, 2, 3, 4
and it even works with XML:
var xml:XML = <root><foo/></root>;
var bar:XML = xml;
bar.children()[ 0 ].#bar = 1;
trace( xml.toXMLString() ); // <root><foo bar="1"/></root>
This is called "passing by reference" instead of "passing by value" or "passing by copy". It means that every time that an item is referenced, each variable will point to the same object.
There are many ways to get around this, and most of them depend on your context. For arrays, my favorite is Array.concat(), which returns a literal clone of the array. This means that anything I do to the returned value will not effect the original in any way. If I'm dealing with XML, however, I will do something like: var xml2:XML = XML( xml.toXMLString() );.
In your case, I would actually recommend that you use:
var secondAC:ArrayCollection = new ArrayCollection( firstAC.source.concat() );
This has the major benefits of not only being faster (it relies on compiled code instead of Flex SDK code and it also does not first instantiate a new array and then re-populate it), but it also has the distinct benefit of being available in older versions of Flex 3's SDK -- it is entirely backwards compatible.

Resources