Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: JScript Panel script discussion/help (Read 378308 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Re: JScript Panel script discussion/help

Reply #1800
In the Thumbs sample I was unable to find, both in the loading modules and in the Thumbs module, the instruction that allows me to change the black color that I have under the various thumbs.



I have the entire skin in Dark Mode with the default UI setting, and I would like that black area under the thumbs to use the default UI setting.

Solved.

common.js

line158 :

//   gr.FillRectangle(x, y, w, h, RGBA(0, 0, 0, alpha || 230));
   gr.FillRectangle(x, y, w, h, RGBA(33, 33, 33));



Re: JScript Panel script discussion/help

Reply #1801
When importing a theme the headerbar.js module of jsplaylist crashes on line 70 currently to avoid this or disabled lines 70 / 71 / 72 of headerbar.js

//      var gb = this.slide_close.GetGraphics();
//      gb.FillRectangle(0, 0, cScrollBar.width, this.h, g_colour_text & 0x15ffffff);
//      gb.WriteTextSimple(chars.right, g_font_fluent_12, g_colour_text, 0, 1, cScrollBar.width, this.h, 2, 2);


Re: JScript Panel script discussion/help

Reply #1803
This is a weird bug, after upgrading 3.7.1 Properties crashes red screen if there is an empty playlist. This doesn't happen when there are albums in the playlist.

JScript Panel 3.7.1 (Properties by marc2003)
JavaScript runtime error
Unable to get property 'Path' of undefined or null reference
File: C:\Portable\foobar2000 64-bit LEGO Edition\foobar2000\profile\user-components-x64\foo_jscript_panel3\samples\js\properties.js
Line: 280, Col: 3

Re: JScript Panel script discussion/help

Reply #1804
Oops, that's a bug that got introduced in 3.7.0, thanks for spotting.

Saving this in the foo_jscript_panel3 component folder \samples\js overwriting the original should fix it.

https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/properties.js

Re: JScript Panel script discussion/help

Reply #1805
Hi Case--your first version of the VU Meter implementation made possible by marc2k3's new JSP code was here, using the same meter GUI as the original Ilovefb2k release.  Because the image scheme is classic, I am hoping that you wouldn't mind releasing a new version of the script?

The original has the problem of the 2 peak bars flickering out/disappearing when 0dB is reached or exceeded--have you found a way to fix that?  Also, it would be great if you could add the ability to adjust peak hold ms, and the ability to specify a maxdB level.
Here's a quick refresh combining bits of old and semi new. Doesn't include any of the fancy menu stuff marc2k3 added.
Code: [Select]
// ==PREPROCESSOR==
// @name "JSP3 VU Meter (Stereo Mode)"
// ==/PREPROCESSOR==

// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 1; // in frames
var peak_fall_mul = 0.9;
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 5; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
var bar_height_static = 20; // use 0 to scale to panel size
var rms_block_count = 20; // number of blocks in meter style 1
var rms_block_db = 2.5;   // dBs per block in meter style 2
var meter_style = 1; // 1: constant number of blocks, 2: dynamic block count to align with dB scale
//
// End of user adjustable settings
// -------------------------------

var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = Peak_falldown1 = Peak_falldown2 = 0;
var rms_db_offset = (!rms_3db) ? (0) : (20 * Math.log(Math.sqrt(2)) / Math.LN10); // 3.01029995663981 dB
var dBrange = maxDB - minDB;
var timer_id = 0;

var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var color_1;
var color_2;
var colours = {
  text : 0,
  background : 0,
  highlight : 0,
}
var brush = {
  Stops : [],
  Start : [0, 0], // x and y values
  End : [0, 0], // x and y values
};
var brush_str = "";

var ColourTypeCUI = {
  text: 0,
  selection_text: 1,
  inactive_selection_text: 2,
  background: 3,
  selection_background: 4,
  inactive_selection_background: 5,
  active_item_frame: 6
};


var ColourTypeDUI = {
  text: 0,
  background: 1,
  highlight: 2,
  selection: 3
};

var FontTypeCUI = {
  items : 0,
  labels : 1,
};

var FontTypeDUI = {
  defaults : 0,
  tabs : 1,
  lists : 2,
  playlists : 3,
  statusbar : 4,
  console : 5,
};

function update_colours() {
  if (window.IsDefaultUI) {
    colours.text = window.GetColourDUI(ColourTypeDUI.text);
    colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
    colours.background = window.GetColourDUI(ColourTypeDUI.background);
  } else {
    colours.text = window.GetColourCUI(ColourTypeCUI.text);
    colours.background = window.GetColourCUI(ColourTypeCUI.background);
    colours.highlight = blendColours(colours.text, colours.background, 0.4);
  }

  //custom colours override
  //  colours.text = RGB(255,255,255);
  //  colours.highlight = RGB(0,0,250);
  //  colours.background = RGB(0,0,0);

  color_1 = colours.text; //  or any color  RGB(250,250,250);
  color_2 = colours.highlight; // or any color RGB(0,0,0);

  brush.Stops = [
   [0.0, color_1],
   [1.0, color_2],
  ]
  brush_str = JSON.stringify(brush);
}

function update_font() {
  if (window.IsDefaultUI) {
    font = window.GetFontDUI(FontTypeDUI.defaults);
  } else {
    font = window.GetFontCUI(FontTypeCUI.items);
  }

  // adjust size
  font_t = font;
  var obj = JSON.parse(font_t);
  obj.Size -= 4;
  font_t = JSON.stringify(obj);
}

function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
  var a = col - 0xFF000000;
  return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}

