2070 lines
50 KiB
C
2070 lines
50 KiB
C
|
/* GKrellM
|
||
|
| Copyright (C) 1999-2007 Bill Wilson
|
||
|
|
|
||
|
| Author: Bill Wilson billw@gkrellm.net
|
||
|
| Latest versions might be found at: http://gkrellm.net
|
||
|
|
|
||
|
|
|
||
|
| GKrellM is free software: you can redistribute it and/or modify it
|
||
|
| under the terms of the GNU General Public License as published by
|
||
|
| the Free Software Foundation, either version 3 of the License, or
|
||
|
| (at your option) any later version.
|
||
|
|
|
||
|
| GKrellM is distributed in the hope that it will be useful, but WITHOUT
|
||
|
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
|
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||
|
| License for more details.
|
||
|
|
|
||
|
| You should have received a copy of the GNU General Public License
|
||
|
| along with this program. If not, see http://www.gnu.org/licenses/
|
||
|
*/
|
||
|
|
||
|
#include "gkrellm.h"
|
||
|
#include "gkrellm-private.h"
|
||
|
|
||
|
static GkrellmBorder zero_border;
|
||
|
static GkrellmMargin zero_margin;
|
||
|
|
||
|
/* Smooth the krell response with an exponential moving average.
|
||
|
| Eponential MA is quicker responding than pure moving average.
|
||
|
| a = 2 / (period + 1)
|
||
|
| ema = ema + a * (reading - ema)
|
||
|
| Don't need floating point precision here, so do the int math in an
|
||
|
| order to minimize roundoff error and scale by 256 for some precision.
|
||
|
*/
|
||
|
static gint
|
||
|
exp_MA(GkrellmKrell *k)
|
||
|
{
|
||
|
gint ema, p, reading, round_up;
|
||
|
|
||
|
/* First, help the krell settle to zero and full scale. This gives
|
||
|
| on/off fast response while the ema is smoothing in between.
|
||
|
*/
|
||
|
if (k->reading == 0 && k->last_reading == 0)
|
||
|
return 0;
|
||
|
if (k->reading >= k->full_scale && k->last_reading >= k->full_scale)
|
||
|
return k->full_scale;
|
||
|
if (k->last_reading == 0) /* Fast liftoff as well */
|
||
|
return k->reading;
|
||
|
ema = k->ema << 8;
|
||
|
p = k->period + 1; /* Don't scale this! */
|
||
|
reading = (k->reading) << 8;
|
||
|
|
||
|
ema = ema + 2 * reading / p - 2 * ema / p;
|
||
|
round_up = ((ema & 0xff) > 127) ? 1 : 0;
|
||
|
|
||
|
return (ema >> 8) + round_up;
|
||
|
}
|
||
|
|
||
|
/* If the Krell has moved, redraw its layer on its stencil.
|
||
|
*/
|
||
|
void
|
||
|
gkrellm_update_krell(GkrellmPanel *p, GkrellmKrell *k, gulong value)
|
||
|
{
|
||
|
gint xnew, x_src, y_src, x_dst, w1, w2, w_overlap, d, frame;
|
||
|
|
||
|
if (!p || !k || k->full_scale == 0)
|
||
|
return;
|
||
|
k->value = value;
|
||
|
if (value < k->previous) /* unsigned long overflow? */
|
||
|
{
|
||
|
k->previous = value;
|
||
|
return;
|
||
|
}
|
||
|
if (!k->monotonic)
|
||
|
k->previous = 0;
|
||
|
k->reading = (gint) (value - k->previous) * k->full_scale_expand;
|
||
|
if (k->reading > k->full_scale)
|
||
|
k->reading = k->full_scale;
|
||
|
|
||
|
k->ema = (k->period > 1) ? exp_MA(k) : k->reading;
|
||
|
if (k->monotonic)
|
||
|
k->previous = value;
|
||
|
k->last_reading = k->reading;
|
||
|
|
||
|
xnew = k->x0 + k->ema * k->w_scale / k->full_scale;
|
||
|
|
||
|
if (xnew == k->x0 && k->reading)
|
||
|
{
|
||
|
xnew = k->x0 + 1; /* Show something for all activity */
|
||
|
k->ema = 1;
|
||
|
}
|
||
|
if (xnew == k->x_position)
|
||
|
return;
|
||
|
k->x_position = xnew;
|
||
|
|
||
|
|
||
|
/* If the krell has depth, pick the frame to display as function of
|
||
|
| ema. Depth == 2 means display frame 0 at xnew == 0, and frame 1
|
||
|
| everywhere else. Depth > 2 means same thing for frame 0,
|
||
|
| diplay frame depth - 1 at xnew == full_scale, and display other
|
||
|
| frames in between at xnew proportional to ema/full_scale.
|
||
|
*/
|
||
|
d = k->depth;
|
||
|
if (k->ema == 0 || xnew == k->x0) /* Krell can settle before ema*/
|
||
|
frame = 0;
|
||
|
else if (k->ema >= k->full_scale)
|
||
|
frame = d - 1;
|
||
|
else
|
||
|
{
|
||
|
if (d == 1)
|
||
|
frame = 0;
|
||
|
else if (d == 2)
|
||
|
frame = 1;
|
||
|
else
|
||
|
frame = 1 + ((d - 2) * k->ema / k->full_scale);
|
||
|
}
|
||
|
y_src = k->h_frame * frame;
|
||
|
if (k->bar_mode)
|
||
|
{
|
||
|
x_src = (k->bar_mode == KRELL_EXPAND_BAR_MODE_SCALED) ? 0 : k->x0;
|
||
|
x_dst = k->x0;
|
||
|
w_overlap = xnew - k->x0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x_src = k->x_hot - (xnew - k->x0);
|
||
|
if (x_src < 0)
|
||
|
x_src = 0;
|
||
|
x_dst = xnew - k->x_hot;
|
||
|
if (x_dst < k->x0)
|
||
|
x_dst = k->x0;
|
||
|
w1 = k->w - x_src;
|
||
|
w2 = (k->x0 + k->w_scale + 1) - x_dst;
|
||
|
w_overlap = (w2 > w1) ? w1 : w2;
|
||
|
}
|
||
|
|
||
|
/* Clear the krell stencil bitmap and draw the mask.
|
||
|
*/
|
||
|
gdk_draw_rectangle(k->stencil, _GK.bit0_GC, TRUE,
|
||
|
0,0, k->w, k->h_frame);
|
||
|
if (k->mask)
|
||
|
gdk_draw_drawable(k->stencil, _GK.bit1_GC, k->mask,
|
||
|
x_src, y_src, x_dst, 0, w_overlap, k->h_frame);
|
||
|
else
|
||
|
gdk_draw_rectangle(k->stencil, _GK.bit1_GC,
|
||
|
TRUE, x_dst, 0, w_overlap, k->h_frame);
|
||
|
|
||
|
if (!k->modified) /* Preserve original old draw if there has been */
|
||
|
k->old_draw = k->draw; /* no intervening draw_panel_layers() */
|
||
|
|
||
|
k->draw.x_src = x_src;
|
||
|
k->draw.y_src = y_src;
|
||
|
k->draw.x_dst = x_dst;
|
||
|
k->draw.y_dst = k->y0;
|
||
|
k->draw.w = w_overlap;
|
||
|
k->draw.h = k->h_frame;
|
||
|
|
||
|
k->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_get_size(GkrellmDecal *d, gint *w, gint *h)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
if (w)
|
||
|
*w = d->w;
|
||
|
if (h)
|
||
|
*h = d->h;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_draw_decal_on_chart(GkrellmChart *cp, GkrellmDecal *d,
|
||
|
gint xd, gint yd)
|
||
|
{
|
||
|
PangoLayout *layout;
|
||
|
PangoRectangle ink;
|
||
|
GList *list;
|
||
|
GdkRectangle rect, *r;
|
||
|
GkrellmTextstyle *ts;
|
||
|
GkrellmText *tx;
|
||
|
gint x, y, max;
|
||
|
|
||
|
if (!cp || !d || d->state != DS_VISIBLE)
|
||
|
return;
|
||
|
d->x = xd;
|
||
|
d->y = yd;
|
||
|
|
||
|
if (d->text_list)
|
||
|
{
|
||
|
r = &d->ink;
|
||
|
if (d->modified || d->chart_sequence_id != cp->bg_sequence_id)
|
||
|
{
|
||
|
gdk_draw_drawable(cp->bg_text_pixmap, _GK.draw1_GC, cp->bg_pixmap,
|
||
|
d->x, d->y, d->x, d->y, d->w, d->h);
|
||
|
layout = gtk_widget_create_pango_layout(
|
||
|
gkrellm_get_top_window(), NULL);
|
||
|
memset(r, 0, sizeof(GdkRectangle));
|
||
|
rect.x = d->x;
|
||
|
rect.y = d->y;
|
||
|
rect.width = d->w;
|
||
|
rect.height = d->h;
|
||
|
gdk_gc_set_clip_rectangle(_GK.text_GC, &rect);
|
||
|
for (list = d->text_list; list; list = list->next)
|
||
|
{
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
ts = &tx->text_style;
|
||
|
pango_layout_set_font_description(layout, ts->font);
|
||
|
if (d->flags & DF_TEXT_USE_MARKUP)
|
||
|
pango_layout_set_markup(layout, tx->text,strlen(tx->text));
|
||
|
else
|
||
|
pango_layout_set_text(layout, tx->text, strlen(tx->text));
|
||
|
x = d->x + tx->x_off;
|
||
|
y = d->y + tx->y_off;
|
||
|
if (ts->effect)
|
||
|
{
|
||
|
gdk_gc_set_foreground(_GK.text_GC, &ts->shadow_color);
|
||
|
gdk_draw_layout_with_colors(cp->bg_text_pixmap,
|
||
|
_GK.text_GC,
|
||
|
x + 1, y + 1, layout,
|
||
|
&ts->shadow_color, NULL);
|
||
|
}
|
||
|
gdk_gc_set_foreground(_GK.text_GC, &ts->color);
|
||
|
gdk_draw_layout(cp->bg_text_pixmap, _GK.text_GC, x, y, layout);
|
||
|
|
||
|
pango_layout_get_pixel_extents(layout, &ink, NULL);
|
||
|
if (r->x == 0 || ink.x + x < r->x) /* Shadow ??? */
|
||
|
r->x = ink.x + x;
|
||
|
if (r->y == 0 || ink.y + y < r->y)
|
||
|
r->y = ink.y + y;
|
||
|
max = ink.x + x + ink.width;
|
||
|
if (r->x + r->width < max)
|
||
|
r->width = max - r->x;
|
||
|
max = ink.y + y + ink.height;
|
||
|
if (r->y + r->height < max)
|
||
|
r->height = max - r->y;
|
||
|
}
|
||
|
gdk_gc_set_clip_rectangle(_GK.text_GC, NULL);
|
||
|
g_object_unref(layout);
|
||
|
d->chart_sequence_id = cp->bg_sequence_id;
|
||
|
d->modified = FALSE;
|
||
|
}
|
||
|
gdk_draw_drawable(cp->pixmap, _GK.draw1_GC, cp->bg_text_pixmap,
|
||
|
r->x, r->y, r->x, r->y, r->width, r->height);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gdk_gc_set_clip_mask(_GK.text_GC, d->stencil);
|
||
|
gdk_gc_set_clip_origin(_GK.text_GC, xd, yd);
|
||
|
gdk_draw_drawable(cp->pixmap, _GK.text_GC, d->pixmap,
|
||
|
0, d->y_src, xd, yd, d->w, d->h);
|
||
|
|
||
|
gdk_gc_set_clip_mask(_GK.text_GC, NULL);
|
||
|
gdk_gc_set_clip_origin(_GK.text_GC, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_draw_decal_pixmap(GkrellmPanel *p, GkrellmDecal *d, gint index)
|
||
|
{
|
||
|
gint y_src;
|
||
|
|
||
|
if (!d)
|
||
|
return;
|
||
|
if (d->value != index)
|
||
|
{
|
||
|
/* Write the new decal mask onto the panel stencil
|
||
|
*/
|
||
|
y_src = index * d->h;
|
||
|
d->y_src = y_src;
|
||
|
if (d->mask) /* Can be NULL if no transparency */
|
||
|
gdk_draw_drawable(d->stencil, _GK.bit1_GC, d->mask,
|
||
|
0, y_src, 0, 0, d->w, d->h);
|
||
|
else /* Fill decal extent with white */
|
||
|
gdk_draw_rectangle(d->stencil, _GK.bit1_GC,
|
||
|
TRUE, 0, 0, d->w, d->h);
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
d->value = index;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
decal_text_list_free(GList **text_list)
|
||
|
{
|
||
|
GList *list;
|
||
|
|
||
|
if (!text_list || !*text_list)
|
||
|
return;
|
||
|
for (list = *text_list; list; list = list->next)
|
||
|
g_free(((GkrellmText *) list->data)->text);
|
||
|
gkrellm_free_glist_and_data(text_list);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Draw to first GkrellmText in text_list and truncate text_list to make
|
||
|
| gkrellm_draw_decal_text() compatible with plugin code written before
|
||
|
| the text_list implementation. For backwards compatibility, d->x_off
|
||
|
| shadows the first tx->x_off.
|
||
|
| Combining gkrellm_draw_decal_text() and gkrellm_decal_text_insert()
|
||
|
| functions on the same decal may lead to unexpected results.
|
||
|
*/
|
||
|
static void
|
||
|
gkrellm_draw_decal_internal(GkrellmPanel *p, GkrellmDecal *d, gchar *s,
|
||
|
gint value)
|
||
|
{
|
||
|
GkrellmText *tx;
|
||
|
GList *list;
|
||
|
|
||
|
if (!s || !d || d->state == DS_INVISIBLE)
|
||
|
return;
|
||
|
if (!d->text_list)
|
||
|
d->text_list = g_list_append(d->text_list, g_new0(GkrellmText, 1));
|
||
|
list = d->text_list;
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
if ( gkrellm_dup_string(&tx->text, s)
|
||
|
|| tx->x_off_prev != d->x_off
|
||
|
|| tx->text_style.font != d->text_style.font
|
||
|
|| tx->text_style.color.pixel != d->text_style.color.pixel
|
||
|
)
|
||
|
d->modified = TRUE;
|
||
|
tx->x_off = d->x_off;
|
||
|
tx->x_off_prev = d->x_off;
|
||
|
tx->y_off = d->y_off - d->y_ink;
|
||
|
tx->text_style = d->text_style;
|
||
|
if (list->next)
|
||
|
decal_text_list_free(&list->next);
|
||
|
d->value = value;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_draw_decal_text(GkrellmPanel *p, GkrellmDecal *d, gchar *s, gint value)
|
||
|
{
|
||
|
d->flags &= ~DF_TEXT_USE_MARKUP;
|
||
|
|
||
|
/* In case mixing scroll_text and draw_decal_text calls
|
||
|
*/
|
||
|
d->flags &= ~DF_SCROLL_TEXT_DIVERTED;
|
||
|
if (d->scroll_text)
|
||
|
{
|
||
|
g_free(d->scroll_text);
|
||
|
d->scroll_text = NULL;
|
||
|
}
|
||
|
|
||
|
gkrellm_draw_decal_internal(p, d, s, value);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_draw_decal_markup(GkrellmPanel *p, GkrellmDecal *d, gchar *s)
|
||
|
{
|
||
|
d->flags |= DF_TEXT_USE_MARKUP;
|
||
|
|
||
|
/* In case mixing scroll_text and draw_decal_text calls
|
||
|
*/
|
||
|
d->flags &= ~DF_SCROLL_TEXT_DIVERTED;
|
||
|
if (d->scroll_text)
|
||
|
{
|
||
|
g_free(d->scroll_text);
|
||
|
d->scroll_text = NULL;
|
||
|
}
|
||
|
|
||
|
gkrellm_draw_decal_internal(p, d, s, 0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_text_get_offset(GkrellmDecal *d, gint *x, gint *y)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
if (x)
|
||
|
*x = d->x_off;
|
||
|
if (y)
|
||
|
*y = d->y_off;
|
||
|
}
|
||
|
|
||
|
/* Setting offset of text decal means setting offset of first GkrellmText
|
||
|
| in text_list. For backwards compatibility with plugin code that
|
||
|
| directly accesses d->x_off, shadow d->x_off to first tx->x_off.
|
||
|
*/
|
||
|
void
|
||
|
gkrellm_decal_text_set_offset(GkrellmDecal *d, gint x, gint y)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmText *tx;
|
||
|
|
||
|
if (!d || (d->x_off == x && d->y_off == y))
|
||
|
return;
|
||
|
|
||
|
d->x_off = x;
|
||
|
d->y_off = y;
|
||
|
if ((list = d->text_list) != NULL)
|
||
|
{
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
tx->x_off = x;
|
||
|
tx->x_off_prev = x;
|
||
|
tx->y_off = y - d->y_ink;;
|
||
|
}
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_text_clear(GkrellmDecal *d)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmText *tx;
|
||
|
|
||
|
if (!d || ((list = d->text_list) == NULL))
|
||
|
return;
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
|
||
|
if (list->next)
|
||
|
decal_text_list_free(&list->next);
|
||
|
|
||
|
gkrellm_dup_string(&tx->text, "");
|
||
|
tx->text_style = d->text_style;
|
||
|
|
||
|
if (d->scroll_text)
|
||
|
g_free(d->scroll_text);
|
||
|
d->scroll_text = NULL;
|
||
|
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
/* Insert text into a decal's text_list at a given offset. Using text
|
||
|
| insert functions makes d->x_off and d->y_off meaningless since offsets
|
||
|
| are in each GkrellmText's tx->x_off and tx->y_off.
|
||
|
*/
|
||
|
void
|
||
|
gkrellm_decal_text_insert(GkrellmDecal *d, gchar *s, GkrellmTextstyle *ts,
|
||
|
gint x_off, gint y_off)
|
||
|
{
|
||
|
GkrellmText *tx = NULL;
|
||
|
|
||
|
if (!s || !d || d->state == DS_INVISIBLE)
|
||
|
return;
|
||
|
d->flags &= ~DF_TEXT_USE_MARKUP;
|
||
|
if (!ts)
|
||
|
ts = &d->text_style;
|
||
|
if ( d->text_list
|
||
|
&& !*((GkrellmText *) d->text_list->data)->text
|
||
|
)
|
||
|
tx = (GkrellmText *) d->text_list->data;
|
||
|
|
||
|
if (!tx)
|
||
|
{
|
||
|
tx = g_new0(GkrellmText, 1);
|
||
|
d->text_list = g_list_append(d->text_list, tx);
|
||
|
}
|
||
|
|
||
|
gkrellm_dup_string(&tx->text, s);
|
||
|
tx->x_off = x_off;
|
||
|
tx->x_off_prev = x_off;
|
||
|
tx->y_off = y_off - d->y_ink;
|
||
|
tx->text_style = *ts;
|
||
|
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_text_markup_insert(GkrellmDecal *d, gchar *s,
|
||
|
GkrellmTextstyle *ts, gint x_off, gint y_off)
|
||
|
{
|
||
|
GkrellmText *tx = NULL;
|
||
|
|
||
|
if (!s || !d || d->state == DS_INVISIBLE)
|
||
|
return;
|
||
|
d->flags |= DF_TEXT_USE_MARKUP;
|
||
|
if (!ts)
|
||
|
ts = &d->text_style;
|
||
|
if ( d->text_list
|
||
|
&& !*((GkrellmText *) d->text_list->data)->text
|
||
|
)
|
||
|
tx = (GkrellmText *) d->text_list->data;
|
||
|
|
||
|
if (!tx)
|
||
|
{
|
||
|
tx = g_new0(GkrellmText, 1);
|
||
|
d->text_list = g_list_append(d->text_list, tx);
|
||
|
}
|
||
|
|
||
|
gkrellm_dup_string(&tx->text, s);
|
||
|
tx->x_off = x_off;
|
||
|
tx->x_off_prev = x_off;
|
||
|
tx->y_off = y_off - d->y_ink;
|
||
|
tx->text_style = *ts;
|
||
|
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_text_nth_inserted_set_offset(GkrellmDecal *d, gint n,
|
||
|
gint x, gint y)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmText *tx;
|
||
|
|
||
|
if (!d || (list = g_list_nth(d->text_list, n)) == NULL)
|
||
|
return;
|
||
|
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
if (tx->x_off != x || tx->y_off != y)
|
||
|
{
|
||
|
tx->x_off = x;
|
||
|
tx->x_off_prev = x;
|
||
|
tx->y_off = y - d->y_ink;;
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_text_nth_inserted_get_offset(GkrellmDecal *d, gint n,
|
||
|
gint *x, gint *y)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmText *tx;
|
||
|
|
||
|
if (!d || (list = g_list_nth(d->text_list, n)) == NULL)
|
||
|
return;
|
||
|
|
||
|
tx = (GkrellmText *) list->data;
|
||
|
if (x)
|
||
|
*x = tx->x_off;
|
||
|
if (y)
|
||
|
*y = tx->y_off + d->y_ink;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_align_center(GkrellmDecal *d, gboolean center)
|
||
|
{
|
||
|
gint prev_center;
|
||
|
|
||
|
if (!d)
|
||
|
return;
|
||
|
prev_center = d->flags & DF_SCROLL_TEXT_CENTER;
|
||
|
if ((center && prev_center) || (!center && !prev_center))
|
||
|
return;
|
||
|
|
||
|
if (center)
|
||
|
d->flags |= DF_SCROLL_TEXT_CENTER;
|
||
|
else
|
||
|
d->flags &= ~DF_SCROLL_TEXT_CENTER;
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_horizontal_loop(GkrellmDecal *d, gboolean loop)
|
||
|
{
|
||
|
gint prev_loop;
|
||
|
|
||
|
if (!d)
|
||
|
return;
|
||
|
prev_loop = d->flags & DF_SCROLL_TEXT_H_LOOP;
|
||
|
if ((loop && prev_loop) || (!loop && !prev_loop))
|
||
|
return;
|
||
|
|
||
|
if (loop)
|
||
|
d->flags |= DF_SCROLL_TEXT_H_LOOP;
|
||
|
else
|
||
|
d->flags &= ~DF_SCROLL_TEXT_H_LOOP;
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_vertical_loop(GkrellmDecal *d, gboolean loop)
|
||
|
{
|
||
|
gint prev_loop;
|
||
|
|
||
|
if (!d)
|
||
|
return;
|
||
|
prev_loop = d->flags & DF_SCROLL_TEXT_V_LOOP;
|
||
|
if ((loop && prev_loop) || (!loop && !prev_loop))
|
||
|
return;
|
||
|
|
||
|
if (loop)
|
||
|
d->flags |= DF_SCROLL_TEXT_V_LOOP;
|
||
|
else
|
||
|
d->flags &= ~DF_SCROLL_TEXT_V_LOOP;
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_get_size(GkrellmDecal *d, gint *w, gint *h)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
if (w)
|
||
|
*w = d->scroll_width;
|
||
|
if (h)
|
||
|
*h = d->scroll_height
|
||
|
+ ((d->flags & DF_SCROLL_TEXT_V_LOOP) ? d->y_ink : 0);
|
||
|
}
|
||
|
|
||
|
static PangoLayout *
|
||
|
decal_scroll_text_layout(GkrellmDecal *d, gchar *text, gint *yink)
|
||
|
{
|
||
|
PangoLayout *layout;
|
||
|
PangoRectangle ink, logical;
|
||
|
GkrellmTextstyle *ts;
|
||
|
gint y_ink;
|
||
|
|
||
|
ts = &d->text_style;
|
||
|
layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
|
||
|
pango_layout_set_spacing(layout, 0);
|
||
|
if (d->flags & DF_SCROLL_TEXT_CENTER)
|
||
|
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||
|
pango_layout_set_font_description(layout, ts->font);
|
||
|
if (d->flags & DF_TEXT_USE_MARKUP)
|
||
|
pango_layout_set_markup(layout, text, strlen(text));
|
||
|
else
|
||
|
pango_layout_set_text(layout, text, strlen(text));
|
||
|
|
||
|
pango_layout_get_pixel_extents(layout, &ink, &logical);
|
||
|
d->scroll_width = logical.width + ts->effect; /* incl trailing spaces */
|
||
|
d->scroll_height = ink.height + ts->effect;
|
||
|
y_ink = ink.y - logical.y;
|
||
|
|
||
|
/* y_ink change can happen if markup up text sizes differently from sizing
|
||
|
| at decal creation. Adjust the decal y_ink so text doesn't get bumped
|
||
|
| upward which clips top of text string. This means the decal height
|
||
|
| should probably also be changed because now descenders might get
|
||
|
| clipped when switching back out of scrolling.
|
||
|
| But this is much less noticeable... later.
|
||
|
*/
|
||
|
if (d->y_ink > y_ink)
|
||
|
d->y_ink = y_ink;
|
||
|
|
||
|
if (yink)
|
||
|
*yink = y_ink;
|
||
|
return layout;
|
||
|
}
|
||
|
|
||
|
/* If mixing draw_decal_text and scroll_text calls, must reset decal regions
|
||
|
| in bg_text_layer_pixmap to bg_pixmap at first switch to scroll_text calls.
|
||
|
*/
|
||
|
static void
|
||
|
reset_text_layer_pixmap_decal_region(GkrellmPanel *p, GkrellmDecal *d)
|
||
|
{
|
||
|
if (d->flags & DF_MOVED)
|
||
|
{
|
||
|
gdk_draw_drawable(p->bg_text_layer_pixmap, _GK.draw1_GC,
|
||
|
p->bg_pixmap,
|
||
|
d->x_old, d->y_old, d->x_old, d->y_old, d->w, d->h);
|
||
|
d->flags &= ~DF_MOVED;
|
||
|
}
|
||
|
else
|
||
|
gdk_draw_drawable(p->bg_text_layer_pixmap, _GK.draw1_GC,
|
||
|
p->bg_pixmap,
|
||
|
d->x, d->y, d->x, d->y, d->w, d->h);
|
||
|
}
|
||
|
|
||
|
/* Draw Pango rendered text onto a pixmap which can be scrolled across
|
||
|
| a decal's extents. So when scrolling, a slow Pango redraw at each scroll
|
||
|
| step can be avoided if the text string has not changed.
|
||
|
| There are a couple of limitations because it's impossible to generate a
|
||
|
| stencil bitmask of Pango rendered text (Pango doesn't allow writting to
|
||
|
| depth 1 and it looks at the background pixmap colors as it renders):
|
||
|
| 1) A scroll text decal is not transparent and will hide any objects
|
||
|
| underneath it, so when this condition is detected, scroll drawing
|
||
|
| is diverted to Pango at each step gkrellm_draw_decal_text().
|
||
|
| 2) The scroll text must be rendered onto a background which for many
|
||
|
| themes won't exactly blend with the panel background as the scroll
|
||
|
| pixmap is scrolled. It should be at worst only slightly noticeable
|
||
|
| for most themes, but might be a problem for themes with high gradient
|
||
|
| panel backgrounds.
|
||
|
*/
|
||
|
static void
|
||
|
gkrellm_decal_scroll_text_set_internal(GkrellmPanel *p, GkrellmDecal *d,
|
||
|
gchar *text)
|
||
|
{
|
||
|
GtkWidget *top_win = gkrellm_get_top_window();
|
||
|
PangoLayout *layout;
|
||
|
GdkPixbuf *pixbuf;
|
||
|
GList *list;
|
||
|
GkrellmDecal *dcheck;
|
||
|
GkrellmBorder *b;
|
||
|
GkrellmTextstyle *ts;
|
||
|
gint dx, y_ink;
|
||
|
gboolean new_text, no_scroll_caching, first_scroll;
|
||
|
|
||
|
if (!p || !text || !d || d->state == DS_INVISIBLE)
|
||
|
return;
|
||
|
|
||
|
first_scroll = (d->scroll_text == NULL);
|
||
|
|
||
|
new_text = gkrellm_dup_string(&d->scroll_text, text);
|
||
|
no_scroll_caching = (p->transparency || p->scroll_text_cache_off);
|
||
|
|
||
|
for (list = p->decal_list; list; list = list->next)
|
||
|
{
|
||
|
dcheck = (GkrellmDecal *) list->data;
|
||
|
|
||
|
/* Scroll text underneath is OK */
|
||
|
if (dcheck == d && !no_scroll_caching)
|
||
|
break;
|
||
|
|
||
|
/* But scroll text overlapping and on top of any other decal requires
|
||
|
| scroll text to be pushed.
|
||
|
*/
|
||
|
if ( no_scroll_caching
|
||
|
|| ( d->x + d->w > dcheck->x
|
||
|
&& d->x < dcheck->x + dcheck->w
|
||
|
&& d->y + d->h > dcheck->y
|
||
|
&& d->y < dcheck->y + dcheck->h
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
if (first_scroll && d->text_list)
|
||
|
reset_text_layer_pixmap_decal_region(p, d);
|
||
|
|
||
|
d->flags |= (DF_TEXT_OVERLAPS | DF_SCROLL_TEXT_DIVERTED);
|
||
|
if (new_text)
|
||
|
{
|
||
|
layout = decal_scroll_text_layout(d, text, NULL);
|
||
|
g_object_unref(G_OBJECT(layout));
|
||
|
}
|
||
|
gkrellm_draw_decal_internal(p, d, text, -1);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (d->text_list) /* Erase any previous gkrellm_draw_decal_text() */
|
||
|
{
|
||
|
reset_text_layer_pixmap_decal_region(p, d);
|
||
|
decal_text_list_free(&d->text_list);
|
||
|
d->value = -1;
|
||
|
}
|
||
|
d->modified = TRUE;
|
||
|
|
||
|
if (!new_text && !(d->flags & DF_SCROLL_TEXT_DIVERTED))
|
||
|
return;
|
||
|
|
||
|
layout = decal_scroll_text_layout(d, text, &y_ink);
|
||
|
gkrellm_free_pixmap(&d->pixmap);
|
||
|
d->pixmap = gdk_pixmap_new(top_win->window,
|
||
|
d->scroll_width, d->scroll_height, -1);
|
||
|
|
||
|
if (!d->pixmap) /* too wide maybe? */
|
||
|
{
|
||
|
d->flags |= (DF_TEXT_OVERLAPS | DF_SCROLL_TEXT_DIVERTED);
|
||
|
g_object_unref(G_OBJECT(layout));
|
||
|
gkrellm_draw_decal_text(p, d, text, -1);
|
||
|
return;
|
||
|
}
|
||
|
d->flags &= ~(DF_TEXT_OVERLAPS | DF_SCROLL_TEXT_DIVERTED);
|
||
|
|
||
|
dx = d->w - d->scroll_width;
|
||
|
|
||
|
if (dx >= 0)
|
||
|
pixbuf = gdk_pixbuf_get_from_drawable(NULL, p->bg_pixmap, NULL,
|
||
|
d->x + ((d->flags & DF_SCROLL_TEXT_CENTER) ? dx / 2 : 0), d->y,
|
||
|
0, 0, d->scroll_width, d->h);
|
||
|
else
|
||
|
{
|
||
|
gint xfudge, yfudge; /* Many themes have sloppy margins XXX */
|
||
|
|
||
|
xfudge = d->w > 20 ? d->w / 6 : 0; /* and gradient compensate a bit */
|
||
|
yfudge = d->h > 5 ? d->h / 5 : 0;
|
||
|
pixbuf = gdk_pixbuf_get_from_drawable(NULL, p->bg_pixmap, NULL,
|
||
|
d->x + xfudge, d->y + yfudge, 0, 0,
|
||
|
d->w - 2 * xfudge, d->h - 2 * yfudge);
|
||
|
}
|
||
|
|
||
|
if (pixbuf)
|
||
|
{
|
||
|
gkrellm_paste_pixbuf(pixbuf, d->pixmap, 0, 0,
|
||
|
d->scroll_width, d->scroll_height);
|
||
|
g_object_unref(G_OBJECT(pixbuf));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b = &p->bg_piximage->border;
|
||
|
gkrellm_paste_pixbuf(p->bg_piximage->pixbuf, d->pixmap,
|
||
|
b->left, b->top,
|
||
|
d->scroll_width + b->left + b->right,
|
||
|
d->scroll_height + b->top + b->bottom); /* XXX */
|
||
|
}
|
||
|
|
||
|
ts = &d->text_style;
|
||
|
if (ts->effect)
|
||
|
{
|
||
|
gdk_gc_set_foreground(_GK.text_GC, &ts->shadow_color);
|
||
|
gdk_draw_layout_with_colors(d->pixmap, _GK.text_GC,
|
||
|
1, -y_ink + 1, layout,
|
||
|
&ts->shadow_color, NULL);
|
||
|
}
|
||
|
gdk_gc_set_foreground(_GK.text_GC, &ts->color);
|
||
|
gdk_draw_layout(d->pixmap, _GK.text_GC, 0, -y_ink, layout);
|
||
|
|
||
|
g_object_unref(G_OBJECT(layout));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_set_markup(GkrellmPanel *p, GkrellmDecal *d,
|
||
|
gchar *text)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
d->flags |= DF_TEXT_USE_MARKUP;
|
||
|
gkrellm_decal_scroll_text_set_internal(p, d, text);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_scroll_text_set_text(GkrellmPanel *p, GkrellmDecal *d,
|
||
|
gchar *text)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
d->flags &= ~DF_TEXT_USE_MARKUP;
|
||
|
gkrellm_decal_scroll_text_set_internal(p, d, text);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
gkrellm_move_krell_yoff(GkrellmPanel *p, GkrellmKrell *k, gint y)
|
||
|
{
|
||
|
if (!k)
|
||
|
return;
|
||
|
if (!k->modified)
|
||
|
k->old_draw = k->draw;
|
||
|
k->y0 = k->draw.y_dst = y;
|
||
|
k->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_destroy_krell(GkrellmKrell *k)
|
||
|
{
|
||
|
if (!k)
|
||
|
return;
|
||
|
gkrellm_free_bitmap(&k->stencil);
|
||
|
gkrellm_free_pixmap(&k->pixmap);
|
||
|
gkrellm_free_bitmap(&k->mask);
|
||
|
g_free(k);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_destroy_krell(GkrellmKrell *k)
|
||
|
{
|
||
|
if (!k)
|
||
|
return;
|
||
|
gkrellm_remove_krell((GkrellmPanel *) k->panel, k);
|
||
|
_destroy_krell(k);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_remove_krell(GkrellmPanel *p, GkrellmKrell *k)
|
||
|
{
|
||
|
GkrellmDrawrec *dr;
|
||
|
|
||
|
if (!k || !k->panel || !p || !g_list_find(p->krell_list, k))
|
||
|
return;
|
||
|
p->krell_list = g_list_remove(p->krell_list, k);
|
||
|
k->panel = NULL;
|
||
|
dr = &k->draw;
|
||
|
if (p->pixmap && p->bg_pixmap)
|
||
|
{
|
||
|
gdk_draw_drawable(p->pixmap, _GK.draw1_GC, p->bg_pixmap,
|
||
|
dr->x_dst, dr->y_dst, dr->x_dst, dr->y_dst, dr->w, dr->h);
|
||
|
if (p->drawing_area && p->drawing_area->window)
|
||
|
gdk_draw_drawable(p->drawing_area->window, _GK.draw1_GC,
|
||
|
p->bg_pixmap,
|
||
|
dr->x_dst, dr->y_dst, dr->x_dst, dr->y_dst, dr->w, dr->h);
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_insert_krell(GkrellmPanel *p, GkrellmKrell *k, gboolean append)
|
||
|
{
|
||
|
if (!k || k->panel || !p || g_list_find(p->krell_list, k))
|
||
|
return;
|
||
|
if (append)
|
||
|
p->krell_list = g_list_append(p->krell_list, k);
|
||
|
else
|
||
|
p->krell_list = g_list_prepend(p->krell_list, k);
|
||
|
k->panel = (GkrellmPanel *) p;
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_insert_krell_nth(GkrellmPanel *p, GkrellmKrell *k, gint n)
|
||
|
{
|
||
|
if (!p || !k || g_list_find(p->krell_list, k))
|
||
|
return;
|
||
|
p->krell_list = g_list_insert(p->krell_list, k, n);
|
||
|
k->panel = (GkrellmPanel *) p;
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_destroy_krell_list(GkrellmPanel *p)
|
||
|
{
|
||
|
GList *list;
|
||
|
|
||
|
if (!p)
|
||
|
return;
|
||
|
for (list = p->krell_list; list; list = list->next)
|
||
|
_destroy_krell((GkrellmKrell *) list->data);
|
||
|
if (p->krell_list)
|
||
|
g_list_free(p->krell_list);
|
||
|
p->krell_list = NULL;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_set_krell_margins(GkrellmPanel *p, GkrellmKrell *k,
|
||
|
gint left, gint right)
|
||
|
{
|
||
|
if (!k)
|
||
|
return;
|
||
|
if (left > _GK.chart_width - 3)
|
||
|
left = _GK.chart_width - 3;
|
||
|
k->x0 = left;
|
||
|
k->w_scale = _GK.chart_width - k->x0 - right - 1;
|
||
|
if (k->w_scale < 2)
|
||
|
k->w_scale = 2;
|
||
|
if (p && p->pixmap && p->bg_pixmap)
|
||
|
{
|
||
|
/* Move the krell proportionally between the new limits
|
||
|
*/
|
||
|
k->x_position = -1;
|
||
|
if (k->monotonic)
|
||
|
k->previous -= k->value;
|
||
|
gkrellm_update_krell(p, k, k->value);
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_set_krell_full_scale(GkrellmKrell *k, gint full_scale, gint expand)
|
||
|
{
|
||
|
if (!k)
|
||
|
return;
|
||
|
k->full_scale_expand = (expand <= 0 ) ? 1 : expand;
|
||
|
k->full_scale = full_scale * k->full_scale_expand;
|
||
|
}
|
||
|
|
||
|
GkrellmKrell *
|
||
|
gkrellm_create_krell(GkrellmPanel *p, GkrellmPiximage *im, GkrellmStyle *style)
|
||
|
{
|
||
|
GtkWidget *top_win = gkrellm_get_top_window();
|
||
|
GkrellmKrell *k;
|
||
|
gint w, h, h_render, w_render;
|
||
|
|
||
|
k = (GkrellmKrell *) g_new0(GkrellmKrell, 1);
|
||
|
if (p)
|
||
|
p->krell_list = g_list_append(p->krell_list, k);
|
||
|
k->panel = (gpointer) p;
|
||
|
k->bar_mode = k->flags = 0;
|
||
|
|
||
|
if (im == NULL || style == NULL)
|
||
|
{
|
||
|
printf(_("create_krell: NULL image or style\n"));
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
/* Set left krell margin */
|
||
|
k->x0 = style->krell_left_margin;
|
||
|
if (k->x0 > _GK.chart_width - 3)
|
||
|
k->x0 = _GK.chart_width - 3;
|
||
|
|
||
|
/* Set right krell margin via w_scale (-1 adjust to keep x_hot visible */
|
||
|
k->w_scale = _GK.chart_width - k->x0 - style->krell_right_margin - 1;
|
||
|
if (k->w_scale < 2)
|
||
|
k->w_scale = 2;
|
||
|
|
||
|
/* krell_yoff values: >= 0, put krell at krell_yoff in the panel.
|
||
|
| == -1 put krell inside of margins at top margin.
|
||
|
| == -2 put krell at bottom of panel
|
||
|
| == -3 put krell inside of margins at bottom margin.
|
||
|
| For anything else, caller must gkrellm_krell_move_yoff() after create.
|
||
|
| Inside of top margin handled here, but panel configure must handle
|
||
|
| bottom of panel adjustments.
|
||
|
*/
|
||
|
k->y0 = style->krell_yoff;
|
||
|
if (k->y0 > 0 && !style->krell_yoff_not_scalable )
|
||
|
k->y0 = k->y0 * _GK.theme_scale / 100;
|
||
|
if (k->y0 == -1 || k->y0 == -3)
|
||
|
k->flags |= KRELL_FLAG_BOTTOM_MARGIN;
|
||
|
if (k->y0 == -1)
|
||
|
gkrellm_get_top_bottom_margins(style, &k->y0, NULL);
|
||
|
w = gdk_pixbuf_get_width(im->pixbuf);
|
||
|
h = gdk_pixbuf_get_height(im->pixbuf);
|
||
|
|
||
|
if (style->krell_x_hot < 0)
|
||
|
style->krell_x_hot = w / 2;
|
||
|
w_render = w * _GK.theme_scale / 100;
|
||
|
k->x_hot = style->krell_x_hot * _GK.theme_scale / 100;
|
||
|
|
||
|
switch (style->krell_expand)
|
||
|
{
|
||
|
case KRELL_EXPAND_NONE:
|
||
|
break;
|
||
|
case KRELL_EXPAND_BAR_MODE:
|
||
|
w_render = _GK.chart_width;
|
||
|
k->bar_mode = KRELL_EXPAND_BAR_MODE;
|
||
|
break;
|
||
|
case KRELL_EXPAND_BAR_MODE_SCALED:
|
||
|
w_render = k->w_scale + 1; /* undo -1 from w_scale calc */
|
||
|
k->bar_mode = KRELL_EXPAND_BAR_MODE_SCALED;
|
||
|
break;
|
||
|
case KRELL_EXPAND_LEFT:
|
||
|
if (style->krell_x_hot > 0 && style->krell_x_hot < w)
|
||
|
{
|
||
|
w_render = _GK.chart_width * w / style->krell_x_hot;
|
||
|
k->x_hot = _GK.chart_width - 1;
|
||
|
}
|
||
|
break;
|
||
|
case KRELL_EXPAND_LEFT_SCALED:
|
||
|
if (style->krell_x_hot > 0 && style->krell_x_hot < w)
|
||
|
{
|
||
|
w_render = (k->w_scale + 1) * w / style->krell_x_hot;
|
||
|
k->x_hot = k->w_scale;
|
||
|
}
|
||
|
break;
|
||
|
case KRELL_EXPAND_RIGHT:
|
||
|
if (w > style->krell_x_hot)
|
||
|
{
|
||
|
w_render = _GK.chart_width * w / (w - style->krell_x_hot);
|
||
|
k->x_hot = style->krell_x_hot * w_render / w;
|
||
|
}
|
||
|
break;
|
||
|
case KRELL_EXPAND_RIGHT_SCALED:
|
||
|
if (w > style->krell_x_hot)
|
||
|
{
|
||
|
w_render = (k->w_scale + 1) * w / (w - style->krell_x_hot);
|
||
|
k->x_hot = style->krell_x_hot * w_render / w;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
k->depth = style->krell_depth;
|
||
|
if (k->depth < 1)
|
||
|
k->depth = 1;
|
||
|
k->h_frame = h / k->depth * _GK.theme_scale / 100;
|
||
|
if (k->h_frame < 1)
|
||
|
k->h_frame = 1;
|
||
|
h_render = k->h_frame * k->depth;
|
||
|
|
||
|
gkrellm_scale_piximage_to_pixmap(im, &k->pixmap, &k->mask,
|
||
|
w_render, h_render);
|
||
|
|
||
|
k->h = h_render;
|
||
|
k->w = w_render;
|
||
|
|
||
|
k->stencil = gdk_pixmap_new(top_win->window, _GK.chart_width,
|
||
|
k->h_frame, 1);
|
||
|
k->period = style->krell_ema_period;
|
||
|
if (k->period >= 4 * _GK.update_HZ)
|
||
|
k->period = 4 * _GK.update_HZ;
|
||
|
|
||
|
k->x_position = -1; /* Force initial draw */
|
||
|
k->full_scale_expand = 1;
|
||
|
k->monotonic = TRUE;
|
||
|
return k;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_monotonic_krell_values(GkrellmKrell *k, gboolean mono)
|
||
|
{
|
||
|
if (k)
|
||
|
k->monotonic = mono;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------- */
|
||
|
|
||
|
static void
|
||
|
remove_from_button_list(GkrellmPanel *p, GkrellmDecalbutton *b)
|
||
|
{
|
||
|
if (!p || !b)
|
||
|
return;
|
||
|
p->button_list = g_list_remove(p->button_list, b);
|
||
|
g_free(b);
|
||
|
|
||
|
if (!p->button_list && p->drawing_area)
|
||
|
{
|
||
|
g_signal_handler_disconnect(G_OBJECT(p->drawing_area), p->id_press);
|
||
|
g_signal_handler_disconnect(G_OBJECT(p->drawing_area), p->id_release);
|
||
|
g_signal_handler_disconnect(G_OBJECT(p->drawing_area), p->id_enter);
|
||
|
g_signal_handler_disconnect(G_OBJECT(p->drawing_area), p->id_leave);
|
||
|
p->button_signals_connected = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_move_decal(GkrellmPanel *p, GkrellmDecal *d, gint x, gint y)
|
||
|
{
|
||
|
if (!d || (d->x == x && d->y == y))
|
||
|
return;
|
||
|
if (!(d->flags & DF_MOVED)) /* If no intervening draw_panel_layers() */
|
||
|
{ /* then preserve original old position */
|
||
|
d->x_old = d->x;
|
||
|
d->y_old = d->y;
|
||
|
}
|
||
|
d->x = x;
|
||
|
d->y = y;
|
||
|
d->flags |= DF_MOVED;
|
||
|
d->modified = TRUE;
|
||
|
|
||
|
if (p)
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_on_top_layer(GkrellmDecal *d, gboolean top)
|
||
|
{
|
||
|
GkrellmPanel *p = (GkrellmPanel *) d->panel;
|
||
|
if (!d)
|
||
|
return;
|
||
|
if (top)
|
||
|
d->flags |= DF_TOP_LAYER;
|
||
|
else
|
||
|
d->flags &= ~DF_TOP_LAYER;
|
||
|
if (p)
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
|
||
|
d->modified = TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_destroy_decal(GkrellmDecal *d)
|
||
|
{
|
||
|
if (!d)
|
||
|
return;
|
||
|
if ((d->flags & DF_LOCAL_PIXMAPS) && d->pixmap)
|
||
|
g_object_unref(G_OBJECT(d->pixmap));
|
||
|
if (d->stencil)
|
||
|
g_object_unref(G_OBJECT(d->stencil));
|
||
|
if (d->text_list)
|
||
|
decal_text_list_free(&d->text_list);
|
||
|
if (d->scroll_text)
|
||
|
g_free(d->scroll_text);
|
||
|
if (d->panel)
|
||
|
((GkrellmPanel *)d->panel)->need_decal_overlap_check = TRUE;
|
||
|
|
||
|
g_free(d);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_remove_decal(GkrellmPanel *p, GkrellmDecal *d)
|
||
|
{
|
||
|
if (!g_list_find(p->decal_list, d))
|
||
|
return;
|
||
|
p->decal_list = g_list_remove(p->decal_list, d);
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
d->panel = NULL;
|
||
|
if (p->pixmap && p->bg_pixmap)
|
||
|
{
|
||
|
gdk_draw_drawable(p->pixmap, _GK.draw1_GC, p->bg_pixmap,
|
||
|
d->x, d->y, d->x, d->y, d->w, d->h);
|
||
|
if (p->drawing_area && p->drawing_area->window)
|
||
|
gdk_draw_drawable(p->drawing_area->window, _GK.draw1_GC,
|
||
|
p->bg_pixmap, d->x, d->y, d->x, d->y, d->w, d->h);
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_destroy_decal(GkrellmDecal *d)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
if (d && d->panel)
|
||
|
{
|
||
|
if ((b = gkrellm_decal_is_button(d)) != NULL)
|
||
|
gkrellm_destroy_button(b);
|
||
|
else
|
||
|
{
|
||
|
_remove_decal((GkrellmPanel *) d->panel, d);
|
||
|
_destroy_decal(d);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
_destroy_decal(d);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_remove_decal(GkrellmPanel *p, GkrellmDecal *d)
|
||
|
{
|
||
|
if (!p || !d || gkrellm_decal_is_button(d))
|
||
|
return;
|
||
|
_remove_decal(p, d);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_insert_decal(GkrellmPanel *p, GkrellmDecal *d, gboolean append)
|
||
|
{
|
||
|
if (!p || !d || g_list_find(p->decal_list, d))
|
||
|
return;
|
||
|
if (append)
|
||
|
p->decal_list = g_list_append(p->decal_list, d);
|
||
|
else
|
||
|
p->decal_list = g_list_prepend(p->decal_list, d);
|
||
|
d->panel = (gpointer) p;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_insert_decal_nth(GkrellmPanel *p, GkrellmDecal *d, gint n)
|
||
|
{
|
||
|
if (!p || !d || g_list_find(p->decal_list, d))
|
||
|
return;
|
||
|
p->decal_list = g_list_insert(p->decal_list, d, n);
|
||
|
d->panel = (gpointer) p;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers_force(p);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_destroy_decal_list(GkrellmPanel *p)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmDecal *d;
|
||
|
GList *list;
|
||
|
|
||
|
if (!p)
|
||
|
return;
|
||
|
for (list = p->decal_list; list; list = list->next)
|
||
|
{
|
||
|
d = (GkrellmDecal *) list->data;
|
||
|
if ((b = gkrellm_decal_is_button(d)) != NULL)
|
||
|
remove_from_button_list(p, b);
|
||
|
_destroy_decal(d);
|
||
|
}
|
||
|
if (p->decal_list)
|
||
|
g_list_free(p->decal_list);
|
||
|
p->decal_list = NULL;
|
||
|
}
|
||
|
|
||
|
GkrellmDecal *
|
||
|
gkrellm_create_decal_pixmap(GkrellmPanel *p,
|
||
|
GdkPixmap *pixmap, GdkBitmap *mask,
|
||
|
gint depth, GkrellmStyle *style, gint x, gint y)
|
||
|
{
|
||
|
GtkWidget *top_win;
|
||
|
GkrellmMargin *m;
|
||
|
GkrellmDecal *d;
|
||
|
|
||
|
if (!pixmap)
|
||
|
return NULL;
|
||
|
top_win = gkrellm_get_top_window();
|
||
|
d = (GkrellmDecal *) g_new0(GkrellmDecal, 1);
|
||
|
if (p)
|
||
|
{
|
||
|
p->decal_list = g_list_append(p->decal_list, d);
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
}
|
||
|
d->panel = (gpointer) p;
|
||
|
|
||
|
gdk_drawable_get_size(pixmap, &d->w, &d->h);
|
||
|
if (depth > 0)
|
||
|
d->h /= depth;
|
||
|
if (d->h == 0)
|
||
|
d->h = 1;
|
||
|
|
||
|
d->x = x;
|
||
|
m = gkrellm_get_style_margins(style);
|
||
|
if (d->x < 0 && style)
|
||
|
{
|
||
|
if ( style->label_position < 50
|
||
|
&& style->label_position != GKRELLM_LABEL_NONE
|
||
|
)
|
||
|
d->x = _GK.chart_width - d->w - m->right;
|
||
|
else
|
||
|
d->x = m->left;
|
||
|
}
|
||
|
d->y = y;
|
||
|
if (d->y < 0)
|
||
|
d->y = m->top;
|
||
|
|
||
|
d->pixmap = pixmap;
|
||
|
d->mask = mask;
|
||
|
d->stencil = gdk_pixmap_new(top_win->window, d->w, d->h, 1);
|
||
|
|
||
|
d->value = -1; /* Force initial draw */
|
||
|
d->flags = 0;
|
||
|
d->state = DS_VISIBLE;
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
static GkrellmDecal *
|
||
|
_create_decal_text(GkrellmPanel *p, gchar *string,
|
||
|
GkrellmTextstyle *ts, GkrellmStyle *style,
|
||
|
gint x, gint y, gint w, gint h, gint y_ink, gboolean markup)
|
||
|
{
|
||
|
GtkWidget *top_win;
|
||
|
GkrellmMargin *m;
|
||
|
GkrellmDecal *d;
|
||
|
GkrellmText *tx;
|
||
|
gint width, height, baseline;
|
||
|
|
||
|
top_win = gkrellm_get_top_window();
|
||
|
d = (GkrellmDecal *) g_new0(GkrellmDecal, 1);
|
||
|
if (p)
|
||
|
{
|
||
|
p->decal_list = g_list_append(p->decal_list, d);
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
}
|
||
|
d->panel = (gpointer) p;
|
||
|
|
||
|
d->text_style = ts ? *ts : *gkrellm_meter_textstyle(0);
|
||
|
tx = g_new0(GkrellmText, 1);
|
||
|
d->text_list = g_list_append(d->text_list, tx);
|
||
|
gkrellm_dup_string(&tx->text, "");
|
||
|
tx->text_style = d->text_style;
|
||
|
|
||
|
if (string && *string)
|
||
|
{
|
||
|
if (markup)
|
||
|
gkrellm_text_markup_extents(d->text_style.font,
|
||
|
string, strlen(string),
|
||
|
&width, &height, &baseline, &d->y_ink);
|
||
|
else
|
||
|
gkrellm_text_extents(d->text_style.font,
|
||
|
string, strlen(string),
|
||
|
&width, &height, &baseline, &d->y_ink);
|
||
|
d->h = height + d->text_style.effect;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
width = 2;
|
||
|
d->h = h;
|
||
|
d->y_ink = y_ink;
|
||
|
}
|
||
|
if (d->h <= 0)
|
||
|
d->h = 2;
|
||
|
|
||
|
/* Width defaults to full chart width
|
||
|
| minus borders unless w > 0, or w == 0 to use string width.
|
||
|
*/
|
||
|
if (style)
|
||
|
{
|
||
|
m = gkrellm_get_style_margins(style);
|
||
|
if (w < 0)
|
||
|
d->w = _GK.chart_width - m->left - m->right;
|
||
|
else if (w == 0)
|
||
|
d->w = width + d->text_style.effect;
|
||
|
else
|
||
|
d->w = w;
|
||
|
|
||
|
d->x = (x >= 0) ? x : m->left;
|
||
|
|
||
|
d->y = y;
|
||
|
if (d->y < 0)
|
||
|
d->y = m->top;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (w < 0)
|
||
|
d->w = _GK.chart_width;
|
||
|
else if (w == 0)
|
||
|
d->w = width;
|
||
|
else
|
||
|
d->w = w;
|
||
|
d->x = x;
|
||
|
d->y = y;
|
||
|
}
|
||
|
if (d->w == 0)
|
||
|
d->w = 1;
|
||
|
d->pixmap = gdk_pixmap_new(top_win->window, d->w, d->h, -1);;
|
||
|
d->mask = NULL;
|
||
|
d->stencil = gdk_pixmap_new(top_win->window, d->w, d->h, 1);
|
||
|
|
||
|
d->value = -1; /* Force initial draw */
|
||
|
d->flags = DF_LOCAL_PIXMAPS;
|
||
|
d->state = DS_VISIBLE;
|
||
|
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
GkrellmDecal *
|
||
|
gkrellm_create_decal_text(GkrellmPanel *p, gchar *string,
|
||
|
GkrellmTextstyle *ts, GkrellmStyle *style,
|
||
|
gint x, gint y, gint w)
|
||
|
{
|
||
|
return _create_decal_text(p, string, ts, style, x, y, w, 0, 0, FALSE);
|
||
|
}
|
||
|
|
||
|
GkrellmDecal *
|
||
|
gkrellm_create_decal_text_markup(GkrellmPanel *p, gchar *string,
|
||
|
GkrellmTextstyle *ts, GkrellmStyle *style,
|
||
|
gint x, gint y, gint w)
|
||
|
{
|
||
|
return _create_decal_text(p, string, ts, style, x, y, w, 0, 0, TRUE);
|
||
|
}
|
||
|
|
||
|
GkrellmDecal *
|
||
|
gkrellm_create_decal_text_with_height(GkrellmPanel *p,
|
||
|
GkrellmTextstyle *ts, GkrellmStyle *style,
|
||
|
gint x, gint y, gint w, gint h, gint y_ink)
|
||
|
{
|
||
|
return _create_decal_text(p, NULL, ts, style, x, y, w, h, y_ink, FALSE);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_make_decal_invisible(GkrellmPanel *p, GkrellmDecal *d)
|
||
|
{
|
||
|
if (!p || !d || d->state == DS_INVISIBLE)
|
||
|
return;
|
||
|
d->state = DS_INVISIBLE;
|
||
|
d->modified = TRUE;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers(p);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_make_decal_visible(GkrellmPanel *p, GkrellmDecal *d)
|
||
|
{
|
||
|
if (!p || !d || d->state == DS_VISIBLE)
|
||
|
return;
|
||
|
d->state = DS_VISIBLE;
|
||
|
d->modified = TRUE;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers(p);
|
||
|
}
|
||
|
|
||
|
gint
|
||
|
gkrellm_is_decal_visible(GkrellmDecal *d)
|
||
|
{
|
||
|
if (!d)
|
||
|
return FALSE;
|
||
|
return (d->state == DS_VISIBLE) ? TRUE : FALSE;
|
||
|
}
|
||
|
|
||
|
/* ===================================================================== */
|
||
|
#define AUTO_HIDE_BUTTON 1
|
||
|
|
||
|
|
||
|
gboolean
|
||
|
gkrellm_in_decal(GkrellmDecal *d, GdkEventButton *ev)
|
||
|
{
|
||
|
if (!d || !ev)
|
||
|
return FALSE;
|
||
|
if ( ev->x >= d->x && ev->x < d->x + d->w
|
||
|
&& ev->y >= d->y && ev->y < d->y + d->h
|
||
|
)
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
set_button_index(GkrellmDecalbutton *b, gint index, gint do_draw)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
gkrellm_draw_decal_pixmap(b->panel, b->decal, index);
|
||
|
b->cur_index = index;
|
||
|
if (do_draw)
|
||
|
gkrellm_draw_panel_layers(b->panel);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_set_button_sensitive(GkrellmDecalbutton *b, gboolean sensitive)
|
||
|
{
|
||
|
if (b)
|
||
|
b->sensitive = sensitive;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_hide_button(GkrellmDecalbutton *b)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
b->sensitive = FALSE;
|
||
|
gkrellm_make_decal_invisible(b->panel, b->decal);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_show_button(GkrellmDecalbutton *b)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
b->sensitive = TRUE;
|
||
|
gkrellm_make_decal_visible(b->panel, b->decal);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
gkrellm_in_button(GkrellmDecalbutton *b, GdkEventButton *ev)
|
||
|
{
|
||
|
return gkrellm_in_decal(b->decal, ev);
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
cb_decal_button_press(GtkWidget *widget, GdkEventButton *ev, GkrellmPanel *p)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmDecalbutton *b;
|
||
|
gboolean stop_sig = FALSE;
|
||
|
|
||
|
if (ev->type != GDK_BUTTON_PRESS) /* I'm connected to "event" */
|
||
|
return FALSE;
|
||
|
for (list = p->button_list; list; list = list->next)
|
||
|
{
|
||
|
b = (GkrellmDecalbutton *) list->data;
|
||
|
if ( b->sensitive && (*(b->cb_in_button))(b, ev, b->in_button_data)
|
||
|
&& ( (b->cb_button_click && ev->button == 1)
|
||
|
|| (b->cb_button_right_click && ev->button == 3)
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
if (b->cur_index != b->pressed_index)
|
||
|
{
|
||
|
b->saved_index = b->cur_index;
|
||
|
set_button_index(b, b->pressed_index, 1);
|
||
|
}
|
||
|
stop_sig = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return stop_sig;
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
cb_decal_button_release(GtkWidget *widget, GdkEventButton *ev, GkrellmPanel *p)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmDecalbutton *b;
|
||
|
gboolean stop_sig = FALSE;
|
||
|
|
||
|
if (ev->type != GDK_BUTTON_RELEASE) /* I'm connected to "event" */
|
||
|
return FALSE;
|
||
|
for (list = p->button_list; list; list = list->next)
|
||
|
{
|
||
|
b = (GkrellmDecalbutton *) list->data;
|
||
|
if (b->cur_index == b->pressed_index)
|
||
|
{
|
||
|
set_button_index(b, b->saved_index, 1);
|
||
|
if ( (*(b->cb_in_button))(b, ev, b->in_button_data) )
|
||
|
{
|
||
|
if (b->cb_button_click && ev->button == 1)
|
||
|
(*(b->cb_button_click))(b, b->data);
|
||
|
else if (b->cb_button_right_click && ev->button == 3)
|
||
|
(*(b->cb_button_right_click))(b, b->right_data);
|
||
|
}
|
||
|
stop_sig = TRUE;
|
||
|
}
|
||
|
}
|
||
|
return stop_sig;
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
cb_decal_button_leave(GtkWidget *widget, GdkEventButton *ev, GkrellmPanel *p)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
if (ev->type != GDK_LEAVE_NOTIFY) /* I'm connected to "event" */
|
||
|
return FALSE;
|
||
|
for (list = p->button_list; list; list = list->next)
|
||
|
{
|
||
|
b = (GkrellmDecalbutton *) list->data;
|
||
|
if (b->type == AUTO_HIDE_BUTTON)
|
||
|
{
|
||
|
if (b->sensitive)
|
||
|
{
|
||
|
set_button_index(b, 0, 0);
|
||
|
b->decal->state = DS_INVISIBLE;
|
||
|
b->decal->modified = TRUE;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers(p);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (b->cur_index == b->pressed_index)
|
||
|
set_button_index(b, b->saved_index, 1);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
cb_decal_button_enter(GtkWidget *widget, GdkEventButton *ev, GkrellmPanel *p)
|
||
|
{
|
||
|
GList *list;
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
if (ev->type != GDK_ENTER_NOTIFY) /* I'm connected to "event" */
|
||
|
return FALSE;
|
||
|
for (list = p->button_list; list; list = list->next)
|
||
|
{
|
||
|
b = (GkrellmDecalbutton *) list->data;
|
||
|
if (b->type != AUTO_HIDE_BUTTON || ! b->sensitive)
|
||
|
continue;
|
||
|
b->decal->state = DS_VISIBLE;
|
||
|
set_button_index(b, 0, 0);
|
||
|
b->decal->modified = TRUE;
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
gkrellm_draw_panel_layers(b->panel);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_set_decal_button_index(GkrellmDecalbutton *b, gint index)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
if (b->cur_index == b->pressed_index)
|
||
|
b->saved_index = index; /* Throw away old save */
|
||
|
else
|
||
|
set_button_index(b, index, 0);
|
||
|
}
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_decal_is_button(GkrellmDecal *d)
|
||
|
{
|
||
|
GkrellmPanel *p;
|
||
|
GkrellmDecalbutton *b;
|
||
|
GList *list;
|
||
|
|
||
|
if ((p = (GkrellmPanel *) d->panel) == NULL)
|
||
|
return NULL;
|
||
|
for (list = p->button_list; list; list = list->next)
|
||
|
{
|
||
|
b = (GkrellmDecalbutton *) list->data;
|
||
|
if (b->decal == d)
|
||
|
return b;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_destroy_button(GkrellmDecalbutton *b)
|
||
|
{
|
||
|
GkrellmPanel *p;
|
||
|
|
||
|
if (!b)
|
||
|
return;
|
||
|
p = b->panel;
|
||
|
if (p && b->decal)
|
||
|
_remove_decal(p, b->decal);
|
||
|
if (b->decal)
|
||
|
_destroy_decal(b->decal);
|
||
|
remove_from_button_list(p, b);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
gkrellm_set_in_button_callback(GkrellmDecalbutton *b,
|
||
|
gint (*func)(), gpointer data)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
b->cb_in_button = func;
|
||
|
b->in_button_data = data;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_button_connect(GkrellmDecalbutton *b, void (*func)(), void *data)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
b->data = data;
|
||
|
b->cb_button_click = func;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_decal_button_right_connect(GkrellmDecalbutton *b,
|
||
|
void (*func)(), void *data)
|
||
|
{
|
||
|
if (!b)
|
||
|
return;
|
||
|
b->right_data = data;
|
||
|
b->cb_button_right_click = func;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gkrellm_panel_button_signals_connect(GkrellmPanel *p)
|
||
|
{
|
||
|
/* I want DecalButton event handlers to be called before any monitor
|
||
|
| handlers, but DecalButtons will be recreated at theme changes and
|
||
|
| thus its handlers will be after panel handlers. So, connect to
|
||
|
| "event" which is called first, and check for the right event in
|
||
|
| the callback.
|
||
|
| There is only one event handler per signal per panel. Buttons do
|
||
|
| not have their own event box so they may be efficiently animated.
|
||
|
*/
|
||
|
if ( !p || p->button_signals_connected
|
||
|
|| !p->button_list || !p->drawing_area
|
||
|
)
|
||
|
return;
|
||
|
p->id_press = g_signal_connect(G_OBJECT(p->drawing_area),
|
||
|
"event", G_CALLBACK(cb_decal_button_press), p);
|
||
|
p->id_release = g_signal_connect(G_OBJECT(p->drawing_area),
|
||
|
"event", G_CALLBACK(cb_decal_button_release), p);
|
||
|
p->id_enter = g_signal_connect(G_OBJECT(p->drawing_area),
|
||
|
"event", G_CALLBACK(cb_decal_button_enter), p);
|
||
|
p->id_leave = g_signal_connect(G_OBJECT(p->drawing_area),
|
||
|
"event", G_CALLBACK(cb_decal_button_leave), p);
|
||
|
p->button_signals_connected = TRUE;
|
||
|
}
|
||
|
|
||
|
/* Make an existing decal into a decal button. The decal should already
|
||
|
| be created and be in the panel's decal list.
|
||
|
*/
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_make_decal_button(GkrellmPanel *p, GkrellmDecal *d, void (*func)(),
|
||
|
void *data, gint cur_index, gint pressed_index)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
if (!p || !d)
|
||
|
return NULL;
|
||
|
b = g_new0(GkrellmDecalbutton, 1);
|
||
|
b->panel = p;
|
||
|
b->decal = d;
|
||
|
b->pressed_index = pressed_index;
|
||
|
b->data = data;
|
||
|
b->cb_button_click = func;
|
||
|
b->cb_in_button = gkrellm_in_button;
|
||
|
b->in_button_data = NULL;
|
||
|
b->sensitive = TRUE;
|
||
|
set_button_index(b, cur_index, 0);
|
||
|
|
||
|
p->button_list = g_list_append(p->button_list, b);
|
||
|
gkrellm_panel_button_signals_connect(p);
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_make_overlay_button(GkrellmPanel *p, void (*func)(), void *data,
|
||
|
gint x, gint y, gint w, gint h,
|
||
|
GkrellmPiximage *normal_piximage,
|
||
|
GkrellmPiximage *pressed_piximage)
|
||
|
{
|
||
|
GtkWidget *top_win;
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmDecal *d;
|
||
|
GdkPixmap *pm = NULL, *pixmap;
|
||
|
GdkBitmap *m = NULL, *mask;
|
||
|
|
||
|
if (!p)
|
||
|
return NULL;
|
||
|
top_win = gkrellm_get_top_window();
|
||
|
if (x < 0)
|
||
|
{
|
||
|
w -= x;
|
||
|
x = 0;
|
||
|
}
|
||
|
if (y < 0)
|
||
|
{
|
||
|
h -= y;
|
||
|
y = 0;
|
||
|
}
|
||
|
if (x + w > _GK.chart_width)
|
||
|
w = _GK.chart_width - x;
|
||
|
if (p->h > 0 && y + h > p->h)
|
||
|
h = p->h - y;
|
||
|
if (h < 2)
|
||
|
h = 2;
|
||
|
if (w < 4)
|
||
|
w = 4;
|
||
|
|
||
|
pixmap = gdk_pixmap_new(top_win->window, w, 2 * h, -1);
|
||
|
mask = gdk_pixmap_new(top_win->window, w, 2 * h, 1);
|
||
|
|
||
|
if (normal_piximage && pressed_piximage)
|
||
|
{
|
||
|
gkrellm_scale_piximage_to_pixmap(normal_piximage, &pm, &m, w, h);
|
||
|
gdk_draw_drawable(pixmap, _GK.draw1_GC, pm, 0, 0, 0, 0, w, h);
|
||
|
if (m)
|
||
|
gdk_draw_drawable(mask, _GK.bit1_GC, m, 0, 0, 0, 0, w, h);
|
||
|
else
|
||
|
gdk_draw_rectangle(mask, _GK.bit1_GC, TRUE, 0, 0, w, h);
|
||
|
gkrellm_free_pixmap(&pm);
|
||
|
gkrellm_free_bitmap(&m);
|
||
|
|
||
|
gkrellm_scale_piximage_to_pixmap(pressed_piximage, &pm, &m, w, h);
|
||
|
gdk_draw_drawable(pixmap, _GK.draw1_GC, pm, 0, 0, 0, h, w, h);
|
||
|
if (m)
|
||
|
gdk_draw_drawable(mask, _GK.bit1_GC, m, 0, 0, 0, h, w, h);
|
||
|
else
|
||
|
gdk_draw_rectangle(mask, _GK.bit1_GC, TRUE, 0, h, w, h);
|
||
|
gkrellm_free_pixmap(&pm);
|
||
|
gkrellm_free_bitmap(&m);
|
||
|
}
|
||
|
else /* Make a default frame. */
|
||
|
{
|
||
|
GdkColor gray0, gray1;
|
||
|
GdkColormap *cmap;
|
||
|
|
||
|
cmap = gdk_colormap_get_system();
|
||
|
gdk_color_parse("gray65", &gray0);
|
||
|
gdk_color_parse("gray100", &gray1);
|
||
|
gdk_colormap_alloc_color(cmap, &gray0, FALSE, TRUE);
|
||
|
gdk_colormap_alloc_color(cmap, &gray1, FALSE, TRUE);
|
||
|
|
||
|
gdk_gc_set_foreground(_GK.draw1_GC, &gray1);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, 0, w - 1, 0);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, 0, 0, h - 1);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, 2 * h - 1, w - 1, 2 * h - 1);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, w - 1, 2 * h - 1, w - 1, h);
|
||
|
|
||
|
gdk_gc_set_foreground(_GK.draw1_GC, &gray0);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, h - 1, w - 1, h - 1);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, w - 1, h - 1, w - 1, 0);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, h, w - 1, h);
|
||
|
gdk_draw_line(pixmap, _GK.draw1_GC, 0, h, 0, 2 * h - 1);
|
||
|
|
||
|
gdk_draw_rectangle(mask, _GK.bit1_GC, TRUE, 0, 0, w, 2 * h);
|
||
|
gdk_draw_rectangle(mask, _GK.bit0_GC, TRUE, 1, 1, w - 2, h - 2);
|
||
|
gdk_draw_rectangle(mask, _GK.bit0_GC, TRUE, 1, h + 1, w - 2, h - 2);
|
||
|
|
||
|
gdk_colormap_free_colors(cmap, &gray0, 1);
|
||
|
gdk_colormap_free_colors(cmap, &gray1, 1);
|
||
|
}
|
||
|
|
||
|
d = gkrellm_create_decal_pixmap(p, pixmap, mask, 2, NULL, x, y);
|
||
|
d->flags |= (DF_LOCAL_PIXMAPS | DF_OVERLAY_PIXMAPS);
|
||
|
d->state = DS_INVISIBLE;
|
||
|
|
||
|
b = gkrellm_make_decal_button(p, d, func, data, 0, 1);
|
||
|
b->type = AUTO_HIDE_BUTTON;
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_put_decal_in_panel_button(GkrellmPanel *p, GkrellmDecal *d,
|
||
|
void (*func)(), void *data, GkrellmMargin *margin_pad)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmBorder *border;
|
||
|
GkrellmMargin *margin;
|
||
|
gint x, y, w, h, a;
|
||
|
|
||
|
if (!p || !d)
|
||
|
return NULL;
|
||
|
border = &_GK.button_panel_border;
|
||
|
margin = margin_pad ? margin_pad : &zero_margin;
|
||
|
|
||
|
x = d->x - border->left - margin->left;
|
||
|
a = d->x + d->w + border->right + margin->right;
|
||
|
w = a - x;
|
||
|
|
||
|
y = d->y - border->top - margin->top;
|
||
|
a = d->y + d->h + border->bottom + margin->bottom;
|
||
|
h = a - y;
|
||
|
|
||
|
b = gkrellm_make_overlay_button(p, func, data, x, y, w, h,
|
||
|
_GK.button_panel_out_piximage, _GK.button_panel_in_piximage);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_put_decal_in_meter_button(GkrellmPanel *p, GkrellmDecal *d,
|
||
|
void (*func)(), void *data, GkrellmMargin *margin_pad)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmBorder *border;
|
||
|
GkrellmMargin *margin;
|
||
|
gint x, y, w, h, a;
|
||
|
|
||
|
if (!p || !d)
|
||
|
return NULL;
|
||
|
border = &_GK.button_meter_border;
|
||
|
margin = margin_pad ? margin_pad : &zero_margin;
|
||
|
|
||
|
x = d->x - border->left - margin->left;
|
||
|
a = d->x + d->w + border->right + margin->right;
|
||
|
w = a - x;
|
||
|
|
||
|
y = d->y - border->top - margin->top;
|
||
|
a = d->y + d->h + border->bottom + margin->bottom;
|
||
|
h = a - y;
|
||
|
|
||
|
b = gkrellm_make_overlay_button(p, func, data, x, y, w, h,
|
||
|
_GK.button_meter_out_piximage, _GK.button_meter_in_piximage);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
static GkrellmDecalbutton *
|
||
|
put_label_in_button(GkrellmPanel *p, void (*func)(), void *data, gint type,
|
||
|
gint pad)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmLabel *lbl;
|
||
|
GkrellmMargin *m;
|
||
|
GkrellmPiximage *normal_piximage, *pressed_piximage;
|
||
|
GkrellmBorder *style_border, *fr_border;
|
||
|
gint x, y, w, h;
|
||
|
|
||
|
if (!p || p->h == 0)
|
||
|
return NULL;
|
||
|
|
||
|
fr_border = (type == METER_PANEL_TYPE) ? &_GK.button_meter_border
|
||
|
: &_GK.button_panel_border;
|
||
|
normal_piximage = (type == METER_PANEL_TYPE)
|
||
|
? _GK.button_meter_out_piximage : _GK.button_panel_out_piximage;
|
||
|
pressed_piximage = (type == METER_PANEL_TYPE)
|
||
|
? _GK.button_meter_in_piximage : _GK.button_panel_in_piximage;
|
||
|
|
||
|
/* If no panel label, put the whole panel in the button.
|
||
|
*/
|
||
|
if ((lbl = p->label) == NULL || lbl->string == NULL || lbl->position < 0)
|
||
|
{
|
||
|
m = gkrellm_get_style_margins(p->style);
|
||
|
style_border = p->style ? &p->style->border : &zero_border;
|
||
|
x = 0 + m->left;
|
||
|
y = 0 + style_border->top - fr_border->top;
|
||
|
w = p->w - x - m->right;
|
||
|
h = p->h - y - style_border->bottom + fr_border->bottom;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x = lbl->x_panel - fr_border->left - pad;
|
||
|
y = lbl->y_panel - fr_border->top;
|
||
|
w = lbl->width + fr_border->left + fr_border->right + 2 * pad;
|
||
|
h = lbl->height + (p->textstyle->effect ? 1 : 0)
|
||
|
+ fr_border->top + fr_border->bottom;
|
||
|
}
|
||
|
b = gkrellm_make_overlay_button(p, func, data, x, y, w, h,
|
||
|
normal_piximage, pressed_piximage);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_put_label_in_panel_button(GkrellmPanel *p, void (*func)(), void *data,
|
||
|
gint pad)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
b = put_label_in_button(p, func, data, CHART_PANEL_TYPE, pad);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_put_label_in_meter_button(GkrellmPanel *p, void (*func)(), void *data,
|
||
|
gint pad)
|
||
|
{
|
||
|
GkrellmDecalbutton *b;
|
||
|
|
||
|
b = put_label_in_button(p, func, data, METER_PANEL_TYPE, pad);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
GkrellmDecalbutton *
|
||
|
gkrellm_make_scaled_button(GkrellmPanel *p, GkrellmPiximage *im,
|
||
|
void (*func)(), void *data,
|
||
|
gboolean auto_hide, gboolean set_default_border,
|
||
|
gint depth, gint cur_index, gint pressed_index,
|
||
|
gint x, gint y, gint w, gint h)
|
||
|
{
|
||
|
GtkWidget *top_win;
|
||
|
GkrellmDecalbutton *b;
|
||
|
GkrellmDecal *d;
|
||
|
GkrellmBorder *bdr;
|
||
|
GdkPixmap *pixmap;
|
||
|
GdkBitmap *mask;
|
||
|
|
||
|
if (!p)
|
||
|
return NULL;
|
||
|
if (!im)
|
||
|
{
|
||
|
im = _GK.decal_button_piximage;
|
||
|
depth = 2;
|
||
|
cur_index = 0;
|
||
|
pressed_index = 1;
|
||
|
}
|
||
|
if (depth < 2)
|
||
|
depth = 2;
|
||
|
if (w < 0)
|
||
|
w = gkrellm_chart_width();
|
||
|
else
|
||
|
{
|
||
|
if (w == 0)
|
||
|
w = gdk_pixbuf_get_width(im->pixbuf);
|
||
|
if ((w = w * _GK.theme_scale / 100) < 2)
|
||
|
w = 2;
|
||
|
}
|
||
|
|
||
|
if (h < 0)
|
||
|
h = p->h;
|
||
|
else
|
||
|
{
|
||
|
if (h == 0)
|
||
|
h = gdk_pixbuf_get_height(im->pixbuf) / depth;
|
||
|
if ((h = h * _GK.theme_scale / 100) < 2)
|
||
|
h = 2;
|
||
|
}
|
||
|
|
||
|
top_win = gkrellm_get_top_window();
|
||
|
pixmap = gdk_pixmap_new(top_win->window, w, depth * h, -1);
|
||
|
mask = gdk_pixmap_new(top_win->window, w, depth * h, 1);
|
||
|
if (set_default_border)
|
||
|
{
|
||
|
bdr = &im->border;
|
||
|
bdr->left = bdr->right = bdr->top = bdr->bottom = 1;
|
||
|
}
|
||
|
gkrellm_scale_piximage_to_pixmap(im, &pixmap, &mask, w, depth * h);
|
||
|
d = gkrellm_create_decal_pixmap(p, pixmap, mask, depth, NULL, x, y);
|
||
|
d->flags |= DF_LOCAL_PIXMAPS;
|
||
|
b = gkrellm_make_decal_button(p, d, func, data, cur_index, pressed_index);
|
||
|
if (auto_hide)
|
||
|
{
|
||
|
d->state = DS_INVISIBLE;
|
||
|
b->type = AUTO_HIDE_BUTTON;
|
||
|
}
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
GkrellmDecal *
|
||
|
gkrellm_make_scaled_decal_pixmap(GkrellmPanel *p, GkrellmPiximage *im,
|
||
|
GkrellmStyle *style, gint depth,
|
||
|
gint x, gint y, gint w, gint h)
|
||
|
{
|
||
|
GtkWidget *top_win;
|
||
|
GdkPixmap *pixmap;
|
||
|
GdkBitmap *mask;
|
||
|
GkrellmMargin *m;
|
||
|
GkrellmDecal *d;
|
||
|
|
||
|
if (!im)
|
||
|
return NULL;
|
||
|
top_win = gkrellm_get_top_window();
|
||
|
d = (GkrellmDecal *) g_new0(GkrellmDecal, 1);
|
||
|
if (p)
|
||
|
{
|
||
|
p->decal_list = g_list_append(p->decal_list, d);
|
||
|
p->need_decal_overlap_check = TRUE;
|
||
|
}
|
||
|
d->panel = (gpointer) p;
|
||
|
|
||
|
if (depth < 1)
|
||
|
depth = 1;
|
||
|
|
||
|
if ( w < 1
|
||
|
&& (w = gdk_pixbuf_get_width(im->pixbuf) * _GK.theme_scale / 100) < 1
|
||
|
)
|
||
|
w = 1;
|
||
|
d->w = w;
|
||
|
|
||
|
if (h < 1)
|
||
|
h = gdk_pixbuf_get_height(im->pixbuf) / depth * _GK.theme_scale / 100;
|
||
|
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
d->h = h;
|
||
|
|
||
|
pixmap = gdk_pixmap_new(top_win->window, d->w, d->h * depth, -1);
|
||
|
mask = gdk_pixmap_new(top_win->window, d->w, d->h * depth, 1);
|
||
|
gkrellm_scale_piximage_to_pixmap(im, &pixmap, &mask, d->w, d->h * depth);
|
||
|
|
||
|
d->x = x;
|
||
|
m = gkrellm_get_style_margins(style);
|
||
|
if (d->x < 0 && style)
|
||
|
{
|
||
|
if ( style->label_position < 50
|
||
|
&& style->label_position != GKRELLM_LABEL_NONE
|
||
|
)
|
||
|
d->x = _GK.chart_width - d->w - m->right;
|
||
|
else
|
||
|
d->x = m->left;
|
||
|
}
|
||
|
d->y = y;
|
||
|
if (d->y < 0)
|
||
|
d->y = m->top;
|
||
|
|
||
|
d->pixmap = pixmap;
|
||
|
d->mask = mask;
|
||
|
d->stencil = gdk_pixmap_new(top_win->window, d->w, d->h, 1);
|
||
|
|
||
|
d->value = -1; /* Force initial draw */
|
||
|
d->flags = DF_LOCAL_PIXMAPS;
|
||
|
d->state = DS_VISIBLE;
|
||
|
return d;
|
||
|
}
|