Example #1
0
void button_draw(BUTTON *b, int x, int y, int width, int height)
{
    // Button is hidden
    if (b->nodraw)
        return;

    // If `update` function is defined, call it on each draw
    if (b->update) {
        b->update(b);
    }

    // Ensure that font is set before calculating position and width.
    setfont(FONT_SELF_NAME);

    // Button contents color
    uint32_t color_text = b->mousedown ? b->ct2 : (b->mouseover ? b->ct2 : b->ct1);
    setcolor(color_text);

    int w = width;
    calculate_pos_and_width(b, &x, &w);

    // Button background color
    uint32_t color_background = b->mousedown ? b->c3 : (b->mouseover ? b->c2 : b->c1);

    if(b->bm) {
        drawalpha(b->bm, x, y, width, height, color_background);
    } else {
        draw_rect_fill(x, y, w, height, b->disabled ? (b->cd ? b->cd : b->cd) : color_background);

        //setfont(FONT_TEXT_LARGE);
        //setcolor(b->mouseover ? 0x222222 : 0x555555);
        //drawtext(x + 5, y, b->text, b->text_length);
    }

    if(b->bm2) {
        int bx = w / 2 - b->bw * SCALE / 2, by = height / 2 - b->bh * SCALE / 2;
        drawalpha(b->bm2, x + bx, y + by, b->bw * SCALE, b->bh * SCALE, color_text);
    }

    if(maybe_i18nal_string_is_valid(&b->button_text)) {
        if(b->bm) {
            while(w > width) {
                // The text didn't fit into the original width.
                // Fill the rest of the new width with the image
                // and hope for the best.
                drawalpha(b->bm, x - width + w, y, width, height, color_background);
                w -= width / 2 + 1;
            }
        }
        STRING* s = maybe_i18nal_string_get(&b->button_text);
        drawtext(x + 3 * SCALE, y + SCALE, s->str, s->length);
    }
}
Example #2
0
File: mmenu.c Project: Ansa89/uTox
// Function called once the user changes its status in the MessagingMenu
static void status_changed(MessagingMenuApp *mmapp_, gint status, gpointer user_data)
{
    switch(status) {
        case MESSAGING_MENU_STATUS_AVAILABLE:
            self.status = 0;
            tox_postmessage(TOX_SETSTATUS, 0, 0, NULL);
            break;

        case MESSAGING_MENU_STATUS_AWAY:
            self.status = 1;
            tox_postmessage(TOX_SETSTATUS, 1, 0, NULL);
            break;

        case MESSAGING_MENU_STATUS_BUSY:
            self.status = 2;
            tox_postmessage(TOX_SETSTATUS, 2, 0, NULL);
            break;

        default:
            self.status = 1;
            tox_postmessage(TOX_SETSTATUS, 1, 0, NULL);
            break;
    }

    drawalpha(BM_ONLINE + status, SELF_STATUS_X + BM_STATUSAREA_WIDTH / 2 - BM_STATUS_WIDTH / 2, SELF_STATUS_Y + BM_STATUSAREA_HEIGHT / 2 - BM_STATUS_WIDTH / 2, BM_STATUS_WIDTH, BM_STATUS_WIDTH, status_color[status]);

}
Example #3
0
void button_draw(BUTTON *b, int x, int y, int width, int height)
{
    if(b->nodraw) {
        return;
    }

    if(b->updatecolor) {
        b->updatecolor(b);
    }

    // Ensure that font is set before calculating position and width.
    setfont(FONT_SELF_NAME);
    setcolor(WHITE);

    int w = width;
    calculate_pos_and_width(b, &x, &w);

    uint32_t color = b->mousedown ? b->c3 : (b->mouseover ? b->c2 : b->c1);
    if(b->bm) {
        drawalpha(b->bm, x, y, width, height, color);
    } else {
        drawrectw(x, y, w, height, b->disabled ? LIST_MAIN : color);

        //setfont(FONT_TEXT_LARGE);
        //setcolor(b->mouseover ? 0x222222 : 0x555555);
        //drawtext(x + 5, y, b->text, b->text_length);
    }

    if(b->bm2) {
        int bx = w / 2 - b->bw * SCALE / 2, by = height / 2 - b->bh * SCALE / 2;
        drawalpha(b->bm2, x + bx, y + by, b->bw * SCALE, b->bh * SCALE, WHITE);
    }

    if(maybe_i18nal_string_is_valid(&b->button_text)) {
        if(b->bm) {
            while(w > width) {
                // The text didn't fit into the original width.
                // Fill the rest of the new width with the image
                // and hope for the best.
                drawalpha(b->bm, x - width + w, y, width, height, color);
                w -= width / 2 + 1;
            }
        }
        STRING* s = maybe_i18nal_string_get(&b->button_text);
        drawtext(x + 3 * SCALE, y + SCALE, s->str, s->length);
    }
}
Example #4
0
File: ui.c Project: notadecent/uTox
static void drawfriend(int x, int y, int w, int height)
{
    FRIEND *f = sitem->data;

    drawalpha(BM_CONTACT, LIST_RIGHT + SCALE * 5, SCALE * 5, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, LIST_MAIN);

    setcolor(C_TITLE);
    setfont(FONT_TITLE);
    drawtextrange(LIST_RIGHT + 30 * SCALE, width - 62 * SCALE, 9 * SCALE, f->name, f->name_length);

    setcolor(LIST_MAIN);
    setfont(FONT_STATUS);
    drawtextrange(LIST_RIGHT + 30 * SCALE, width - 62 * SCALE, 16 * SCALE, f->status_message, f->status_length);

    if(!f->calling) {
        button_call.c1 = C_GREEN;
        button_call.c2 = C_GREEN_LIGHT;
        button_call.c3 = C_GREEN_LIGHT;
        button_video.c1 = C_GREEN;
        button_video.c2 = C_GREEN_LIGHT;
        button_video.c3 = C_GREEN_LIGHT;

        return;
    }

    button_call.c1 = C_GRAY;
    button_call.c2 = C_GRAY;
    button_call.c3 = C_GRAY;
    button_video.c1 = C_GRAY;
    button_video.c2 = C_GRAY;
    button_video.c3 = C_GRAY;

    BUTTON *b;
    if(f->calling & 4) {
        b = &button_video;
    } else {
        b = &button_call;
    }

    switch(f->calling & 3) {
    case CALL_INVITED: {
        b->c1 = C_YELLOW;
        b->c2 = C_YELLOW_LIGHT;
        break;
    }

    case CALL_RINGING: {
        b->c1 = C_GRAY;
        b->c2 = C_GRAY;
        break;
    }

    case CALL_OK: {
        b->c1 = C_RED;
        b->c2 = C_RED_LIGHT;
        break;
    }
    }
}
Example #5
0
File: ui.c Project: draziw-/uTox
/* Top left self interface Avatar, name, statusmsg, status icon */
static void drawself(void)
{
    //40x40 self icon at 10,10
    setcolor(button_name.mouseover ? C_STATUS : WHITE);
    setfont(FONT_SELF_NAME);
    drawtextrange(SELF_NAME_X, SELF_STATUS_X, SELF_NAME_Y, self.name, self.name_length);

    setcolor(button_statusmsg.mouseover ? C_GRAY2 : C_STATUS);
    setfont(FONT_STATUS);
    drawtextrange(SELF_MSG_X, SELF_STATUS_X, SELF_MSG_Y, self.statusmsg, self.statusmsg_length);

    drawalpha(BM_CONTACT, SELF_AVATAR_X, SELF_AVATAR_Y, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, WHITE);

    drawalpha(BM_STATUSAREA, SELF_STATUS_X, SELF_STATUS_Y, BM_STATUSAREA_WIDTH, BM_STATUSAREA_HEIGHT, button_status.mouseover ? LIST_HIGHLIGHT : LIST_MAIN);

    uint8_t status = tox_connected ? self.status : 3;
    drawalpha(BM_ONLINE + status, SELF_STATUS_X + BM_STATUSAREA_WIDTH / 2 - BM_STATUS_WIDTH / 2, SELF_STATUS_Y + BM_STATUSAREA_HEIGHT / 2 - BM_STATUS_WIDTH / 2, BM_STATUS_WIDTH, BM_STATUS_WIDTH, status_color[status]);
}
Example #6
0
void button_draw(BUTTON *b, int x, int y, int width, int height)
{
    uint32_t color = b->mousedown ? b->c3 : (b->mouseover ? b->c2 : b->c1);
    if(b->bm) {
        drawalpha(b->bm, x, y, width, height, color);
    } else {
        drawrectw(x, y, width, height, b->disabled ? LIST_MAIN : color);

        //setfont(FONT_TEXT_LARGE);
        //setcolor(b->mouseover ? 0x222222 : 0x555555);
        //drawtext(x + 5, y, b->text, b->text_length);
    }

    if(b->bm2) {
        int bx = width / 2 - b->bw / 2, by = height / 2 - b->bh / 2;
        drawalpha(b->bm2, x + bx, y + by, b->bw, b->bh, WHITE);
    }
}
Example #7
0
File: ui.c Project: draziw-/uTox
static void drawgroup(int UNUSED(x), int UNUSED(y), int UNUSED(w), int UNUSED(height))
{
    GROUPCHAT *g = sitem->data;

    drawalpha(BM_GROUP, LIST_RIGHT + SCALE * 5, SCALE * 5, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, LIST_MAIN);

    setcolor(C_TITLE);
    setfont(FONT_TITLE);
    drawtext(LIST_RIGHT + 30 * SCALE, 1 * SCALE, g->name, g->name_length);

    setcolor(LIST_MAIN);
    setfont(FONT_STATUS);
    drawtext(LIST_RIGHT + 30 * SCALE, 8 * SCALE, g->topic, g->topic_length);

    setcolor(GRAY(150));
    uint32_t i = 0;
    int k = LIST_RIGHT + 30 * SCALE;

    uint64_t time = get_time();

    unsigned int pos_y = 15;
    while(i < g->peers)
    {
        uint8_t *name = g->peername[i];
        if(name)
        {
            uint8_t buf[134];
            memcpy(buf, name + 1, name[0]);
            memcpy(buf + name[0], ", ", 2);

            int w = textwidth(buf, name[0] + 2);
            if (i == g->our_peer_number) {
                setcolor(C_GREEN);
            } else if (time - g->last_recv_audio[i] <= (uint64_t)1 * 1000 * 1000 * 1000) {
                setcolor(C_RED);
            } else {
                setcolor(GRAY(150));
            }

            if(k + w >= (utox_window_width - 32 * SCALE)) {
                if (pos_y == 15) {
                    pos_y += 6;
                    k = LIST_RIGHT + 30 * SCALE;
                } else {
                    drawtext(k, pos_y * SCALE, (uint8_t*)"...", 3);
                    break;
                }
            }

            drawtext(k, pos_y * SCALE, buf, name[0] + 2);

            k += w;
        }
        i++;
    }
}
Example #8
0
static void draw_group(int x, int UNUSED(y), int UNUSED(w), int UNUSED(height)) {
    GROUPCHAT *g = flist_get_groupchat();
    if (!g) {
        LOG_ERR("Group", "Could not get selected groupchat.");
        return;
    }

    drawalpha(BM_GROUP, x + SCALE(10), SCALE(10), BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, COLOR_MAIN_TEXT);

    setcolor(COLOR_MAIN_TEXT);
    setfont(FONT_TITLE);
    drawtextrange(x + SCALE(60), settings.window_width - SCALE(64), SCALE(2), g->name, g->name_length);

    setcolor(COLOR_MAIN_TEXT_SUBTEXT);
    setfont(FONT_STATUS);
    drawtextrange(x + SCALE(60), settings.window_width - SCALE(64), SCALE(16), g->topic, g->topic_length);

    uint32_t i = 0;
    unsigned k = x + SCALE(60);

    unsigned int pos_y = 15;
    while (i < g->peer_count) {
        GROUP_PEER *peer = g->peer[i];

        if (peer && peer->name_length) {
            char buf[TOX_MAX_NAME_LENGTH];
            int  text_length = snprintf((char *)buf, TOX_MAX_NAME_LENGTH, "%.*s, ", (int)peer->name_length, peer->name);

            unsigned w = textwidth(buf, text_length);
            if (peer->name_color) {
                setcolor(peer->name_color);
            } else {
                setcolor(COLOR_GROUP_PEER);
            }

            if (k + w >= (settings.window_width - SCALE(64))) {
                if (pos_y == 15) {
                    pos_y += 6;
                    k = x + SCALE(60);
                } else {
                    drawtext(k, SCALE(pos_y * 2), "...", 3);
                    break;
                }
            }

            drawtext(k, SCALE(pos_y * 2), buf, text_length);

            k += w;
        }
        i++;
    }
}
Example #9
0
File: ui.c Project: draziw-/uTox
/* Header for friend chat window */
static void drawfriend(int UNUSED(x), int UNUSED(y), int UNUSED(w), int UNUSED(height))
{
    FRIEND *f = sitem->data;

    drawalpha(BM_CONTACT, LIST_RIGHT + SCALE * 5, SCALE * 5, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, LIST_MAIN);

    setcolor(C_TITLE);
    setfont(FONT_TITLE);
    drawtextrange(LIST_RIGHT + 30 * SCALE, utox_window_width - 92 * SCALE, 9 * SCALE, f->name, f->name_length);

    setcolor(LIST_MAIN);
    setfont(FONT_STATUS);
    drawtextrange(LIST_RIGHT + 30 * SCALE, utox_window_width - 92 * SCALE, 16 * SCALE, f->status_message, f->status_length);
}
Example #10
0
void scroll_draw(SCROLLABLE *s, int x, int y, int width, int height) {
    uint32_t c            = s->content_height;
    uint32_t h            = height, m, dy;
    uint32_t scroll_width = 0;
    if (s->small) {
        scroll_width = SCROLL_WIDTH / 2;
    } else {
        scroll_width = SCROLL_WIDTH;
    }

    if (h >= c) {
        // If h(eight) > c(ontent height), don't draw anything.
        return;
    } else {
        m        = (h * h) / c;
        double d = (h - m);
        dy       = (s->d * d) + 0.5;
    }

    y += dy;
    x += s->x;

    if (!s->left) {
        x += width - scroll_width;
    }

    drawalpha(s->small ? BM_SCROLLHALFTOP_SMALL : BM_SCROLLHALFTOP, x, y, scroll_width, scroll_width / 2, s->color);

    y += scroll_width / 2;
    int y2 = y + m - scroll_width;
    if (scroll_width > m) {
        y2 = y;
    }
    drawrect(x, y, x + scroll_width, y2, s->color);

    drawalpha(s->small ? BM_SCROLLHALFBOT_SMALL : BM_SCROLLHALFBOT, x, y2, scroll_width, scroll_width / 2, s->color);
}
Example #11
0
File: ui.c Project: Mirovinger/uTox
static void drawgroup(int UNUSED(x), int UNUSED(y), int UNUSED(w), int UNUSED(height))
{
    GROUPCHAT *g = sitem->data;

    drawalpha(BM_GROUP, LIST_RIGHT + SCALE * 5, SCALE * 5, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, LIST_MAIN);

    setcolor(C_TITLE);
    setfont(FONT_TITLE);
    drawtext(LIST_RIGHT + 30 * SCALE, 5 * SCALE, g->name, g->name_length);

    setcolor(LIST_MAIN);
    setfont(FONT_STATUS);
    drawtext(LIST_RIGHT + 30 * SCALE, 12 * SCALE, g->topic, g->topic_length);


    setcolor(GRAY(150));
    uint32_t i = 0, j = 0;
    int k = LIST_RIGHT + 30 * SCALE;
    while(i < g->peers)
    {
        uint8_t *name = g->peername[j];
        if(name)
        {
            uint8_t buf[134];
            memcpy(buf, name + 1, name[0]);
            memcpy(buf + name[0], ", ", 2);

            int w = textwidth(buf, name[0] + 2);
            if(k + w >= width) {
                drawtext(k, 18 * SCALE, (uint8_t*)"...", 3);
                break;
            }

            drawtext(k, 18 * SCALE, buf, name[0] + 2);

            k += w;
            i++;
        }
        j++;
    }
}
Example #12
0
File: list.c Project: PKRoma/uTox
static void drawitem(ITEM *i, int UNUSED(x), int y)
{
    drawitembox(i, y);
    switch(i->item) {
    case ITEM_FRIEND: {
        FRIEND *f = i->data;

        // draw avatar or default image
        if (friend_has_avatar(f)) {
            draw_avatar_image(f->avatar.image, LIST_AVATAR_X, y + LIST_AVATAR_Y, f->avatar.width, f->avatar.height, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH);
        } else {
            drawalpha(BM_CONTACT, LIST_AVATAR_X, y + LIST_AVATAR_Y, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, (selected_item == i) ? COLOR_MAIN_TEXT : COLOR_LIST_TEXT);
        }

        if(f->alias){
            drawname(i, y, f->alias, f->status_message, f->alias_length, f->status_length, 0, 0);
        } else {
            drawname(i, y, f->name, f->status_message, f->name_length, f->status_length, 0, 0);
        }

        uint8_t status = f->online ? f->status : 3;
        drawalpha(BM_ONLINE + status, LIST_RIGHT - SCALE * 12, y + ITEM_HEIGHT / 2 - BM_STATUS_WIDTH / 2, BM_STATUS_WIDTH, BM_STATUS_WIDTH, status_color[status]);
        if(f->notify) {
            drawalpha(BM_STATUS_NOTIFY, LIST_RIGHT - SCALE * 13, y + ITEM_HEIGHT / 2 - BM_STATUS_NOTIFY_WIDTH / 2, BM_STATUS_NOTIFY_WIDTH, BM_STATUS_NOTIFY_WIDTH, status_color[status]);
        }
        // tooltip_new(utf8tonative(snprint_t(f->name, sizeof(char_t)*8));
        break;
    }

    case ITEM_GROUP: {
        GROUPCHAT *g = i->data;
        drawalpha(BM_GROUP, LIST_AVATAR_X, y + LIST_AVATAR_Y, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, (selected_item == i) ? COLOR_MAIN_TEXT : COLOR_LIST_TEXT);
        _Bool color_overide = 0;
        uint32_t color = 0;

        if (g->muted) {
            color_overide = 1;
            color = COLOR_GROUP_MUTED;
        } else {
            uint64_t time = get_time();
            unsigned int j;
            for (j = 0; j < g->peers; ++j) {
                if (time - g->last_recv_audio[j] <= (uint64_t)1 * 1000 * 1000 * 1000) {
                    color_overide = 1;
                    color = COLOR_GROUP_AUDIO;
                    break;
                }
            }
        }

        drawname(i, y, g->name, g->topic, g->name_length, g->topic_length, color_overide, color);
        break;
    }

    case ITEM_FRIEND_ADD: {
        FRIENDREQ *f = i->data;

        char_t name[TOX_FRIEND_ADDRESS_SIZE * 2];
        id_to_string(name, f->id);

        drawalpha(BM_CONTACT, LIST_AVATAR_X, y + LIST_AVATAR_Y, BM_CONTACT_WIDTH, BM_CONTACT_WIDTH, (selected_item == i) ? COLOR_MAIN_TEXT : COLOR_LIST_TEXT);
        drawname(i, y, name, f->msg, sizeof(name), f->length, 0, 0);
        break;
    }
    }
}
Example #13
0
/** Formats all messages from self and friends, and then call draw functions
 * to write them to the UI.
 *
 * accepts: messages struct *pointer, int x,y positions, int width,height
 */