function blendColours(c1, c2, factor) { //@Marc2003
  var c1 = toRGB(c1);
  var c2 = toRGB(c2);
  var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
  var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
  var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
  return (0xff000000 | (r << 16) | (g << 8) | (b));
}

function clear_graph() {
  RMS_level1 = RMS_level2 = 0;
  Peak_level1 = Peak_level2 = 0;
  Peak_falldown1 = Peak_falldown2 = 0;
  window.Repaint();
}

function update_graph() {
  if (fb.PlaybackTime > rms_window) {
    var chunk = fb.GetAudioChunk(rms_window);
    if (chunk) {
      var data = chunk.Data.toArray();
      var nch = chunk.ChannelCount;
      var frame_len = chunk.SampleCount;
      if (data && nch > 0 && frame_len > 0) {
        var ch2_idx = (nch >= 2) ? 1 : 0;
        var sum1 = sum2 = peak1 = peak2 = 0;
        for (var i = 0; i < data.length; i += nch) {
          var s1 = Math.abs(data[i]);
          var s2 = Math.abs(data[i + ch2_idx]);
          if (s1 > peak1) peak1 = s1;
          if (s2 > peak2) peak2 = s2;
          sum1 += s1 * s1;
          sum2 += s2 * s2;
        }
        RMS_level1 = Math.sqrt(sum1/frame_len);
        RMS_level2 = Math.sqrt(sum2/frame_len);
        if (++Peak_falldown1 > peak_hold) Peak_level1 *= peak_fall_mul;
        if (++Peak_falldown2 > peak_hold) Peak_level2 *= peak_fall_mul;
        if (peak1 >= Peak_level1) {
          Peak_level1 = peak1;
          Peak_falldown1 = 0;
        }
        if (peak2 >= Peak_level2) {
          Peak_level2 = peak2;
          Peak_falldown2 = 0;
        }
        window.Repaint();
      }
    }
  }
}

function start_timer() {
  if (!timer_id) timer_id = window.SetInterval(update_graph, timer_interval);
}

function stop_timer() {
  if (timer_id) window.ClearInterval(timer_id);
  timer_id = 0;
}

function to_db(num) {
  return 20 * Math.log(num) / Math.LN10;
}

function clamp(value, min, max) {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}

function get_colour_for_db(db) {
  /*
  if (colour_mode != 0) {
    var f = db / dBrange;
    for (var i = 0; i < rainbow_stops.length-1; ++i) {
      var a = rainbow_stops[i][0];
      var b = rainbow_stops[i+1][0];
      var ca = rainbow_stops[i][1];
      var cb = rainbow_stops[i+1][1];
      if (b > a) {
        var t = a; a = b; b = t;
        var tc = ca; ca = cb; cb = tc;
      }
      if (a >= f && f >= b) {
        return blendColours(cb, ca, (f - b) / (a - b));
      }
    }
  }
  */
  return blendColours(colours.text, colours.highlight, db / dBrange);
}

// UI callbacks
function on_colours_changed() {
  update_colours();
  window.Repaint();
}

function on_mouse_lbtn_up(x, y) {
  window.ShowConfigure();
}

function on_size() {
  ww = window.Width;
  wh = window.Height;
}

