Add list widget + cleanups

This commit is contained in:
Matthew Allum 2005-04-07 22:46:43 +00:00
parent 668890821f
commit f016f09792
14 changed files with 619 additions and 484 deletions

View File

@ -1,3 +1,27 @@
2005-04-07 mallum,,, <mallum@openedhand.com>
* Makefile:
* cltr-events.c: (cltr_main_loop):
* cltr-list.c:
* cltr-list.h:
Add list widget
* cltr-photo-grid.c: (cltr_photo_grid_cell_new),
(cltr_photo_grid_append_cell), (ctrl_photo_grid_cell_to_coords),
(ctrl_photo_grid_get_zoomed_coords), (cltr_photo_grid_idle_cb),
(cltr_photo_grid_navigate), (cltr_photo_grid_activate_cell),
(cltr_photo_grid_update_visual_state), (cltr_photo_grid_paint),
(cltr_photo_grid_show), (cltr_photo_grid_new):
* cltr-texture.c:
* cltr-widget.c:
* cltr-window.c: (cltr_window_new), (cltr_window_show),
(cltr_window_handle_xevent):
* cltr-window.h:
* cltr.c: (main):
* cltr.h:
* pixbuf.c: (pixbuf_copy):
* pixbuf.h:
Cleanups
2005-04-03 mallum,,, <mallum@openedhand.com>
* Makefile:

View File

@ -10,7 +10,9 @@ OBJS=cltr.o pixbuf.o util.o fonts.o \
cltr-widget.o \
cltr-events.o \
cltr-window.o \
cltr-photo-grid.o
cltr-photo-grid.o \
cltr-list.o \
cltr-scratch.o
# cltr-photo-grid.o
@ -24,7 +26,9 @@ $(OBJS): pixbuf.h util.h fonts.h \
cltr-texture.h \
cltr-widget.h \
cltr-window.h \
cltr-photo-grid.h
cltr-photo-grid.h \
cltr-list.h \
cltr-scratch.h
#cltr-photo-grid.h

View File

@ -160,10 +160,15 @@ cltr_main_loop()
CltrWidget *widget = NULL;
CltrWindow *win = CLTR_WINDOW(ctx->window);
while ((widget = g_queue_pop_head(ctx->internal_event_q)) != NULL)
{
cltr_widget_paint(widget);
}
/* Empty the queue */
while (g_queue_pop_head(ctx->internal_event_q) != NULL) ;
/* Repaint everything visible from window down - URG.
* GL workings make it difficult to paint single part with
* layering etc..
* Is this really bad ? time will tell...
*/
cltr_widget_paint(CLTR_WIDGET(win));
/* Swap Buffers */
glXSwapBuffers(ctx->xdpy, cltr_window_xwin(win));

View File

