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: Spider Monkey Panel (foo_spider_monkey_panel) (Read 342193 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #175
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)

Reply #176
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)

Reply #177
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)

Reply #178
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)

Reply #179
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)

Reply #180
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)

Reply #181
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)

Reply #182
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)

Reply #183
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)

Reply #184
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)

Reply #185
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)

Reply #186
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)

Reply #187
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"

Change your function to
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)

Reply #188
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)

Reply #189
@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)

Reply #190
@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)

Reply #191
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)

Reply #192
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.

Thanks in advance
Decalicatan Decalicatan

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #193
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)

Reply #195
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)

Reply #196
@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)

Reply #197
@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)

Reply #198
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)

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