function on_paint(gr) {
  gr.Clear(colours.background);
  if (wh < 1 || ww < 1) return;

  var hide_ch_labels = false;
  var hide_db_labels = false;
  var bar_pad_left = 3*8;
  var bar_pad_right = 3*8;
  var bar_pad_top = 5;
  var bar_pad_bottom = 30;
  var bar_height = 0;
  var bar_width = 0;

  bar_height = (bar_height_static > 0) ? (bar_height_static) : (Math.floor((wh - bar_pad_top - bar_pad_bottom) / 4));

  if (bar_height < 8) { // bars are too thin for channel labels, hide them
    hide_ch_labels = true;
  }
  if (bar_height < 4) { // bars are too thin for dB scale too
    hide_ch_labels = true;
    hide_db_labels = true;
    bar_pad_top = 0;
    bar_pad_bottom = 0;
    bar_pad_left = 0;
    bar_pad_right = 0;
    bar_height = Math.floor(wh / 4);
  }

  bar_width = ww - bar_pad_left - bar_pad_right;

  // labels
  if (!hide_db_labels) {
    var db_spacing = 5;
    if (dBrange < db_spacing) db_spacing = 1;
    if (ww * db_spacing / dBrange < 10*8) {
      db_spacing = ((10*8 * dBrange) / ww);
      db_spacing -= (db_spacing % 5);
    }

    var y = bar_pad_top + (bar_height * 4) + 5;
    gr.FillRectangle(bar_pad_left, y, bar_width, 1, colours.text);

    for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
      var x = bar_pad_left + (bar_width * j / (dBrange / db_spacing));
      gr.WriteText(i + "dB", font_t, colours.text, x - (bar_pad_left / 2), y + 5, ww, wh);
      gr.DrawLine(x, y-2, x, y+2, 1, colours.text);
    }
  }

  if (!hide_ch_labels) {
    gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 0) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 1) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 2) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 3) + bar_height / 2 - 8, ww, wh);
  }

  // bars
  var block_count = rms_block_count;
  if (meter_style == 2 && rms_block_db > 0) block_count = Math.floor(dBrange / rms_block_db);
  if (block_count < 1) block_count = 1;
  var block_width = bar_width / block_count;
  var block_pad = Math.ceil(block_width * 0.03);
  if (block_pad < 1) block_pad = 1;

  if (Peak_level1 > 0) {
    var peak_db1 = clamp(to_db(Peak_level1), minDB, maxDB);
    if (peak_db1 > minDB) {
      var width1 = Math.round(bar_width * (peak_db1 - minDB) / dBrange);
      gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 0) + 1, width1, bar_height - 3, brush_str);
    }
  }
  if (Peak_level2 > 0) {
    var peak_db2 = clamp(to_db(Peak_level2), minDB, maxDB);
    if (peak_db2 > minDB) {
      var width2 = Math.round(bar_width * (peak_db2 - minDB) / dBrange);
      gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 3) + 1, width2, bar_height - 3, brush_str);
    }
  }

  if (RMS_level1 > 0) {
    var rms_db1 = clamp(to_db(RMS_level1) + rms_db_offset, minDB, maxDB);
    var blocks1 = Math.round(block_count * (rms_db1 - minDB) / dBrange);
    for (var i = 0; i < blocks1; ++i) {
      gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 1) + 1, block_width - block_pad, bar_height - 3, get_colour_for_db(i * dBrange / block_count));
    }
  }
  if (RMS_level2 > 0) {
    var rms_db2 = clamp(to_db(RMS_level2) + rms_db_offset, minDB, maxDB);
    var blocks2 = Math.round(block_count * (rms_db2 - minDB) / dBrange);
    for (var i = 0; i < blocks2; ++i) {
      gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 2) + 1, block_width - block_pad, bar_height - 3, get_colour_for_db(i * dBrange / block_count));
    }
  }
}

// fb2k callbacks
function on_playback_new_track(handle) {
  start_timer();
}

function on_playback_stop(reason) {
  if (reason != 2) stop_timer(); // not starting another track
  clear_graph();
}

function on_playback_pause(state) {
  state ? stop_timer() : start_timer();
}

function init() {
  update_colours();
  update_font();

  if (fb.IsPlaying) start_timer();
}

init();

Re: JScript Panel script discussion/help

Reply #1806
Here's a quick refresh combining bits of old and semi new. Doesn't include any of the fancy menu stuff marc2k3 added.
Many thanks Case for doing a revision based on the 4-bar "first look" you did after marc2k3 first made the direct data read possible--it fixes ALL the initial performance issues, and while the visual presentation differs slightly from the first (less space between the bars etc.) there are plenty of user configurable settings both grouped as such at the script's top, and in its body for the "daring" to experiment with.  Which I will be doing for the rest of the day!  Cool.

Re: JScript Panel script discussion/help

Reply #1807
I found a way, with the sample Text Reader, to read the lyrics that are thrown into the lyrics folder by ESLyrics by inserting the following string in the custom path:

Unsynced

$if($strstr(%path%,'://'),C:\foobar2000 Portable\Apache Evolution Theme 64 BIT\foobar2000\profile\lyrics\%album artist% - %title%.txt)



Synced



$if($strstr(%path%,'://'),C:\foobar2000 Portable\Apache Evolution Theme 64 BIT\foobar2000\profile\lyrics\%album artist% - %title%.lrc)

Is it possible to change the font from string?

Re: JScript Panel script discussion/help

Reply #1808
Is it possible to change the font from string?

right? It would be nicer if component developers didn't inflict their preferences on everyone but whatever.

Re: JScript Panel script discussion/help

Reply #1809
If you choose another font in the main preferences, the panel updates itself to use that. So please go fuck yourself.

And even if it was hardcoded, it's nothing like as abhorrent as that volume changing in the other thread. I notice there was no appreciation of me finding that for you. Go fuck yourself again.

Re: JScript Panel script discussion/help

Reply #1810
If you choose another font in the main preferences, the panel updates itself to use that. So please go fuck yourself.

And even if it was hardcoded, it's not like as abhorrent as that volume changing in the other thread. I notice there was no appreciation of me finding that for you. Go fuck yourself again.

Not abhorrent, unless someone lacked the slightest understanding of why headlines have different fonts/sizes/colors than body copy, and then insisted on burying in every sample, the opportunity for users to modify the options.

Or how about when someone decides to maintain the most excellent Smooth panels, but proceeds to immediately rip out all of the UX customizations that made them useful in the first place?

The point here is one might be more mindful about throwing stones from glass houses if they are a fragile POS.

Re: JScript Panel script discussion/help

Reply #1811
@mjm716 while I don't find marc's replies a valid behavior on forums (and still wonder how mods simply ignore these things...), yours makes no sense.

I mean, you may not agree with the development, for sure. And I may find reasonable to criticize things if they have no logic or don't follow the dev's design or intents but... expecting a dev should do something for you just because you want it in a different way, makes zero sense. I mean, no one here is being paid.