@ -1,349 +1,301 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "cltr-list.h"
#include "cltr-private.h"
#include <X11/Xlib.h>
#define ANIM_FPS 200
#define FPS_TO_TIMEOUT(t) (1000/(t))
#include <GL/glx.h>
#include <GL/gl.h>
#include "pixbuf.h"
#include "fonts.h"
#define TEX_W 1024 /* must be > than frame_w & power of 2 */
#define TEX_H 1024
/*
*
*/
#define WINW 640
#define WINH 480
#define NBOXITEMS 10
#define NUMRECTS 4
#define MAXSCALE 2
#define MAXDIST (WINH)
#define MAXH (WINH/NUMRECTS)
#define MAXW (WINW - 20)
#ifndef ABS
#define ABS(a) ((a > 0) ? (a) : -1 * (a))
#endif
typedef struct TableWidget TableWidget;
typedef struct TableWidgetCell TableWidgetCell;
int ScrollDir = 1;
struct TableWidget
typedef struct CltrListCell
{
int x,y,width,height;
TableWidgetCell *cells, *active_cell;
int active_cell_y;
CltrRect rect;
Pixbuf *pixb;
CltrTexture *texture;
} CltrListCell;
struct CltrList
{
CltrWidget widget;
GList *cells, *active_cell;
int active_cell_y;
int cell_height;
int cell_width;
CltrListState state;
int scroll_dir;
};
struct TableWidgetCell
static void
cltr_list_show(CltrWidget *widget);
static gboolean
cltr_list_handle_xevent (CltrWidget *widget, XEvent *xev);
static void
cltr_list_paint(CltrWidget *widget);
static float
distfunc(CltrList *list, int d)
{
XRectangle rect;
TableWidgetCell *next, *prev;
};
Display *xdpy;
Window xwin;
XEvent xevent;
GC xgc;
Pixbuf *pix, *pix_orig;
float
distfunc(TableWidget *table, int d)
{
/* printf("returning %f\n", (exp((float)d/MAXDIST)/exp(1.0))); */
int maxdist = table->height;
int maxdist = list->widget.height;
d = (maxdist-ABS(d)) ;
return ( exp( (float)d/maxdist * 2.0 ) / exp(2.0) );
}
TableWidgetCell*
table_cell_new()
CltrListCell*
cltr_list_cell_new(CltrList *list)
{
TableWidgetCell *cell = NULL;
CltrListCell *cell = NULL;
ClutterFont *font;
gchar buf[24];
PixbufPixel pixel = { 255, 20, 20, 255 };
cell = malloc(sizeof(TableWidgetCell));
memset(cell, 0, sizeof(TableWidgetCell));
font = font_new ("Sans Bold 96");
cell = g_malloc0(sizeof(CltrListCell));
cell->pixb = pixbuf_new(list->cell_width, list->cell_height);
pixbuf_fill_rect(cell->pixb, 0, 0, -1, -1, &pixel);
g_snprintf(&buf[0], 24, "%i %i %i", rand()%10, rand()%10, rand()%10);
font_draw(font, cell->pixb, buf, 10, 10);
cell->texture = cltr_texture_new(cell->pixb);
return cell;
}
TableWidget*
table_new(int n_items)
CltrWidget*
cltr_list_new(int width,
int height,
int cell_width,
int cell_height)
{
TableWidget *table = NULL;
TableWidgetCell *last = NULL, *cell = NULL;
int i;
CltrList *list;
table = malloc(sizeof(TableWidget));
memset(table, 0, sizeof(TableWidget));
list = g_malloc0(sizeof(CltrList));
list->widget.width = width;
list->widget.height = height;
list->widget.show = cltr_list_show;
list->widget.paint = cltr_list_paint;
list->cell_height = cell_height; /* maximum */
list->cell_width = cell_width; /* maximum */
table->width = WINW;
table->height = WINH;
list->widget.xevent_handler = cltr_list_handle_xevent;
table->active_cell_y = 100;
return CLTR_WIDGET(list);
}
static void
cltr_list_show(CltrWidget *widget)
{
CltrList *list = CLTR_LIST(widget);
int n_items = 50, i;
list->active_cell_y = 100;
for (i=0; i<n_items; i++)
{
cell = table_cell_new();
if (last)
list->cells = g_list_append(list->cells, cltr_list_cell_new(list));
}
list->active_cell = g_list_first(list->cells);
cltr_widget_queue_paint(widget);
}
static gboolean
cltr_list_handle_xevent (CltrWidget *widget, XEvent *xev)
{
CltrList *list = CLTR_LIST(widget);
switch (xev->type)
{
case KeyPress:
{
KeySym kc;
kc = XKeycodeToKeysym(xev->xkey.display, xev->xkey.keycode, 0);
switch (kc)
{
case XK_Up:
case XK_KP_Up:
cltr_list_scroll_up(list);
break;
case XK_Down:
case XK_KP_Down:
cltr_list_scroll_down(list);
break;
case XK_Return:
CLTR_DBG("Return");
break;
case XK_Left:
case XK_KP_Left:
case XK_Right:
case XK_KP_Right:
default:
CLTR_DBG("unhandled keysym");
}
}
break;
}
return TRUE;
}
static void
cltr_list_animate(CltrList *list)
{
GList *cell_item = NULL;
CltrListCell *next_active = NULL, *cell_top = NULL;
cell_top = (CltrListCell *)g_list_nth_data(list->cells, 0);
if (list->state == CLTR_LIST_STATE_SCROLL_UP)
{
cell_item = g_list_previous(list->active_cell);
if (!cell_item)
{
last->next = cell;
cell->prev = last;
list->state = CLTR_LIST_STATE_BROWSE;
return;
}
next_active = (CltrListCell *)cell_item->data;
if (next_active->rect.y < list->active_cell_y)
{
cell_top->rect.y += 2;
}
else
table->cells = table->active_cell = cell;
last = cell;
}
table->cells->rect.y = table->active_cell_y;
return table;
}
void
table_redraw(TableWidget *table)
{
TableWidgetCell *cur = table->cells;
int last = table->cells->rect.y;
glClearColor( 0.0, 0.0, 0.0, 1.0);
glClear (GL_COLOR_BUFFER_BIT);
while (cur)
{
cur->rect.y = last;
if (cur->rect.y+cur->rect.height >= 0)
{
cur->rect.width = MAXW * distfunc(table, cur->rect.y - table->active_cell_y);
cur->rect.height = MAXH * distfunc(table, cur->rect.y - table->active_cell_y);
cur->rect.x = (WINW - cur->rect.width)/6;
list->active_cell = cell_item;
list->state = CLTR_LIST_STATE_BROWSE;
}
}
else if (list->state == CLTR_LIST_STATE_SCROLL_DOWN)
{
cell_item = g_list_next(list->active_cell);
last = cur->rect.y + cur->rect.height;
if (last > 0 && cur->rect.y < WINH) /* crappy clip */
if (!cell_item)
{
float tx = 1.0, ty = 1.0, sx, sy;
int x1 = cur->rect.x, x2 = cur->rect.x + cur->rect.width;
int y1 = cur->rect.y, y2 = cur->rect.y + cur->rect.height;
tx = (float) pix->width / TEX_W;
ty = (float) pix->height / TEX_H;
glBegin (GL_QUADS);
glTexCoord2f (tx, ty); glVertex2i (x2, y2);
glTexCoord2f (0, ty); glVertex2i (x1, y2);
glTexCoord2f (0, 0); glVertex2i (x1, y1);
glTexCoord2f (tx, 0); glVertex2i (x2, y1);
glEnd ();
/* draw with X primitives
XDrawRectangle(xdpy, xwin, xgc,
cur->rect.x, cur->rect.y,
cur->rect.width, cur->rect.height);
XDrawLine(xdpy, xwin, xgc,
cur->rect.x, cur->rect.y,
cur->rect.x + cur->rect.width,
cur->rect.y + cur->rect.height);
*/
list->state = CLTR_LIST_STATE_BROWSE;
return;
}
next_active = (CltrListCell *)cell_item->data;
if (next_active->rect.y > list->active_cell_y)
{
cell_top->rect.y -= 2;
}
else
{
list->active_cell = cell_item;
list->state = CLTR_LIST_STATE_BROWSE;
}
cur = cur->next;
}
glXSwapBuffers(xdpy, xwin);
}
void
table_scroll_down(TableWidget *table)
gboolean
cltr_list_timeout_cb(gpointer data)
{
TableWidgetCell *next_active = table->active_cell->next;
CltrList *list = (CltrList *)data;
if (!next_active)
cltr_list_animate(list);
cltr_widget_queue_paint(CLTR_WIDGET(list));
switch(list->state)
{
ScrollDir = 0;
return;
case CLTR_LIST_STATE_SCROLL_UP:
case CLTR_LIST_STATE_SCROLL_DOWN:
return TRUE;
case CLTR_LIST_STATE_LOADING:
case CLTR_LIST_STATE_LOAD_COMPLETE:
case CLTR_LIST_STATE_BROWSE:
default:
return FALSE;
}
while (next_active->rect.y > table->active_cell_y)
{
table->cells->rect.y--;
table_redraw(table);
}
table->active_cell = next_active;
}
void
table_scroll_up(TableWidget *table)
static void
cltr_list_paint(CltrWidget *widget)
{
TableWidgetCell *next_active = table->active_cell->prev;
GList *cell_item = NULL;
CltrList *list = CLTR_LIST(widget);
CltrListCell *cell = NULL;
if (!next_active)
return;
int last;
while (next_active->rect.y < table->active_cell_y)
{
table->cells->rect.y++;
table_redraw(table);
}
cell_item = g_list_first(list->cells);
cell = (CltrListCell *)cell_item->data;
last = cell->rect.y;
table->active_cell = next_active;
}
glPushMatrix();
glEnable(GL_TEXTURE_2D);
int
main(int argc, char **argv)
{
TableWidget *table;
int i, j, last, offset=0;
XGCValues gcvals;
ClutterFont *font = NULL;
/* GL */
GLXContext context; /* OpenGL context */
GLubyte *texture_data = NULL;
XVisualInfo *vinfo;
static int attributes[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
0
};
if ((xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
{
fprintf(stderr, "%s: Cant open display\n", argv[0]);
exit(-1);
}
if ((vinfo = glXChooseVisual(xdpy, DefaultScreen(xdpy), attributes)) == NULL)
{
fprintf(stderr, "Unable to find visual\n");
exit(-1);
}
xwin = XCreateSimpleWindow(xdpy,
RootWindow(xdpy, DefaultScreen(xdpy)),
0, 0,
WINW, WINH,
0, 0, WhitePixel(xdpy, DefaultScreen(xdpy)));
gcvals.foreground = BlackPixel(xdpy, DefaultScreen(xdpy));
gcvals.background = WhitePixel(xdpy, DefaultScreen(xdpy));
gcvals.line_width = 1;
xgc = XCreateGC(xdpy, RootWindow(xdpy, DefaultScreen(xdpy)),
GCForeground|GCBackground|GCLineWidth,
&gcvals);
context = glXCreateContext(xdpy, vinfo, 0, True);
glXMakeCurrent(xdpy, xwin, context);
glViewport (0, 0, WINW, WINH);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glClearColor (0, 0, 0, 0);
glClearDepth (1.0f);
glDisable (GL_DEPTH_TEST);
glDepthMask (GL_FALSE);
glDisable (GL_CULL_FACE);
glShadeModel (GL_FLAT);
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, WINW, WINH, 0, -1, 1);
glEnable (GL_TEXTURE_2D);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
texture_data = malloc (TEX_W * TEX_H * 4);
for (i=0; i < (TEX_W * TEX_H * 4); i++)
texture_data[i] = rand()%255;
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
TEX_W, TEX_H,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
pix_orig = pixbuf_new_from_file(argv[1]);
if (!pix_orig)
while (cell_item)
{
fprintf(stderr, "image load failed\n");
exit(-1);
}
cell = (CltrListCell *)cell_item->data;
pix = pixbuf_scale_down(pix_orig, 100, 100);
/*
font = font_new("Sans Bold 48");
font_draw(font, pix, "Hello World\nlove matmoo", 0, 0);
*/
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
(GLsizei)pix->width,
(GLsizei)pix->height,
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
pix->data);
table = table_new(NBOXITEMS);
table_redraw(table);
XMapWindow(xdpy, xwin);
for (;;)
{
XEvent ev;
// XNextEvent(xdpy, &ev);
// XClearWindow(xdpy, xwin);
table_redraw(table);
ScrollDir ? table_scroll_down(table) : table_scroll_up(table);
cell->rect.y = last;
if (cell->rect.y + cell->rect.height >= 0)
{
cell->rect.width = list->cell_width * distfunc(list, cell->rect.y - list->active_cell_y);
cell->rect.height = list->cell_height * distfunc(list, cell->rect.y - list->active_cell_y);
/* cell->rect.x = (list->widget.width - cell->rect.width) / 6; */
cell->rect.x = 0;
}
// scroll_to_next();
XFlush(xdpy);
sleep(1);
last = cell->rect.y + cell->rect.height;
if (last > 0 && cell->rect.y < list->widget.width) /* crappy clip */
{
cltr_texture_render_to_gl_quad(cell->texture,
cltr_rect_x1(cell->rect),
cltr_rect_y1(cell->rect),
cltr_rect_x2(cell->rect),
cltr_rect_y2(cell->rect));
}
cell_item = g_list_next(cell_item);
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void
cltr_list_scroll_down(CltrList *list)
{
list->state = CLTR_LIST_STATE_SCROLL_DOWN;
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_list_timeout_cb, list);
}
void
cltr_list_scroll_up(CltrList *list)
{
list->state = CLTR_LIST_STATE_SCROLL_UP;
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_list_timeout_cb, list);
}

