Topic: Spider Monkey Panel (foo_spider_monkey_panel) (Read 20077 times)
0 Members and 1 Guest are viewing this topic.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Update: the above solution is okay if the objects are separate, but it gets buggy when they overlap.
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Unless I'm missing something, RepaintRect just clips the area that is currently drawn to the screen. So if I draw a rectangle from 0,0,100,100 to the gr buffer, and I'm only painting the region from (50,50 -> 100,100), the next time a full repaint is done, the rectangle will be completely drawn from 0,0 -> 100,100.

Also, it's my understanding that RepaintRect isn't something that causes a draw to happen immediately. It just specifies the region which will be drawn to the screen and that region is the union of the outermost extants of the region on the next draw cycle. So if I do RepaintRect(10,10,20,20) and then another RepaintRect(1000,1000,20,20) before the contents are actually drawn, when the drawcycle occurs it'll actually draw (10,10) -> (1020,1020). I'm assuming the underlying gdi stuff hasn't changed for Spidermonkey.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Unless I'm missing something, RepaintRect just clips the area that is currently drawn to the screen. So if I draw a rectangle from 0,0,100,100 to the gr buffer, and I'm only painting the region from (50,50 -> 100,100), the next time a full repaint is done, the rectangle will be completely drawn from 0,0 -> 100,100.

Yes, unless you do this:
Code: [Select]
`var myRegion = new PaintRegion(50, 50, 100, 100)function on_paint(gr){    myRegion.paint(gr);}function PaintRegion(x, y, w, h){    this.x = x;    this.y = y;    this.w = w;    this.h = h;    this.repainting = false;    this.repaint_done = false;    this.paint = (gr) => {        if (this.repainting) {            gr.FillSolidRect(0,0, window.Width, window.Height,0xFF000000);  // these are just examples,any other            gr.DrawEllipse(80, 30, 200, 200, 2, 0xFFFFFFFF)                 // GdiGraphics method goes here.            this.repaint_done = true;            this.repainting = false;        };        if (!this.repaint_done) {            this.repainting = true;            window.RepaintRect(this.x, this.y, this.w, this.h);            this.repaint_done = false;                    };    }}`

The full paint is done only if the repainting property is true, but this is set to false by default and it is not touched when a full paint is called. It is turned to true only for the RepaintRect method to reference it, and than back to false right after its execution. The repaint_done property works the other way round, in order to prevent a RepaintRect loop.
The above code works, but in my new project I built a system of nested objects, that pass the paint action (any action actually) on to their content, and that's where it gets tricky, but it's a very specific problem for that script.

Anyway, I'd prefer, and I'm still looking for (I still did not look into the Catrox scripts!  ), an alternative method that doesn't use the on_paint() callback to trigger the RepaintRect() method, for obvious safety reasons, but also because it would probably work in my nested objects chain.

Also, it's my understanding that RepaintRect isn't something that causes a draw to happen immediately.

I'm not sure about that. From what I read in the docs, it behaves like the Repaint() method. Doesn't that call an immediate window repaint?
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Sorry, I just realized the last line of code which resets the repaint_done property to false, must not be in the conditional section, but right after:
Code: [Select]
`var myRegion = new PaintRegion(50, 50, 100, 100)function on_paint(gr){    myRegion.paint(gr);}function PaintRegion(x, y, w, h){    this.x = x;    this.y = y;    this.w = w;    this.h = h;    this.repainting = false;    this.repaint_done = false;    this.paint = (gr) => {        if (this.repainting) {            gr.FillSolidRect(0,0, window.Width, window.Height,0xFF000000);  // these are just examples,any other            gr.DrawEllipse(80, 30, 200, 200, 2, 0xFFFFFFFF)                 // GdiGraphics method goes here.            this.repaint_done = true;            this.repainting = false;        };        if (!this.repaint_done) {            this.repainting = true;            window.RepaintRect(this.x, this.y, this.w, this.h);             };       this.repaint_done = false;  // <---------    }}`

I don't really understand why, though. It seems that the RepaintRect method aborts the execution of the previously called on_paint() function that triggered it. Is that correct?
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

I don't really understand why, though. It seems that the RepaintRect method aborts the execution of the previously called on_paint() function that triggered it. Is that correct?