If marc chooses to set the default font like this in all his scripts, it would be perefectly fine... because maybe you have forgotten the first and last user of everything he does is himself. Just saying, people on these forums seem to forget that xd also with my scripts ;) You may ask in a positive way for "options" but complaining about defaults set by the developer.. what answer did you expect? XD

Also if you don't want to spend 3 min searching the line to change the font, maybe a dev doesn't want to spend 1 h creating a menu entry to set it. (not saying is you case, just something which is common around here). Just looking at the VU Meter script for ex. there have been like +10 change requests in one month xd well, maybe people think devs are slaves to fullfill others' desires. ::)

Re: JScript Panel script discussion/help

Reply #1812
@mjm716 while I don't find marc's replies a valid behavior on forums (and still wonder how mods simply ignore these things...), yours makes no sense.

Firstly I agree with you 100% that *all* devs are entitled to work however they like and we're lucky they do.

context: https://hydrogenaud.io/index.php/topic,126042.msg1050146.html#msg1050146

Re: JScript Panel script discussion/help

Reply #1813
For sure that applies to everyone, him too.  And while that particular reply could be read as rude or a request, I would say it was a tip from a dev to another dev (with wrong wording), since Marc was not requesting anything for himself. I get the irony on your reply, obviously, but they are not the same situation.

Anyway I will not be the one defending his words, I already said this kind of behavior is not allowed on most forums and other users are banned for less. I still don't get what's going on with HA TOS, since point 2 seems to be applied in a totally arbitrary way. Not that I want anyone to be banned.

Re: JScript Panel script discussion/help

Reply #1814
hi all a bit off the topic but any way to add coloured popup like winamp

many thanks telboy

Re: JScript Panel script discussion/help

Reply #1815
@telboy1812

> coloured popup like winamp
Could you please be a bit more specific?
------
Flowin (foo_flowin)
https://github.com/ttsping/foo_flowin/releases



On the right is WebView (foo_uie_webview).
https://github.com/stuerp/foo_uie_webview/releases

SHURE SRH1840, SENNHEISER HD660S2, SENNHEISER HD620S, SENNHEISER HD 490 Pro Plus, beyerdynamic DT 1990 PRO, HiFiMAN Edition XS, Bowers & Wilkins P7, FiiO FT5, 水月雨 (MOONDROP) 空鳴 - VOID, Nakamichi Elite FIVE ANC, SONY WH1000XM5 (made a Upgrade/Balanced Cable by myself)

Re: JScript Panel script discussion/help

Reply #1816
like this maybe

Re: JScript Panel script discussion/help

Reply #1817
This is possible with both Flowin (foo_flowin) or Popup Panels (foo_popup_panels).

Popup Panels (foo_popup_panels)
https://www.foobar2000.org/components/view/foo_popup_panels

Flowin:
You can create as many Panels as you like.
There are many options



This is not the question for this thread.
SHURE SRH1840, SENNHEISER HD660S2, SENNHEISER HD620S, SENNHEISER HD 490 Pro Plus, beyerdynamic DT 1990 PRO, HiFiMAN Edition XS, Bowers & Wilkins P7, FiiO FT5, 水月雨 (MOONDROP) 空鳴 - VOID, Nakamichi Elite FIVE ANC, SONY WH1000XM5 (made a Upgrade/Balanced Cable by myself)

Re: JScript Panel script discussion/help

Reply #1818
yes i know and i am sorry I have it installed but no idea how to get it work sorry

almost sorted it thank you ken :)

Re: JScript Panel script discussion/help

Reply #1819
Hi,

I am using the "Text Display" sample and I want to achieve some specific effects:
1-How can I add a simple white stroke/border effect to the album cover in the foreground?
(Sometimes, the album cover in the foreground can lost itself and blend in the blurred album art background when the album art's colors are darker in general. So, hence why I'd like to achieve this.)
2-How can I add a colored drop shadow effect to the custom text?

Thanks!

One more VU meter--NOT a request!!

Reply #1820
Thanks to Case, Air Ken, marc2k3, and ilove2fbk who did the original image, I finally was able to obtain the JSP3 VU Meter design that not only has the latest technical and functional elements but maintained the graphic 4-bar meter design and color scheme of that first pre-JSP3 3.6.6 model.  I did a little tweaking myself on the bar padding.  Anyway, after everybody having to suffer through my VU Meter design requests here I wanted to post the script for anyone who also hoped for a re-worked version of that clunky original.  Requires at least JSP3 3.6.6, working smooth here with the latest 3.7.4 release.
Code: [Select]
// ==PREPROCESSOR==
// @name "JSP3 VU Meter (Stereo Mode)"
// ==/PREPROCESSOR==

// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 1; // in frames
var peak_fall_mul = 0.9;
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 10; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
var bar_height_static = 17; // use 0 to scale to panel size
var rms_block_count = 30; // number of blocks in meter style 1
var rms_block_db = 3;   // dBs per block in meter style 2
var meter_style = 2; // 1: constant number of blocks, 2: dynamic block count to align with dB scale
//
// End of user adjustable settings
// -------------------------------