34
cltr-list.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _HAVE_CLTR_LIST_H
#define _HAVE_CLTR_LIST_H
#include "cltr.h"
typedef struct CltrList CltrList;
#define CLTR_LIST(w) ((CltrList*)(w))
typedef enum CltrListState
{
CLTR_LIST_STATE_LOADING ,
CLTR_LIST_STATE_LOAD_COMPLETE ,
CLTR_LIST_STATE_BROWSE ,
CLTR_LIST_STATE_SCROLL_UP ,
CLTR_LIST_STATE_SCROLL_DOWN
}
CltrListState;
CltrWidget*
cltr_list_new(int width,
int height,
int cell_width,
int cell_height);
void
cltr_list_scroll_down(CltrList *list);
void
cltr_list_scroll_up(CltrList *list);
#endif

View File

@ -43,7 +43,7 @@ struct CltrPhotoGrid
int n_rows;
int n_cols;
int row_offset; /* for scrolling */
int row_offset; /* where is the first visible row. */
int cell_width;
int cell_height;
@ -53,18 +53,22 @@ struct CltrPhotoGrid
/* animation / zoom etc stuff */
int anim_n_steps, anim_step;
/* current anim frame position */
int anim_n_steps, anim_step;
float zoom_min, zoom_max, zoom_step;
/* start / end points for animations */
float zoom_min, zoom_max, zoom_step;
float view_min_x, view_max_x, view_min_y, view_max_y;
float scroll_dist;
/* Values calucated from above for setting up the GL tranforms and 'view' */
float paint_trans_x, paint_trans_y, paint_zoom;
int paint_start_y;
GList *paint_cell_item;
float view_min_x, view_max_x, view_min_y, view_max_y;
float scroll_dist;
CltrPhotoGridState state;
int scroll_state, scroll_step; /* urg */
};
static void
@ -76,6 +80,9 @@ cltr_photo_grid_handle_xevent (CltrWidget *widget, XEvent *xev);
static void
cltr_photo_grid_show(CltrWidget *widget);
static void
cltr_photo_grid_update_visual_state(CltrPhotoGrid *grid);
/* this likely shouldn'y go here */
static GMutex *Mutex_GRID = NULL;
@ -181,8 +188,6 @@ cltr_photo_grid_append_cell(CltrPhotoGrid *grid,
CltrPhotoGridCell *cell)
{
grid->cells_tail = g_list_append(grid->cells_tail, cell);
}
/* relative */
@ -196,8 +201,6 @@ ctrl_photo_grid_cell_to_coords(CltrPhotoGrid *grid,
idx = g_list_position(grid->cells_tail, cell);
/* idx -= (grid->row_offset * grid->n_cols); */
*y = idx / grid->n_cols;
*x = idx % grid->n_cols;
@ -218,7 +221,6 @@ ctrl_photo_grid_get_zoomed_coords(CltrPhotoGrid *grid,
*tx = (float)grid->cell_width * (grid->zoom_max) * x * -1.0;
*ty = (float)grid->cell_height * (grid->zoom_max) * y * -1.0;
}
static gboolean
@ -252,6 +254,8 @@ cltr_photo_grid_idle_cb(gpointer data)
{
CltrPhotoGrid *grid = (CltrPhotoGrid *)data;
cltr_photo_grid_update_visual_state(grid);
cltr_widget_queue_paint(CLTR_WIDGET(grid));
switch(grid->state)
@ -334,11 +338,6 @@ cltr_photo_grid_navigate(CltrPhotoGrid *grid,
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE;
/*
XXX view_min|max should be view_start|end
*/
grid->view_min_x = grid->view_max_x;
grid->view_min_y = grid->view_max_y ;
grid->anim_step = 0;
@ -382,11 +381,8 @@ cltr_photo_grid_activate_cell(CltrPhotoGrid *grid)
g_timeout_add(FPS_TO_TIMEOUT(ANIM_FPS),
cltr_photo_grid_idle_cb, grid);
}
/* que a draw ? */
}
gpointer
cltr_photo_grid_populate(gpointer data)
{
@ -465,24 +461,147 @@ cltr_photo_grid_populate(gpointer data)
return NULL;
}
static void
cltr_photo_grid_update_visual_state(CltrPhotoGrid *grid)
{
int view_x_diff = grid->view_max_x - grid->view_min_x;
int view_y_diff = grid->view_max_y - grid->view_min_y;
int zoom_diff = grid->zoom_max - grid->zoom_min;
int row_offset_h = grid->row_offset * grid->cell_height;
/* Default states ( zoomed out ) */
grid->paint_zoom = grid->zoom_min;
grid->paint_trans_x = grid->view_min_x;
grid->paint_trans_y = grid->view_min_y - row_offset_h;
grid->paint_start_y = row_offset_h;
grid->paint_cell_item = g_list_nth(grid->cells_tail,
grid->n_cols * grid->row_offset);
if (grid->state != CLTR_PHOTO_GRID_STATE_BROWSE
&& grid->state != CLTR_PHOTO_GRID_STATE_LOADING
&& grid->state != CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE)
{
float scroll_min_y_offset = (float)(row_offset_h);
/* Assume zoomed in */
grid->paint_zoom = grid->zoom_max;
grid->paint_trans_x = grid->view_max_x;
grid->paint_trans_y = grid->view_max_y;
if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOM_IN)
{
grid->anim_step++;
/* Are we zoomed all the way in > */
if (grid->anim_step >= grid->anim_n_steps)
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOMED;
grid->anim_step = 0;
}
else
{
float f = (float)grid->anim_step/grid->anim_n_steps;
scroll_min_y_offset *= grid->zoom_max;
grid->paint_zoom = grid->zoom_min + (zoom_diff * f);
grid->paint_trans_x = view_x_diff * f;
grid->paint_trans_y = (view_y_diff + scroll_min_y_offset) * f;
grid->paint_start_y = 0;
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOM_OUT)
{
grid->anim_step++;
if (grid->anim_step >= grid->anim_n_steps)
{
grid->paint_zoom = grid->zoom_min;
grid->anim_step = 0;
grid->paint_trans_x = grid->view_min_x;
grid->paint_trans_y = grid->view_min_y - scroll_min_y_offset;
grid->state = CLTR_PHOTO_GRID_STATE_BROWSE;
}
else
{
float f = (float)(grid->anim_n_steps - grid->anim_step )
/ grid->anim_n_steps;
scroll_min_y_offset *= grid->zoom_max;
grid->paint_zoom = grid->zoom_min + (zoom_diff * f);
grid->paint_trans_x = view_x_diff * f;
grid->paint_trans_y = (view_y_diff + scroll_min_y_offset) * f;
grid->paint_start_y = 0;
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE)
{
grid->anim_step++;
if (grid->anim_step >= grid->anim_n_steps)
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOMED;
grid->anim_step = 0;
}
else
{
float f = (float)grid->anim_step/grid->anim_n_steps;
grid->paint_trans_x = grid->view_min_x + (view_x_diff * f);
grid->paint_trans_y = grid->view_min_y + (view_y_diff * f);
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_SCROLLED_MOVE)
{
grid->paint_zoom = grid->zoom_min;
grid->paint_trans_x = grid->view_min_x;
grid->paint_trans_y = grid->view_min_y - row_offset_h;
grid->anim_step++;
if (grid->anim_step >= (grid->anim_n_steps/4))
{
grid->state = CLTR_PHOTO_GRID_STATE_BROWSE;
grid->anim_step = 0;
grid->paint_zoom = grid->zoom_min;
}
else
{
float f = (float)grid->anim_step / (grid->anim_n_steps/4);
grid->paint_trans_y += (grid->scroll_dist * f);
if (grid->scroll_dist > 0) /* up */
{
grid->paint_start_y = (grid->row_offset-1) * grid->cell_height;
}
else /* down */
{
grid->paint_cell_item = g_list_nth(grid->cells_tail,
grid->n_cols * (grid->row_offset-1));
}
}
}
}
}
static void
cltr_photo_grid_paint(CltrWidget *widget)
{
int x = 0, y = 0, rows = 0, cols = 0, i =0;
GList *cell_item;
float zoom, trans_x, trans_y;
CltrWindow *win = CLTR_WINDOW(widget->parent);
CltrWindow *win = CLTR_WINDOW(widget->parent);
CltrPhotoGrid *grid = (CltrPhotoGrid *)widget;
rows = grid->n_rows+1;
/* CLTR_MARK();*/
CLTR_MARK();
glPushMatrix();
glClear(GL_COLOR_BUFFER_BIT);
if (grid->cells_tail == NULL)
{
/* No pictures to paint yet */
@ -503,11 +622,11 @@ cltr_photo_grid_paint(CltrWidget *widget)
* see http://blog.metawrap.com/blog/PermaLink.aspx?guid=db82f92e-9fc8-4635-b3e5-e37a1ca6ee0a
* for more info
*
* Note bg must be glClearColor( 0.0, 0.0, 0.0, 0.0 ) to work.
* Is there a better way.?
* - multisample ?
*/
glClearColor( 0.0, 0.0, 0.0, 0.0 ); /* needed for saturate to work */
glEnable(GL_BLEND);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); /* needed */
@ -519,127 +638,15 @@ cltr_photo_grid_paint(CltrWidget *widget)
glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE);
/* Assume zoomed out */
zoom = grid->zoom_min;
trans_x = grid->view_min_x;
trans_y = grid->view_min_y - (grid->row_offset * grid->cell_height);
glColor4f(1.0, 1.0, 1.0, 1.0);
y = grid->row_offset * grid->cell_height;
/* values from cltr_photo_grid_update_visual_state() */
cell_item = g_list_nth(grid->cells_tail, grid->n_cols * grid->row_offset);
cell_item = grid->paint_cell_item;
y = grid->paint_start_y;
if (grid->state != CLTR_PHOTO_GRID_STATE_BROWSE
&& grid->state != CLTR_PHOTO_GRID_STATE_LOADING
&& grid->state != CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE)
{
float scroll_min_y_offset = (float)(grid->row_offset * grid->cell_height);
/* Assume zoomed in */
zoom = grid->zoom_max;
trans_x = grid->view_max_x;
trans_y = grid->view_max_y;
if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOM_IN)
{
grid->anim_step++;
/* Are we zoomed all the way in > */
if (grid->anim_step >= grid->anim_n_steps)
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOMED;
grid->anim_step = 0;
/* zoom = grid->zoom_max; set above */
}
else
{
float f = (float)grid->anim_step/grid->anim_n_steps;
scroll_min_y_offset *= grid->zoom_max;
zoom = grid->zoom_min + ((grid->zoom_max - grid->zoom_min) * f);
trans_x = (grid->view_max_x - grid->view_min_x) * f;
trans_y = (grid->view_max_y - grid->view_min_y + scroll_min_y_offset) * f;
y = 0;
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOM_OUT)
{
grid->anim_step++;
if (grid->anim_step >= grid->anim_n_steps)
{
zoom = grid->zoom_min;
grid->anim_step = 0;
trans_x = grid->view_min_x;
trans_y = grid->view_min_y - scroll_min_y_offset;
grid->state = CLTR_PHOTO_GRID_STATE_BROWSE;
}
else
{
float f = (float)(grid->anim_n_steps - grid->anim_step )
/ grid->anim_n_steps;
zoom = grid->zoom_min + (grid->zoom_max - grid->zoom_min) * f;
scroll_min_y_offset *= grid->zoom_max;
trans_x = (grid->view_max_x - grid->view_min_x) * f;
trans_y = ((grid->view_max_y - grid->view_min_y + scroll_min_y_offset) * f) ;
y = 0;
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE)
{
grid->anim_step++;
if (grid->anim_step >= grid->anim_n_steps)
{
grid->state = CLTR_PHOTO_GRID_STATE_ZOOMED;
grid->anim_step = 0;
}
else
{
float f = (float)grid->anim_step/grid->anim_n_steps;
trans_x = grid->view_min_x + ((grid->view_max_x - grid->view_min_x) * f);
trans_y = grid->view_min_y + ((grid->view_max_y - grid->view_min_y) * f);
}
}
else if (grid->state == CLTR_PHOTO_GRID_STATE_SCROLLED_MOVE)
{
zoom = grid->zoom_min;
trans_x = grid->view_min_x;
trans_y = grid->view_min_y - (grid->row_offset * grid->cell_height);
grid->anim_step++;
if (grid->anim_step >= (grid->anim_n_steps/4))
{
grid->state = CLTR_PHOTO_GRID_STATE_BROWSE;
grid->anim_step = 0;
zoom = grid->zoom_min;
}
else
{
float f = (float)grid->anim_step / (grid->anim_n_steps/4);
trans_y += (grid->scroll_dist * f);
if (grid->scroll_dist > 0) /* up */
{
y = (grid->row_offset-1) * grid->cell_height;
}
else /* down */
{
cell_item = g_list_nth(grid->cells_tail, grid->n_cols * (grid->row_offset-1));
// rows++;
}
}
}
}
glTranslatef( trans_x, trans_y, 0.0);
glScalef( zoom, zoom, 0.0);
glTranslatef (grid->paint_trans_x, grid->paint_trans_y, 0.0);
glScalef (grid->paint_zoom, grid->paint_zoom, 0.0);
while (rows--)
{
@ -648,9 +655,9 @@ cltr_photo_grid_paint(CltrWidget *widget)
while (cols--)
{
CltrPhotoGridCell *cell = (CltrPhotoGridCell *)cell_item->data;
Pixbuf *pixb = NULL;
int x1, x2, y1, y2, thumb_w, thumb_h;
int ns_border, ew_border;
Pixbuf *pixb = NULL;
int x1, x2, y1, y2, thumb_w, thumb_h;
int ns_border, ew_border;
pixb = cell->pixb;
@ -670,6 +677,11 @@ cltr_photo_grid_paint(CltrWidget *widget)
thumb_w = thumb_w + cell->anim_step;
thumb_h = thumb_h + cell->anim_step;
}
/* set color here for developing effect
* only fully develop when all picts loaded ?
* blur texture too ?
*/
/* glColor4f(1.0, 1.0, 1.0, 0.5); */
cell->anim_step = 0;
}
@ -722,8 +734,7 @@ cltr_photo_grid_paint(CltrWidget *widget)
glEnable(GL_TEXTURE_2D);
/* back to regular non translated matrix */
glPopMatrix();
glPopMatrix();
cell_item = g_list_next(cell_item);
@ -733,6 +744,7 @@ cltr_photo_grid_paint(CltrWidget *widget)
x += grid->cell_width;
i++;
}
y += grid->cell_height;
}
@ -741,6 +753,7 @@ cltr_photo_grid_paint(CltrWidget *widget)
glPopMatrix();
/* finally paint background */
glDisable(GL_TEXTURE_2D);
glColor3f(0.6, 0.6, 0.62);
glRecti(0, 0, widget->width, widget->height);
@ -753,12 +766,28 @@ cltr_photo_grid_paint(CltrWidget *widget)
g_mutex_unlock(Mutex_GRID);
/* reset */
glDisable(GL_POLYGON_SMOOTH);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
static void
cltr_photo_grid_show(CltrWidget *widget)
{
CltrPhotoGrid* grid = CLTR_PHOTO_GRID(widget);
CltrPhotoGrid *grid = CLTR_PHOTO_GRID(widget);
GThread *loader_thread;
grid->state = CLTR_PHOTO_GRID_STATE_LOADING;
loader_thread = g_thread_create (cltr_photo_grid_populate,
(gpointer)grid,
TRUE,
NULL);
g_timeout_add(FPS_TO_TIMEOUT(20),
cltr_photo_grid_idle_cb, grid);
cltr_widget_queue_paint(widget);
}
@ -771,7 +800,6 @@ cltr_photo_grid_new(int width,
const gchar *img_path)
{
CltrPhotoGrid *grid = NULL;
GThread *loader_thread;
grid = g_malloc0(sizeof(CltrPhotoGrid));
@ -795,6 +823,7 @@ cltr_photo_grid_new(int width,
grid->anim_n_steps = 20; /* value needs to be calced dep on rows */
grid->anim_step = 0;
/* Default 'browse view' */
grid->zoom_min = 1.0;
grid->view_min_x = (grid->widget.width - (grid->zoom_min * grid->widget.width))/2.0;
grid->view_min_y = 0.0;
@ -804,19 +833,7 @@ cltr_photo_grid_new(int width,
grid->row_offset = 0;
/* Below needs to go else where - some kind of texture manager/helper */
Mutex_GRID = g_mutex_new();
/* Load */
loader_thread = g_thread_create (cltr_photo_grid_populate,
(gpointer)grid,
TRUE,
NULL);
g_timeout_add(FPS_TO_TIMEOUT(20),
cltr_photo_grid_idle_cb, grid);
return CLTR_WIDGET(grid);
}

View File

@ -4,9 +4,7 @@
/*
IDEAS or less memory
+ up to 4 textures tiled per image *DONE*
+ texture compression ?
+ texture compression - made no difference ?
+ mipmaps - make zoom faster ? ( vs memory )

View File

@ -14,9 +14,10 @@ cltr_widget_new(void)
void
cltr_widget_show(CltrWidget *widget)
{
widget->visible = TRUE;
if (widget->show)
{
widget->visible = TRUE;
widget->show(widget);
}
}
@ -60,8 +61,27 @@ cltr_widget_hide(CltrWidget *widget)
void
cltr_widget_paint(CltrWidget *widget)
{
if (widget->paint && widget->visible)
widget->paint(widget);
if (widget->visible)
{
GList *child_item = widget->children;;
if (widget->paint)
widget->paint(widget);
/* Recurse down */
if (child_item)
{
do
{
CltrWidget *child = CLTR_WIDGET(child_item->data);
if (child->visible)
cltr_widget_paint(child);
}
while ((child_item = g_list_next(child_item)) != NULL);
}
}
}
void