void messages_draw(MESSAGES *m, int x, int y, int width, int height)
{

    // Do not draw author name next to every message
    uint8_t lastauthor = 0xFF;

    // Message iterator
    void **p = m->data->data;
    MSG_IDX i, n = m->data->n;

    // Go through messages
    for(i = 0; i != n; i++) {
        MESSAGE *msg = *p++;

        // Empty message
        if(msg->height == 0) {
            return;
        }

        //! NOTE: should not be constant 0
        if(y + msg->height <= 0) {
            y += msg->height;
            continue;
        }

        //! NOTE: should not be constant 100
        if(y >= height + 50 * SCALE) {
            break;
        }

        // Draw timestamps
        {
            char timestr[6];
            STRING_IDX len;
            len = snprintf(timestr, sizeof(timestr), "%u:%.2u", msg->time / 60, msg->time % 60);
            if (len >= sizeof(timestr)) {
                len = sizeof(timestr) - 1;
            }

            setcolor(COLOR_MAIN_SUBTEXT);
            setfont(FONT_MISC);
            drawtext(x + width - TIME_WIDTH, y, (char_t*)timestr, len);
        }

        // Draw the names for groups or friends
        if(m->type) {
            // Group message authors are all the same colour
            setcolor(COLOR_MAIN_CHATTEXT);
            setfont(FONT_TEXT);
            drawtextwidth_right(x, MESSAGES_X - NAME_OFFSET, y, &msg->msg[msg->length] + 1, msg->msg[msg->length]);
        } else {
            FRIEND *f = &friend[m->data->id];

            // Always draw name next to action message
            if(msg->msg_type == MSG_TYPE_ACTION_TEXT)
                lastauthor = 0xFF;

            if(msg->author != lastauthor) {
                // Draw author name
                // If author is current user
                setfont(FONT_TEXT);
                if(msg->msg_type == MSG_TYPE_ACTION_TEXT)
                    setcolor(COLOR_MAIN_ACTIONTEXT);
                else
                    if(msg->author)
                        setcolor(COLOR_MAIN_SUBTEXT);
                    else
                        setcolor(COLOR_MAIN_CHATTEXT);
                if(msg->author)
                    drawtextwidth_right(x, MESSAGES_X - NAME_OFFSET, y, self.name, self.name_length);
                else
                    drawtextwidth_right(x, MESSAGES_X - NAME_OFFSET, y, f->name, f->name_length);
                lastauthor = msg->author;
            }
        }

        // Draw message contents
        switch(msg->msg_type) {
        case MSG_TYPE_TEXT:
        case MSG_TYPE_ACTION_TEXT: {
            // Normal message
            STRING_IDX h1 = STRING_IDX_MAX, h2 = STRING_IDX_MAX;
            if(i == m->data->istart) {
                h1 = m->data->start;
                h2 = ((i == m->data->iend) ? m->data->end : msg->length);
            } else if(i == m->data->iend) {
                h1 = 0;
                h2 = m->data->end;
            } else if(i > m->data->istart && i < m->data->iend) {
                h1 = 0;
                h2 = msg->length;
            }

            if((m->data->istart == m->data->iend && m->data->start == m->data->end) || h1 == h2) {
                h1 = STRING_IDX_MAX;
                h2 = STRING_IDX_MAX;
            }

            if(msg->author) {
                setcolor(COLOR_MAIN_SUBTEXT);
            } else {
                setcolor(COLOR_MAIN_CHATTEXT);
            }

            if (msg->msg_type == MSG_TYPE_ACTION_TEXT) {
                setcolor(COLOR_MAIN_ACTIONTEXT);
            }

            setfont(FONT_TEXT);
            int ny = drawtextmultiline(x + MESSAGES_X, x + width - TIME_WIDTH, y, y, y + msg->height, font_small_lineheight, msg->msg, msg->length, h1, h2 - h1, 1);
            if(ny < y || (uint32_t)(ny - y) + MESSAGES_SPACING != msg->height) {
                debug("error101 %u %u\n", ny -y, msg->height - MESSAGES_SPACING);
            }
            y = ny;

            break;
        }

        // Draw image
        case MSG_TYPE_IMAGE: {
            MSG_IMG *img = (void*)msg;
            int maxwidth = width - MESSAGES_X - TIME_WIDTH;
            draw_message_image(img->image, x + MESSAGES_X, y, img->w, img->h, maxwidth, img->zoom, img->position);
            y += (img->zoom || img->w <= maxwidth) ? img->h : img->h * maxwidth / img->w;
            break;
        }

        // Draw file transfer
        case MSG_TYPE_FILE: {
            MSG_FILE *file = (void*)msg;
            int dx = MESSAGES_X;
            /* Mouse Positions */
            _Bool mo = (m->iover == i);
            _Bool mouse_over = (mo && m->over) ? 1 : 0;
            _Bool mouse_tbtn = (mo && m->over == 1) ? 1 : 0;
            _Bool mouse_bbtn = (mo && m->over == 2) ? 1 : 0;

            /* Old var kept for bug hunting
            int xx = x + dx;
            int xxx = xx + BM_FTM_WIDTH + SCALE; */

            /* File transfer bar */
            int ftbar_x  = x + dx;
            int ftbar_y  = y;
            int ftbar_w  = BM_FT_WIDTH;
            int ftbar_sw = BM_FTM_WIDTH;
            int ftbar_h  = BM_FT_HEIGHT;
            /* Button Background */
            int btn_bg_x  = ftbar_x + BM_FTM_WIDTH + SCALE;
            int btn_bg_w  = BM_FTB_WIDTH;
            /* Button Background heights */
            int tbtn_bg_y = y;
            int bbtn_bg_y = y + BM_FTB_HEIGHT + SCALE * 2;
            int tbtn_bg_h  = BM_FTB_HEIGHT + SCALE;
            int bbtn_bg_h  = BM_FTB_HEIGHT;
            /* Top button info */
            int btnx    = ((x + dx) + BM_FTM_WIDTH + SCALE) + (BM_FTB_WIDTH - BM_FB_WIDTH) / 2;
            int tbtn_y    = y + SCALE * 4;
            int bbtn_y    = y + BM_FTB_HEIGHT + SCALE * 5;
            int btnw    = BM_FB_WIDTH;
            int btnh    = BM_FB_HEIGHT;

            char_t size[16];
            STRING_IDX sizelen = sprint_bytes(size, sizeof(size), file->size);
            uint64_t progress = file->progress;
            if(progress > file->size) {
                progress = file->size;
            }
            char_t size_text[16];
            STRING_IDX size_text_len = sprint_bytes(size_text, sizeof(size_text), file->speed);
            size_text[size_text_len++] = '/';
            size_text[size_text_len++] = 's';
            uint64_t etasec = 0;
            if(file->speed) {
                etasec = (file->size - progress) / file->speed;
            }

            char_t text2[16];
            STRING_IDX len2 = snprintf((char*)text2, sizeof(text2), "%us", (uint32_t)etasec);
            if (len2 >= sizeof(text2)) {
                len2 = sizeof(text2) - 1;
            }

            // progress rectangle
            uint32_t w = (file->size == 0) ? 0 : (progress * (uint64_t)106 * SCALE) / file->size;

            setfont(FONT_MISC);
            setcolor(COLOR_MAIN_BACKGROUND);

            switch (file->status){
            case FILE_TRANSFER_STATUS_COMPLETED: {
                /* If mouse over use hover color */
                setcolor((mouse_over) ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT);

                drawalpha(BM_FT, ftbar_x, ftbar_y, ftbar_w, ftbar_h, (mouse_over) ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND);
                drawalpha(BM_YES, btnx, tbtn_y, btnw, btnh, (mouse_over) ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT);
                if(file->inline_png){
                    drawstr(x + dx + 5 * SCALE, y + 17 * SCALE, CLICKTOSAVE);
                } else {
                    drawstr(x + dx + 5 * SCALE, y + 17 * SCALE, CLICKTOOPEN);
                }
                break;
            }
            case FILE_TRANSFER_STATUS_KILLED:{
                setcolor(COLOR_BUTTON_DANGER_TEXT);

                drawalpha(BM_FT, ftbar_x, ftbar_y, ftbar_w, ftbar_h, COLOR_BUTTON_DANGER_BACKGROUND);
                drawalpha(BM_NO, btnx, tbtn_y, btnw, btnh, COLOR_BUTTON_DANGER_TEXT);

                drawstr(x + dx + 5 * SCALE, y + 17 * SCALE, TRANSFER_CANCELLED);
                break;
            }
            case FILE_TRANSFER_STATUS_BROKEN: {
                setcolor(COLOR_BUTTON_DANGER_TEXT);

                drawalpha(BM_FT, ftbar_x, ftbar_y, ftbar_w, ftbar_h, COLOR_BUTTON_DANGER_BACKGROUND);
                drawalpha(BM_NO, btnx, tbtn_y, btnw, btnh, COLOR_BUTTON_DANGER_TEXT);

                drawstr(x + dx + 5 * SCALE, y + 17 * SCALE, TRANSFER_BROKEN);
                break;
            }
            case FILE_TRANSFER_STATUS_NONE: {
                /* ↑ used for incoming transfers */
                setcolor(COLOR_BUTTON_DISABLED_TRANSFER);

                drawalpha(BM_FTM, ftbar_x, ftbar_y, ftbar_sw, ftbar_h, COLOR_BUTTON_DISABLED_BACKGROUND);

                drawalpha(BM_FTB1, btn_bg_x, tbtn_bg_y, btn_bg_w, tbtn_bg_h, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                drawalpha(BM_NO, btnx, tbtn_y, btnw, btnh, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));

                drawalpha(BM_FTB2, btn_bg_x, bbtn_bg_y, btn_bg_w, bbtn_bg_h, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                drawalpha(BM_YES, btnx, bbtn_y, btnw, btnh, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));

                framerect((x + dx) + 5 * SCALE, y + 17 * SCALE, (x + dx) + 111 * SCALE, y + 24 * SCALE, COLOR_BUTTON_DISABLED_TRANSFER);
                drawrectw((x + dx) + 5 * SCALE, y + 17 * SCALE, w, 7 * SCALE, COLOR_BUTTON_DISABLED_TRANSFER);
                break;
            }
            case FILE_TRANSFER_STATUS_ACTIVE: {
                setcolor(COLOR_BUTTON_INPROGRESS_TEXT);

                drawalpha(BM_FTM, ftbar_x, ftbar_y, ftbar_sw, ftbar_h, COLOR_BUTTON_INPROGRESS_BACKGROUND);

                drawalpha(BM_FTB1, btn_bg_x, tbtn_bg_y, btn_bg_w, tbtn_bg_h, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                drawalpha(BM_NO, btnx, tbtn_y, btnw, btnh, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));

                drawalpha(BM_FTB2, btn_bg_x, bbtn_bg_y, btn_bg_w, bbtn_bg_h, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                drawalpha(BM_PAUSE, btnx, bbtn_y, btnw, btnh, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));

                drawtext(x + dx + 5 * SCALE + 53 * SCALE - textwidth(size_text, size_text_len) / 2, y + 10 * SCALE, size_text, size_text_len);
                drawtext(x + dx + 5 * SCALE + 106 * SCALE - textwidth(text2, len2), y + 10 * SCALE, text2, len2);

                framerect((x + dx) + 5 * SCALE, y + 17 * SCALE, (x + dx) + 111 * SCALE, y + 24 * SCALE, COLOR_BUTTON_INPROGRESS_TEXT);
                drawrectw((x + dx) + 5 * SCALE, y + 17 * SCALE, w, 7 * SCALE, COLOR_BUTTON_INPROGRESS_TEXT);
                break;
            }
            case FILE_TRANSFER_STATUS_PAUSED_US:
            case FILE_TRANSFER_STATUS_PAUSED_BOTH:
            case FILE_TRANSFER_STATUS_PAUSED_THEM: {
                setcolor(COLOR_BUTTON_DISABLED_TRANSFER);

                drawalpha(BM_FTM, ftbar_x, ftbar_y, ftbar_sw, ftbar_h, COLOR_BUTTON_DISABLED_BACKGROUND);

                drawalpha(BM_FTB1, btn_bg_x, tbtn_bg_y, btn_bg_w, tbtn_bg_h, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                drawalpha(BM_NO, btnx, tbtn_y, btnw, btnh, (mouse_tbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));

                if(file->status <= FILE_TRANSFER_STATUS_PAUSED_BOTH){
                    /* Paused by at least us */
                    drawalpha(BM_FTB2, btn_bg_x, bbtn_bg_y, btn_bg_w, bbtn_bg_h, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_BACKGROUND : COLOR_BUTTON_SUCCESS_BACKGROUND));
                    drawalpha(BM_RESUME, btnx, bbtn_y, btnw, btnh, (mouse_bbtn ? COLOR_BUTTON_SUCCESS_HOVER_TEXT : COLOR_BUTTON_SUCCESS_TEXT));
                } else {
                    /* Paused only by them */
                    drawalpha(BM_FTB2, btn_bg_x, bbtn_bg_y, btn_bg_w, bbtn_bg_h, COLOR_BUTTON_DISABLED_BACKGROUND);
                    drawalpha(BM_PAUSE, btnx, bbtn_y, btnw, btnh, COLOR_BUTTON_DISABLED_TRANSFER);
                }

                framerect((x + dx) + 5 * SCALE, y + 17 * SCALE, (x + dx) + 111 * SCALE, y + 24 * SCALE, COLOR_BUTTON_DISABLED_TRANSFER);
                drawrectw((x + dx) + 5 * SCALE, y + 17 * SCALE, w, 7 * SCALE, COLOR_BUTTON_DISABLED_TRANSFER);
                break;
            }
            }

            drawtext(x + dx + 5 * SCALE, y + 10 * SCALE, size, sizelen);
            drawtextwidth(x + dx + 5 * SCALE, 106 * SCALE, y + 3 * SCALE, file->name, file->name_length);

            y += BM_FT_HEIGHT;
            break;

        }
        }

        y += MESSAGES_SPACING;
    }

    if(i == n) {
        // Last message is visible. Append typing notifications, if needed.
        FRIEND *f = get_typers(m);
        if(f) {
            setfont(FONT_TEXT);
            // @TODO: separate these colours if needed
            setcolor(COLOR_MAIN_HINTTEXT);
            drawtextwidth_right(x, MESSAGES_X - NAME_OFFSET, y, f->name, f->name_length);
            drawtextwidth(x + MESSAGES_X, x + width, y, S(IS_TYPING), SLEN(IS_TYPING));
        }
    }
}