var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = Peak_falldown1 = Peak_falldown2 = 0;
var rms_db_offset = (!rms_3db) ? (0) : (20 * Math.log(Math.sqrt(2)) / Math.LN10); // 3.01029995663981 dB
var dBrange = maxDB - minDB;
var timer_id = 0;

var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var color_1;
var color_2;
var colours = {
  text : 0,
  background : 0,
  highlight : 0,
}
var brush = {
  Stops : [],
  Start : [0, 0], // x and y values
  End : [0, 0], // x and y values
};
var brush_str = "";

var ColourTypeCUI = {
  text: 0,
  selection_text: 1,
  inactive_selection_text: 2,
  background: 3,
  selection_background: 4,
  inactive_selection_background: 5,
  active_item_frame: 6
};


var ColourTypeDUI = {
  text: 0,
  background: 1,
  highlight: 2,
  selection: 3
};

var FontTypeCUI = {
  items : 0,
  labels : 1,
};

var FontTypeDUI = {
  defaults : 0,
  tabs : 1,
  lists : 2,
  playlists : 3,
  statusbar : 4,
  console : 5,
};

function update_colours() {
  if (window.IsDefaultUI) {
    colours.text = window.GetColourDUI(ColourTypeDUI.text);
    colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
    colours.background = window.GetColourDUI(ColourTypeDUI.background);
  } else {
    colours.text = window.GetColourCUI(ColourTypeCUI.text);
    colours.background = window.GetColourCUI(ColourTypeCUI.background);
    colours.highlight = blendColours(colours.text, colours.background, 0.4);
  }

  //custom colours override
    colours.text = RGB(255,255,255);
    colours.highlight = RGB(23,179,255);
    colours.background = RGB(30,30,30);

  color_1 = colours.text; // RGB(250,250,250);
  color_2 = colours.highlight; // RGB(0,70,250);

  brush.Stops = [
   [3.0, color_1],
   [1.2, color_2],
  ]
  brush_str = JSON.stringify(brush);
}

function update_font() {
  if (window.IsDefaultUI) {
    font = window.GetFontDUI(FontTypeDUI.defaults);
  } else {
    font = window.GetFontCUI(FontTypeCUI.items);
  }

  // adjust size
  font_t = font;
  var obj = JSON.parse(font_t);
  obj.Size -= 4;
  font_t = JSON.stringify(obj);
}

function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
  var a = col - 0xFF000000;
  return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}

function blendColours(c1, c2, factor) { //@Marc2003
  var c1 = toRGB(c1);
  var c2 = toRGB(c2);
  var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
  var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
  var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
  return (0xff000000 | (r << 16) | (g << 8) | (b));
}

function clear_graph() {
  RMS_level1 = RMS_level2 = 0;
  Peak_level1 = Peak_level2 = 0;
  Peak_falldown1 = Peak_falldown2 = 0;
  window.Repaint();
}

function update_graph() {
  if (fb.PlaybackTime > rms_window) {
    var chunk = fb.GetAudioChunk(rms_window);
    if (chunk) {
      var data = chunk.Data.toArray();
      var nch = chunk.ChannelCount;
      var frame_len = chunk.SampleCount;
      if (data && nch > 0 && frame_len > 0) {
        var ch2_idx = (nch >= 2) ? 1 : 0;
        var sum1 = sum2 = peak1 = peak2 = 0;
        for (var i = 0; i < data.length; i += nch) {
          var s1 = Math.abs(data[i]);
          var s2 = Math.abs(data[i + ch2_idx]);
          if (s1 > peak1) peak1 = s1;
          if (s2 > peak2) peak2 = s2;
          sum1 += s1 * s1;
          sum2 += s2 * s2;
        }
        RMS_level1 = Math.sqrt(sum1/frame_len);
        RMS_level2 = Math.sqrt(sum2/frame_len);
        if (++Peak_falldown1 > peak_hold) Peak_level1 *= peak_fall_mul;
        if (++Peak_falldown2 > peak_hold) Peak_level2 *= peak_fall_mul;
        if (peak1 >= Peak_level1) {
          Peak_level1 = peak1;
          Peak_falldown1 = 0;
        }
        if (peak2 >= Peak_level2) {
          Peak_level2 = peak2;
          Peak_falldown2 = 0;
        }
        window.Repaint();
      }
    }
  }
}

function start_timer() {
  if (!timer_id) timer_id = window.SetInterval(update_graph, timer_interval);
}

function stop_timer() {
  if (timer_id) window.ClearInterval(timer_id);
  timer_id = 0;
}

function to_db(num) {
  return 20 * Math.log(num) / Math.LN10;
}

function clamp(value, min, max) {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}

function get_colour_for_db(db) {
  /*
  if (colour_mode != 0) {
    var f = db / dBrange;
    for (var i = 0; i < rainbow_stops.length-1; ++i) {
      var a = rainbow_stops[i][0];
      var b = rainbow_stops[i+1][0];
      var ca = rainbow_stops[i][1];
      var cb = rainbow_stops[i+1][1];
      if (b > a) {
        var t = a; a = b; b = t;
        var tc = ca; ca = cb; cb = tc;
      }
      if (a >= f && f >= b) {
        return blendColours(cb, ca, (f - b) / (a - b));
      }
    }
  }
  */
  return blendColours(colours.text, colours.highlight, db / dBrange);
}