Alright, I think I understand now what @MordredKLB was telling me in his previous reply: the new paint event called by the RepaintRect() method is queued and executed only when the first paint event that triggered it is popped off the stack. Right?
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Alright, I think I understand now what @MordredKLB was telling me in his previous reply: the new paint event called by the RepaintRect() method is queued and executed only when the first paint event that triggered it is popped off the stack. Right?
Not exactly. Say you have a function that calls window.RepaintRect() twice in a row so that two buttons are repainted. It's my understanding that your on_paint method will only be called once the next time a WM_PAINT message is received by the foobar window, and that the cliprect for the area drawn will be the union of the exterior bounds (although that I'm less sure on).

Basically the Javascript is single-threaded, but the operating system isn't, and it queues up the areas that will be drawn.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

I finally found out how @TheQwertiest managed to solve the above issue in his CatRox theme. It's pretty straightforward actually, but it took me a few days because it was buried in thousands of code lines. So, for who's interested, here is a proper and more reasonable way than the one I came up with:

Code: [Select]
`var myRegion = new PaintRegion(100, 100, 200, 200)function on_paint(gr){    myRegion.paint(gr);}function PaintRegion(x, y, w, h){    this.x = x;    this.y = y;    this.w = w;    this.h = h;    this.paint = (gr) => {        var clipImg = gdi.CreateImage(this.w, this.h)        var grClip = clipImg.GetGraphics();        grClip.DrawEllipse(100, 50, 200, 200, 2, 0xFF000000)        clipImg.ReleaseGraphics(grClip);        gr.DrawImage(clipImg, this.x, this.y, this.w, this.h, 0, 0, this.w, this.h)    }}`
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Hello,

I have a question about on_size event. It has two parameters and documentation indicates that it corresponds to panel size.
I have tested that and saw that it correspond to window size.
I did not do the test with JScript panel, but I would like to know if it the same with the JScript Panel ?

Kind regards,

Re: Spider Monkey Panel (foo_spider_monkey_panel)

I have a question about on_size event. It has two parameters and documentation indicates that it corresponds to panel size.
I have tested that and saw that it correspond to window size.
That is impossible - SMP currently does not have a way to find the size of fb2k window. on_size arguments ARE panel width and height respectively.
You can easily verify this by creating a layout with two resizeable SMP panels (e.g. in DUI) and replacing the following line in the default script:
Code: [Select]
`gr.GdiDrawText(g_text, g_font, g_hot ? g_textcolour_hl : g_textcolour, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);`
with
Code: [Select]
`gr.GdiDrawText(`width: \${ww}, height \${wh}`, g_font, g_hot ? g_textcolour_hl : g_textcolour, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);`
Each panel will display it's size, which will change when they are resized.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Thanks for you response.
I was already displaying width and height but is was the same for my for 4 panels.
After more testing, I decided to add a MinWidth and MaxWidth, idem with height. And it is not respected. I use CUI with horizontal and vertical splitter.
The thing is that a panel stretch to the size of the largest panel inside a column, even if larger than MaxWidth.
When you say 'resizeable SMP panel', do you mean that we can have them not resizeable?

Re: Spider Monkey Panel (foo_spider_monkey_panel)

After more testing, I decided to add a MinWidth and MaxWidth, idem with height. And it is not respected. I use CUI with horizontal and vertical splitter.
MinWidth and MaxWidth properties (and window dimensions adjustment functionality) are not provided by SMP component, but rather by foo_ui_hacks =)
You can use the following code though from my CaTRoX theme though: https://github.com/TheQwertiest/CaTRoX_QWR/blob/61eecfa4159e3714d58f53ae942d5f1861e83fb2/theme/Scripts/Panel_Menu.js#L1018
Note, that you have to change assignments like MinWidth=True to MinWidth.Enabled=True.

When you say 'resizeable SMP panel', do you mean that we can have them not resizeable
I mean smth like parent vertical/horizontal splitter in DUI/CUI that allows for panel size adjustment. There are components that provide panels for CUI/DUI, which allow having other panels inside, but don't allow their resizing.

[EDIT] Disregard this, I can't read...

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Hi,