View File

@ -7,6 +7,9 @@ cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev);
static void
cltr_window_show(CltrWidget *widget);
static void
cltr_window_paint(CltrWidget *widget);
struct CltrWindow
{
CltrWidget widget;
@ -25,6 +28,7 @@ cltr_window_new(int width, int height)
win->widget.width = width;
win->widget.height = height;
win->widget.show = cltr_window_show;
win->widget.paint = cltr_window_paint;
win->widget.xevent_handler = cltr_window_handle_xevent;
win->xwin = XCreateSimpleWindow(CltrCntx.xdpy,
@ -55,12 +59,6 @@ cltr_window_new(int width, int height)
return CLTR_WIDGET(win);
}
Window
cltr_window_xwin(CltrWindow *win)
{
return win->xwin;
}
static void
cltr_window_show(CltrWidget *widget)
{
@ -70,12 +68,21 @@ cltr_window_show(CltrWidget *widget)
/* XXX set focused call */
if (widget->children)
{
win->focused_child = g_list_nth_data(widget->children, 0);
if (win->focused_child == NULL)
win->focused_child = g_list_nth_data(widget->children, 0);
}
XMapWindow(ctx->xdpy, win->xwin);
}
static void
cltr_window_paint(CltrWidget *widget)
{
glClear(GL_COLOR_BUFFER_BIT);
glClearColor( 0.0, 0.0, 0.0, 0.0 ); /* needed for saturate to work */
}
static gboolean
cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev)
{
@ -85,7 +92,7 @@ cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev)
if (xev->type == Expose)
{
;
cltr_widget_queue_paint(widget);
}
/* XXX Very basic - assumes we are only interested in mouse clicks */
@ -95,7 +102,22 @@ cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev)
return FALSE;
}
/* window only */
/* window only methods */
Window
cltr_window_xwin(CltrWindow *win)
{
return win->xwin;
}
Window
cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget)
{
/* XXX Should check widget is an actual child of the window */
ClutterMainContext *ctx = CLTR_CONTEXT();
win->focused_child = widget;
}