// UI callbacks
function on_colours_changed() {
  update_colours();
  window.Repaint();
}

function on_mouse_lbtn_up(x, y) {
  window.ShowConfigure();
}

function on_size() {
  ww = window.Width;
  wh = window.Height;
}

function on_paint(gr) {
  gr.Clear(colours.background);
  if (wh < 1 || ww < 1) return;

  var hide_ch_labels = false;
  var hide_db_labels = false;
  var bar_pad_left = 3*8;
  var bar_pad_right = 3*8;
  var bar_pad_top = 36;
  var bar_pad_bottom = 30;
  var bar_height = 0;
  var bar_width = 0;

  bar_height = (bar_height_static > 0) ? (bar_height_static) : (Math.floor((wh - bar_pad_top - bar_pad_bottom) / 4));

  if (bar_height < 8) { // bars are too thin for channel labels, hide them
    hide_ch_labels = true;
  }
  if (bar_height < 4) { // bars are too thin for dB scale too
    hide_ch_labels = true;
    hide_db_labels = true;
    bar_pad_top = 0;
    bar_pad_bottom = 0;
    bar_pad_left = 0;
    bar_pad_right = 0;
    bar_height = Math.floor(wh / 4);
  }

  bar_width = ww - bar_pad_left - bar_pad_right;

  // labels
  if (!hide_db_labels) {
    var db_spacing = 5;
    if (dBrange < db_spacing) db_spacing = 1;
    if (ww * db_spacing / dBrange < 10*8) {
      db_spacing = ((10*8 * dBrange) / ww);
      db_spacing -= (db_spacing % 5);
    }

    var y = bar_pad_top + (bar_height * 4) + 5;
    gr.FillRectangle(bar_pad_left, y, bar_width, 1, colours.text);

    for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
      var x = bar_pad_left + (bar_width * j / (dBrange / db_spacing));
      gr.WriteText(i + "dB", font_t, colours.text, x - (bar_pad_left / 2), y + 5, ww, wh);
      gr.DrawLine(x, y-2, x, y+2, 1, colours.text);
    }
  }

  if (!hide_ch_labels) {
    gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 0) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 1) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 2) + bar_height / 2 - 8, ww, wh);
    gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 3) + bar_height / 2 - 8, ww, wh);
  }

  // bars
  var block_count = rms_block_count;
  if (meter_style == 2 && rms_block_db > 0) block_count = Math.floor(dBrange / rms_block_db);
  if (block_count < 1) block_count = 1;
  var block_width = bar_width / block_count;
  var block_pad = Math.ceil(block_width * 0.11);
  if (block_pad < 1) block_pad = 1;

  if (Peak_level1 > 0) {
    var peak_db1 = clamp(to_db(Peak_level1), minDB, maxDB);
    if (peak_db1 > minDB) {
      var width1 = Math.round(bar_width * (peak_db1 - minDB) / dBrange);
      gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 0) + 0, width1, bar_height - 3, brush_str);
    }
  }
  if (Peak_level2 > 0) {
    var peak_db2 = clamp(to_db(Peak_level2), minDB, maxDB);
    if (peak_db2 > minDB) {
      var width2 = Math.round(bar_width * (peak_db2 - minDB) / dBrange);
      gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 3) + 3, width2, bar_height - 3, brush_str);
    }
  }

  if (RMS_level1 > 0) {
    var rms_db1 = clamp(to_db(RMS_level1) + rms_db_offset, minDB, maxDB);
    var blocks1 = Math.round(block_count * (rms_db1 - minDB) / dBrange);
    for (var i = 0; i < blocks1; ++i) {
      gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 1) + 1, block_width - block_pad, bar_height - 4, get_colour_for_db(i * dBrange / block_count));
    }
  }
  if (RMS_level2 > 0) {
    var rms_db2 = clamp(to_db(RMS_level2) + rms_db_offset, minDB, maxDB);
    var blocks2 = Math.round(block_count * (rms_db2 - minDB) / dBrange);
    for (var i = 0; i < blocks2; ++i) {
      gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 2) + 1, block_width - block_pad, bar_height - 2, get_colour_for_db(i * dBrange / block_count));
    }
  }
}

// fb2k callbacks
function on_playback_new_track(handle) {
  start_timer();
}

function on_playback_stop(reason) {
  if (reason != 2) stop_timer(); // not starting another track
  clear_graph();
}

function on_playback_pause(state) {
  state ? stop_timer() : start_timer();
}

function init() {
  update_colours();
  update_font();

  if (fb.IsPlaying) start_timer();
}

init();


Re: JScript Panel script discussion/help

Reply #1821


I was looking to replicate the spotify now playing full screen. So I just did an awful attempt to the images script and text display + buttons script.
This lets us load artist images from Last.fm while still giving us the flexibility of the text display.
I'm not sure how to resize the album art from the text script, so I've just loaded a new album art on top of the text.
This layout could be useful for those who like dynamic backgrounds or for those who want to set it up with Flowin for now playing full screen.