Does someone knows a trick to trigger a new evaluation of panel stack splitter scripts, from a SMP panel ?
There is the play/pause way, using the function below, because the PerTrack scripts of a PSS panel are evaluate on playback changes, but this creates some sound glitches, especially while playing live streams (because foobar can't buffer the stream when this is a live stream, it need to synchronize with the stream after a pause command)

Code: [Select]
`function RefreshPSS() {	if (fb.IsPlaying || fb.IsPaused) {		fb.PlayOrPause();		fb.PlayOrPause();	}	else {		fb.Play();fb.Stop();	}}`

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Hi,

Does someone knows a trick to trigger a new evaluation of panel stack splitter scripts, from a SMP panel ?
There is the play/pause way, using the function below, because the PerTrack scripts of a PSS panel are evaluate on playback changes, but this creates some sound glitches, especially while playing live streams (because foobar can't buffer the stream when this is a live stream, it need to synchronize with the stream after a pause command)

Code: [Select]
`function RefreshPSS() {	if (fb.IsPlaying || fb.IsPaused) {		fb.PlayOrPause();		fb.PlayOrPause();	}	else {		fb.Play();fb.Stop();	}}`

There is a trick you can try.

You will need to enable is the PSS panels "Evaluate scripts when track info is modified"

Code: [Select]
`function RefreshPSS() {let handle_list = plman.GetPlaylistItems(plman.ActivePlaylist);handle_list.RefreshStats();}`

There is a limitation:  Your handle list cannot be empty.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Ah yes, thanks! By combining both methods, you end up with something which work all the time:
Code: [Select]
`function RefreshPSS() {	if (fb.IsPlaying || fb.IsPaused) {		let handle_list = new FbMetadbHandleList(fb.GetNowPlaying());		handle_list.RefreshStats();	}		else {		fb.Play();fb.Stop();	}	}`

Important point:
"Evaluate scripts when track info is modified" needs to be enabled AND on the script tab of the PSS panel, "Titleformat mode on startup" needs to be on "now playing"

Re: Spider Monkey Panel (foo_spider_monkey_panel)

@cerbaire , I have to apologize: my last answer was answering the wrong question, since I've misread `MinWidth` (present in SMP/JSP) as `MinSize.Width` (foo_ui_hacks)... But you've probably read the (correct) answer by marc2003 by now, so I won't repeat it here... :shame_on_me:

Re: Spider Monkey Panel (foo_spider_monkey_panel)

@cerbaire , I have to apologize: my last answer was answering the wrong question, since I've misread `MinWidth` (present in SMP/JSP) as `MinSize.Width` (foo_ui_hacks)... But you've probably read the (correct) answer by marc2003 by now, so I won't repeat it here... :shame_on_me:
Thanks TheQwertiest, yes I saw marc2k3 response on GitHub.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

How can I use foobar2000 code with Spider Monkey Panel code?

This is what I want to do:
Code: [Select]
`\$if(%ispaused%,❚❚,▶)‌‌%title%%playback_time% / %length%`

This is my Spider Monkey Panel code so far:
Code: [Select]
`var font = gdi.Font("Segoe UI", 12, 0);function Color(r, g, b) {	return 0xFF000000 | r << 16 | g << 8 | b;}function on_paint(gr) {    gr.FillSolidRect(0, 0, 1000, 1000, Color(240,240,240));    gr.GdiDrawText("Playing/Paused - Track Title", font, Color(0,0,0), 5, 1, 226, 1000);    gr.GdiDrawText("00:00 / 00:00", font, Color(0,0,0), 237, 1, 1000, 1000);}`

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Hi everyone,

Does anyone ever hear of a SMP (or marc2003's jscript) code for an library search toolbar (like the Quicksearch toobar component for example?)
There used to be a WSH toolbar in one of Br3tt's theme (xchange I think) but it's kind of old and I'm not sure I will be able to port it to SMP.

Decalicatan Decalicatan

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Hi everyone,

Does anyone ever hear of a SMP (or marc2003's jscript) code for an library search toolbar (like the Quicksearch toobar component for example?)
There used to be a WSH toolbar in one of Br3tt's theme (xchange I think) but it's kind of old and I'm not sure I will be able to port it to SMP.

Not sure it helps, but here is an adaptation of the script I wrote for my config. It was not meant to work in a component-like fashion, so you might have to edit the code here and there (no window properties, sorry). My coding is much more naive than marc2003's or Br3tt's, but perhaps this makes it easier to grasp and modify.
For reasons I don't understand, it only works with columns ui, maybe some more advanced coder can figure out why,
I still didn't find the time to handle the typing animation when the text's length exceeds that of the width of the panel, so make sure the panel is wide enough for your average search strings.
Search results are displayed in a playlist called "Search results [your search string]", which is overwritten at every new search.

Code: [Select]
`"use strict";include(fb.ComponentPath + "docs\\flags.js");include(fb.ComponentPath + "docs\\helpers.js");include(fb.ComponentPath + "samples\\complete\\js\\lodash.min.js");var font_height = 18;var fontcolor = colours.White;var text = "";var cursor = 0;var set_cursor = false;var selection_lx = 0;var selection_rx = 0;var selection = "";var mouse_lbtn_down = false;var count = 0;var timerID;var timer = false;var edit = false; var writing = false;var ctrla = false;var dblclk = false;var dblclk_lx = 0;var dblclk_rx = 0;var mouse_lbtn_down_x = 0;var mouse_move_x = 0;var obj = new ActiveXObject("htmlfile");var autocomplete = new Array();var history = new Array();history.push(text);var currentState = 0;var ww = 0;var wh = 0;var text_x = 0;function on_size(){    ww = window.Width;    wh = window.Height;  }function on_paint(gr){        var iconfont = "Segoe mdl2 assets";        var font = gdi.Font(iconfont, font_height, 0);    var selection_color = colours.Black;    var icon = String.fromCharCode(57492);     var textheigth = gr.CalcTextHeight(icon, font);      text_x = wh + gr.CalcTextWidth(" ", font);        dblclk_lx = Math.max(text.slice(0, getPos(mouse_lbtn_down_x, text, font, gr)).toString().lastIndexOf(" ") + 1, 0);    dblclk_rx = getPos(mouse_lbtn_down_x, text, font, gr) + (text + " ").slice(getPos(mouse_lbtn_down_x, text, font, gr)).toString().indexOf(" ") + 1;    selection_lx = getPos(Math.min(mouse_lbtn_down_x, mouse_move_x), text, font, gr);    selection_rx = getPos(Math.max(mouse_lbtn_down_x, mouse_move_x), text, font, gr);    if (dblclk) selection_lx = Math.min(selection_lx, dblclk_lx);    if (dblclk) selection_rx = Math.max(selection_rx, dblclk_rx);    if (ctrla) selection_lx = 0;    if (ctrla) selection_rx = text.length;            var selection_x = text_x + (gr.CalcTextWidth(text.slice(0, selection_lx), font));    var selection_w = gr.CalcTextWidth(text.slice(selection_lx, selection_rx), font);    var text1 = text.slice(0, selection_lx);    var text2 = text.slice(selection_lx, selection_rx);    var text3 = text.slice(selection_rx);    if (set_cursor) {        cursor = getPos(mouse_lbtn_down_x, text, font, gr);        set_cursor = false;    }    selection = text2;    var cursor_x = text_x + gr.CalcTextWidth(text.slice(0, cursor), font);         gr.DrawRect(0, 0, ww - 1, wh - 1, 1, fontcolor);     gr.GdiDrawText(icon, font, fontcolor, 0, 0, wh, wh, DT_CENTER | DT_VCENTER | DT_SINGLELINE);      gr.FillSolidRect(selection_x, (wh - textheigth)/2, selection_w, textheigth, colours.Gray);           gr.GdiDrawText(text1, font, fontcolor, text_x, 0, gr.CalcTextWidth(text1, font), wh, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);    gr.GdiDrawText(text2, font, selection_color, text_x + gr.CalcTextWidth(text1, font), 0, gr.CalcTextWidth(text2, font), wh, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);    gr.GdiDrawText(text3, font, fontcolor, text_x + gr.CalcTextWidth(text1, font) + gr.CalcTextWidth(text2, font), 0, gr.CalcTextWidth(text3, font), wh, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);    if (selection_w == 0 && edit && count%2 == 1) gr.DrawLine(cursor_x, (wh - textheigth)/2, cursor_x, (wh + textheigth)/2, 1, fontcolor);    if (text == "" && !edit) gr.GdiDrawText("Search", font, fontcolor, text_x, 0, ww - text_x, wh, DT_LEFT | DT_VCENTER | DT_SINGLELINE);    writing = false;}function on_mouse_move(x, y){    window.SetCursor(IDC_IBEAM);    if (mouse_lbtn_down){        mouse_move_x = x;        window.Repaint();	}}function on_mouse_lbtn_down(x, y){    edit = true;    mouse_lbtn_down = true;    mouse_lbtn_down_x = x;    set_cursor = true;    unselect();    window.Repaint();}function on_mouse_lbtn_up(x, y){    mouse_lbtn_down = false;}function on_mouse_lbtn_dblclk(x, y){    mouse_lbtn_down = true;    mouse_lbtn_down_x = x;    dblclk = true;        window.Repaint();}        function on_mouse_leave(){    mouse_lbtn_down = false;    edit = writing;}function on_focus(is_focused){    if (is_focused){        timerID = window.SetInterval(function() {            count++;            window.Repaint();            }, 500);            timer = true    } else {        window.ClearInterval(timerID);        timer = false;        count = 0;        window.Repaint();    }}function on_char(code){    if (code > 31) {        if (selection_lx < selection_rx){            text = text.slice(0, selection_lx) + String.fromCharCode(code) + text.slice(selection_rx);            cursor = selection_lx + 1;            unselect();        } else {                        text = text.slice(0, cursor) + String.fromCharCode(code) + text.slice(cursor);            cursor = cursor + 1;        }        newState(text);        var autocompleteMenu = window.CreatePopupMenu();        var filtered_list = _.uniq(autocomplete, true).filter(filterAutocomplete);        for (var i = 0; i < filtered_list.length; i++){            autocompleteMenu.AppendMenuItem(MF_STRING, i + 1, filtered_list[i]);        }        var ret = autocompleteMenu.TrackPopupMenu(text_x, wh, 0);        if (ret > 0){            text = filtered_list[ret - 1];            cursor = text.length;        }        writing = true;        window.Repaint();    }}        function on_key_down(vkey){    var ShiftKeyPressed = utils.IsKeyPressed(VK_SHIFT);    var ControlKeyPressed = utils.IsKeyPressed(VK_CONTROL);    if (!ControlKeyPressed){               switch (vkey){                        case 8: //backspace                        if (selection_lx < selection_rx){                text = text.slice(0, selection_lx) + text.slice(selection_rx);                cursor = selection_lx;                unselect();            } else {                text = text.slice(0, Math.max(cursor - 1, 0)) + text.slice(cursor);                cursor = Math.max(cursor - 1, 0);            }            newState(text);            break;                        case 13: //enter            search();            text = "";            cursor = 0;            history = [];            newState(text);            break;                        case 37: //left arrow            cursor = Math.max(cursor - 1, 0);            break;                        case 39: //right arrow            cursor = Math.min(cursor + 1, text.length);            break;                        case 46: //delete            if (selection_lx < selection_rx){                text = text.slice(0, selection_lx) + text.slice(selection_rx);                cursor = selection_lx;                unselect();            } else {                text = text.slice(0, cursor) + text.slice(cursor).slice(1);            }            newState(text);            break;        }    } else {        switch (vkey){            case 65: //ctrl + A            ctrla = true;            break;                        case 67: //ctrl + C            obj.parentWindow.clipboardData.setData("Text", selection);            break;                        case 86: //ctrl + V            var clipboard = obj.parentWindow.clipboardData.getData("Text") + "";            if (selection_lx < selection_rx){                text = text.slice(0, selection_lx) + clipboard + text.slice(selection_rx);            } else {                text = text.slice(0, cursor) + clipboard + text.slice(cursor);             }            cursor = selection_lx + clipboard.length;            unselect();             newState(text);                        break;                        case 88: //ctrl + X            obj.parentWindow.clipboardData.setData("Text", selection);            text = text.slice(0, selection_lx) + text.slice(selection_rx);            cursor = selection_lx;            unselect();            newState(text);            break;                        case 89: //ctrl + Y            currentState = Math.max(currentState - 1, 0);            text = history[currentState];            cursor = text.length;            break;                        case 90: //ctrl + Z            currentState = Math.min(currentState + 1, history.length - 1);            text = history[currentState];            cursor = text.length;            break;                 }    }    window.Repaint();}            function getPos(x, text, font, gr){    var pos;    for (var i = 0; i <= text.length; i++){        if (x < text_x + gr.CalcTextWidth(text.slice(0, i + 1), font)){            pos = i;            i = text.length + 1;        } else {            pos = text.length;        }    }    return pos;}	    function unselect(){    mouse_move_x = mouse_lbtn_down_x;    dblclk = false;    ctrla = false;}function newState(text){    history.slice(currentState);    history.unshift(text);    currentState = 0;}function search(){    autocomplete.push(text);    autocomplete.sort();        var SortOrder = "%album artist%|%release date%|%album%|%discnumber%|%set subtitle%|%tracknumber%|%path%";    try {        var queryItems = fb.GetQueryItems(fb.GetLibraryItems(), text);    }    catch(Error){        var queryItems = fb.CreateHandleList();    }        var index = -1;         for (var i = 0; i < plman.PlaylistCount; i++) {       if (plman.GetPlaylistName(i).indexOf("Search results [") == 0) index = i;    }    if (index > -1){        plman.RemovePlaylist(index);    } else {        index = plman.PlaylistCount;    }    plman.CreatePlaylist(index,"Search results [" + text + "]");    plman.InsertPlaylistItems(index, 0, queryItems);    plman.SortByFormat(index, SortOrder);      plman.ActivePlaylist = index;}function filterAutocomplete(value){    return value.indexOf(text) == 0;}`
I'm late

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Oh god I just figured out how to write my panel! Kind of like a short status bar:

Code: [Select]
`var font = gdi.Font("Segoe UI", 12, 0);var play_pause = fb.TitleFormat('\$if(%ispaused%,❚❚,▶)');var title = fb.TitleFormat('%title%');var time1 = fb.TitleFormat('%playback_time%');var time2 = fb.TitleFormat('%length%');function on_playback_pause() {  // + play    window.Repaint();}function on_playback_new_track() {    window.Repaint();}function on_playback_seek() {	window.Repaint();}function on_playback_time() {	window.Repaint();}function Color(r, g, b) {	return 0xFF000000 | r << 16 | g << 8 | b;}function on_paint(gr) {    gr.FillSolidRect(0, 0, 1000, 1000, Color(240,240,240));    gr.GdiDrawText(play_pause.Eval() + " " + title.Eval(), font, Color(0,0,0), 5, 1, 226, 1000);    gr.GdiDrawText(time1.Eval() + " / " + time2.Eval(), font, Color(0,0,0), 237, 1, 1000, 1000);}`

But does anyone know if there's a way to update just one string, and not the whole panel like window.Repaint(); does?

Re: Spider Monkey Panel (foo_spider_monkey_panel)

@spuuunit , you can use `RepaintRect(w,h)` instead of `Repaint()` if you want to redraw only part of the panel.

@CrowRabbit , TS typings would be nice, but I'm wary of the duplicated documentation: there is already a JSDoc version https://github.com/TheQwertiest/foo_spider_monkey_panel/blob/master/component/docs/js/foo_spider_monkey_panel.js , and it would be a pain to have to maintain the same docs in TS typings as well... (I mean method descriptions and stuff, I'm fine with maintaining the interface itself)

Re: Spider Monkey Panel (foo_spider_monkey_panel)

@spuuunit , you can use `RepaintRect(w,h)` instead of `Repaint()` if you want to redraw only part of the panel.

@CrowRabbit , TS typings would be nice, but I'm wary of the duplicated documentation: there is already a JSDoc version https://github.com/TheQwertiest/foo_spider_monkey_panel/blob/master/component/docs/js/foo_spider_monkey_panel.js , and it would be a pain to have to maintain the same docs in TS typings as well... (I mean method descriptions and stuff, I'm fine with maintaining the interface itself)

Thanks! But how exactly does that look like, is it like this: window.RepaintRect(0, 1000, 0, 1000); Does that cover the whole area? Because nothing is updating for me.

And another thing: The playback time that increases every second is what I want to update. Is it worth updating just that area all the time, rather than the whole panel, to save resources? Or does panel update affect resources so little that I shouldn't bother?

EDIT: This is my panel by the way. 4 tags and a background color: https://imgur.com/Pds7rqY

Re: Spider Monkey Panel (foo_spider_monkey_panel)

That's cause you are using it wrong =)
The method prototype is `window.RepaintRect(x,y,w,h)` and you calling it like `window.RepaintRect(x,w,y,h)`. So, in your case, the correct call would be `window.RepaintRect(0, 0, 1000, 1000)`.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Oh shit thanks! =) But does RepaintRect require less computer power than only Repaint? If so I'll go with that.