View File

@ -10,14 +10,19 @@ typedef struct CltrWindow CltrWindow;
CltrWidget*
cltr_window_new(int width, int height);
Window
cltr_window_xwin(CltrWindow *win);
void
cltr_window_paint(CltrWidget *widget);
void
cltr_window_add_widget(CltrWindow *win, CltrWidget *widget, int x, int y);
/* win only methods */
Window
cltr_window_xwin(CltrWindow *win);
Window
cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget);
#endif

20
cltr.c
View File

@ -3,7 +3,8 @@
int
main(int argc, char **argv)
{
CltrWidget *win = NULL, *grid = NULL;
CltrWidget *win = NULL, *grid = NULL, *test = NULL, *test2 = NULL;
CltrWidget *list;
if (argc < 2)
{
@ -16,10 +17,25 @@ main(int argc, char **argv)
win = cltr_window_new(640, 480);
grid = cltr_photo_grid_new(640, 480, 3, 3, argv[1]);
/*
grid = cltr_photo_grid_new(640, 480, 4, 4, argv[1]);
test = cltr_scratch_new(100, 100);
test2 = cltr_scratch_new(150, 150);
cltr_widget_add_child(win, grid, 0, 0);
cltr_widget_add_child(win, test, 320, 240);
cltr_widget_add_child(win, test2, 400, 300);
cltr_window_focus_widget(CLTR_WINDOW(win), grid);
*/
list = cltr_list_new(640,480,640, 160);
cltr_widget_add_child(win, list, 0, 0);
cltr_widget_show_all(win);
cltr_main_loop();

11
cltr.h
View File

@ -27,6 +27,17 @@ typedef enum CltrDirection
}
CltrDirection;
typedef struct CltrRect
{
int x, y, width, height;
}
CltrRect;
#define cltr_rect_x1(r) ((r).x)
#define cltr_rect_y1(r) ((r).y)
#define cltr_rect_x2(r) ((r).x + (r).width)
#define cltr_rect_y2(r) ((r).y + (r).height)
/* texture stuff */
/* ******************* */

View File

@ -577,6 +577,24 @@ pixbuf_copy(Pixbuf *src_pixb,
}
}
void
pixbuf_fill_rect(Pixbuf *pixb,
int x,
int y,
int width,
int height,
PixbufPixel *p)
{
int i, j;
if (width < 0) width = pixb->width;
if (height < 0) height = pixb->height;
for (i = x; i<width; i++)
for (j =y; j<height; j++)
pixbuf_set_pixel(pixb, i, j, p);
}
Pixbuf *
pixbuf_scale_down(Pixbuf *pixb,
int new_width,

View File

@ -72,6 +72,15 @@ pixbuf_copy(Pixbuf *src_pixb,
int dstx,
int dsty);
void
pixbuf_fill_rect(Pixbuf *pixb,
int x,
int y,
int width,
int height,
PixbufPixel *p);
Pixbuf*
pixbuf_scale_down(Pixbuf *pixb,
int new_width,