Since I don't know how to override the properties, so I had to do the steps below manually to get the display like above.
Right click > Uncheck album art background
Right click > Text alignment (horizontal) >Left
Right click > Text alignment (vertical) >Bottom
Right click > Margin...> 140
Shift + Right click > Last.fm artist art
Shift + Right click > Crop (Focus on top) (Optional)
Code: [Select]
// ==PREPROCESSOR==
// @name "Images"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\images.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==

var panel = new _panel({ custom_background : true });
var images = new _images();
///
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
var seekbar = new _seekbar(0, 0, 0, 0);

var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};

var tfo = {
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat('$if2(%length%,LIVE)'),
};

var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var bottom_y = 0;

buttons.update = function () {
var x = (panel.w - (bs * 7)) / 2
var y = seekbar.y + _scale(12);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour: fb.StopAfterCurrent ? colours.contrast : colours.white}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.white }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.white}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.white }, null, function () { fb.Next(); }, 'Next');
this.buttons.search = new _button(x + (bs * 5), y, bs, bs, { char : chars.search, colour:colours.white }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _button(x + (bs * 6), y, bs, bs, { char : chars.preferences, colour:colours.white}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
///
panel.item_focus_change();

function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
window.Repaint();
}

function on_font_changed() {
panel.font_changed();
text.refresh(true);
window.Repaint();
}

function on_http_request_done(task_id, success, response_text) {
images.http_request_done(task_id, success, response_text);
}

function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}

function on_key_down(k) {
images.key_down(k);
}

function on_metadb_changed(handles, fromhook) {
if (fromhook) return;
images.metadb_changed();
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}

function on_mouse_move(x, y) {
if (albumart.move(x, y)) {
return;
} else if (seekbar.move(x, y)) {
return;
} else if (buttons.move(x, y)) {
return;
}
text.move(x, y);
images.move(x, y);
}

function on_mouse_lbtn_dblclk(x, y) {
images.lbtn_dblclk(x, y);
}

function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}

function on_mouse_lbtn_up(x, y) {
if (seekbar.lbtn_up(x, y)) {
return;
} else if (buttons.lbtn_up(x, y)) {
return;
}
text.lbtn_up(x, y);
}

function on_mouse_leave() {
buttons.leave();
}

function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
if (utils.IsKeyPressed(VK_SHIFT)) {
return panel.rbtn_up(x, y, images);
} else {
return panel.rbtn_up(x, y, text);
}
}

function on_mouse_wheel(s) {
if (albumart.wheel(s)) {
return;
} else if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
images.wheel(s);
}

function on_paint(gr) {
panel.paint(gr);
images.paint(gr);

_drawOverlay(gr, 0, 0, panel.w, panel.h, 100);

text.paint(gr);

_drawImage(gr, albumart.img, 20, panel.h - 340, 150, 150, image.crop);

buttons.paint(gr);

gr.FillRoundedRectangle(seekbar.x, seekbar.y, seekbar.w, seekbar.h, _scale(2), _scale(2), colours.slider_background);

if (fb.IsPlaying) {
var time_width = seekbar.x - _scale(12);
gr.WriteText(tfo.playback_time.Eval(), font, colours.white, 0, bottom_y, time_width, _scale(12), 1, 2);
gr.WriteText(tfo.length.Eval(), font, colours.white, seekbar.x + seekbar.w + _scale(12), bottom_y, time_width, _scale(12), 0, 2);

if (fb.PlaybackLength > 0) {
gr.FillEllipse(seekbar.x + seekbar.pos(), seekbar.y + _scale(3), _scale(6), _scale(6), colours.white);
}
}
}

function on_playback_order_changed() {
buttons.update();
window.Repaint();
}

function on_playback_dynamic_info_track(type) {
if (type == 0) {
images.playback_new_track();
text.metadb_changed() ;
} else if (type == 1) albumart.metadb_changed();
}

function on_playback_new_track() {
panel.item_focus_change();
images.playback_new_track();
}

function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}

function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}

function on_playback_starting() {
buttons.update();
window.Repaint();
}

function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}

buttons.update();
window.Repaint();
}

function on_playback_time() {
images.playback_time();
//
text.playback_time();
window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playlist_items_added() {
text.refresh();
}

function on_playlist_items_removed() {
text.refresh();
}

function on_playlist_items_reordered() {
text.refresh();
}

function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}

function on_playlist_switch() {
on_item_focus_change();
}

function on_playlists_changed() {
text.refresh();
}


function on_size() {
panel.size();

images.w = panel.w;
images.h = panel.h;
//
text.size();

seekbar.x = _scale(60);
seekbar.y = panel.h - _scale(120);
seekbar.w = panel.w - (seekbar.x * 2);
seekbar.h = _scale(6);

bottom_y = seekbar.y - _scale(4);
buttons.update();
}

Re: JScript Panel script discussion/help

Reply #1822
Playing around with image script and text display with svg buttons.



Re: JScript Panel script discussion/help

Reply #1824
Can I send a script?
Instruction:
Spoiler (click to show/hide)
Code: [Select]
// ==PREPROCESSOR==
// @name "Images + Text Display + Album Art + Custom SVG and PNG Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\images.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==

var panel = new _panel({ custom_background : true });
var images = new _images();
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);

//.svg files
var folder = utils.LoadSVG(fb.ProfilePath + 'images\\folder.svg');
var youtube = utils.LoadSVG(fb.ProfilePath + 'images\\youtube.svg');
var spotify = utils.LoadSVG(fb.ProfilePath + 'images\\spotify.svg');
var wikipedia = utils.LoadSVG(fb.ProfilePath + 'images\\wikipedia.svg');
var lastfm = utils.LoadSVG(fb.ProfilePath + 'images\\lastfm.svg');
var search = utils.LoadSVG(fb.ProfilePath + 'images\\search.svg');
var settings = utils.LoadSVG(fb.ProfilePath + 'images\\settings.svg');
//.png files
var guitar = utils.LoadImage(fb.ProfilePath + 'images\\guitar.png');

var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat('$if2(%length%,LIVE)'),
}

var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};

var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var mg = _scale(4);
var bottom_y = 0;

buttons.update = function () {
var x = (panel.w - (bs * 9)) / 2
var y = bottom_y;
var handle_list = fb.GetFocusItem();

this.buttons.folder = new _button(x + (bs * 5 + mg * 5), y, bs, bs, { img : folder }, null, function () { _explorer(handle_list.path); }, 'folder');
this.buttons.youtube = new _button(x, y, bs, bs, { img : youtube }, null, function () { utils.Run('http://www.youtube.com/results?search_query=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'youtube');
this.buttons.spotify = new _button(x + bs + mg, y, bs, bs, { img : spotify}, null, function () { utils.Run('https://open.spotify.com/search/' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'spotify');
this.buttons.wikipedia = new _button(x + (bs * 2 + mg * 2), y, bs, bs, { img : wikipedia }, null, function () { utils.Run('http://en.wikipedia.org/wiki/Special:Search?search=' + encodeURIComponent(tfo.artist.Eval()));  }, 'wikipedia');
this.buttons.lastfm = new _button(x + (bs * 3 + mg * 3), y, bs, bs, { img : lastfm }, null, function () { utils.Run('https://www.last.fm/search?q=' + encodeURIComponent(tfo.artist.Eval()));  }, 'lastfm');
this.buttons.guitar = new _button(x + (bs * 4 + mg * 4), y, bs, bs, { img : guitar }, null, function () { utils.Run('https://www.ultimate-guitar.com/search.php?search_type=title&value=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'Ultimate Guitar');
this.buttons.search = new _button(x + (bs * 6 + mg * 6), y, bs, bs, { img : search }, null, function () { fb.ShowLibrarySearchUI('artist IS ' + tfo.artist.Eval()); }, 'Search');
this.buttons.preferences = new _button(x + (bs * 7 + mg * 7), y, bs, bs, { img : settings}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}

panel.item_focus_change();

function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
window.Repaint();
}

function on_font_changed() {
panel.font_changed();
text.refresh(true);
window.Repaint();
}

function on_http_request_done(task_id, success, response_text) {
images.http_request_done(task_id, success, response_text);
}

function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}

function on_key_down(k) {
images.key_down(k);
}

function on_metadb_changed(handles, fromhook) {
if (fromhook) return;
images.metadb_changed();
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}

function on_mouse_move(x, y) {
text.move(x, y);
images.move(x, y);
buttons.move(x, y);

_.forEach(buttons.buttons, function (button) {
if (button.containsXY(x, y)) {
window.SetCursor(IDC_HAND);
return;
}
});
}

function on_mouse_lbtn_dblclk(x, y) {
images.lbtn_dblclk(x, y);
}

function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
// text.lbtn_up(x, y);
}

function on_mouse_leave() {
buttons.leave();
}

function on_mouse_rbtn_up(x, y) {
if (utils.IsKeyPressed(VK_SHIFT)) {
return panel.rbtn_up(x, y, images);
} else {
return panel.rbtn_up(x, y, text);
}
}

function on_mouse_wheel(s) {
text.wheel(s);
images.wheel(s);
}

function on_paint(gr) {
panel.paint(gr);
images.paint(gr);

//_drawOverlay(gr, 0, panel.h - 190, panel.w, panel.h, 100);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 100);

text.paint(gr);

_drawImage(gr, albumart.img, 20, panel.h - _scale(130), 100, 100, image.crop);

buttons.paint(gr);
}

function on_playback_order_changed() {
buttons.update();
window.Repaint();
}

function on_playback_dynamic_info_track(type) {
if (type == 0) {
images.playback_new_track();
text.metadb_changed() ;
} else if (type == 1) albumart.metadb_changed();
}

function on_playback_new_track() {
panel.item_focus_change();
images.playback_new_track();
}

function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}

function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}

function on_playback_starting() {
buttons.update();
window.Repaint();
}

function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}

buttons.update();
window.Repaint();
}

function on_playback_time() {
images.playback_time();
text.playback_time();
window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
}

function on_playlist_items_added() {
text.refresh();
}

function on_playlist_items_removed() {
text.refresh();
}

function on_playlist_items_reordered() {
text.refresh();
}

function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}

function on_playlist_switch() {
on_item_focus_change();
}

function on_playlists_changed() {
text.refresh();
}


function on_size() {
panel.size();
images.w = panel.w;
images.h = panel.h;
text.size();
bottom_y = panel.h - _scale(36);
buttons.update();
}