mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-12-22 18:36:48 +02:00
- added icons for new-style measurements (on-going)
- increased default window size for make room for new icons - switch the canvas to dark blue when instantiation fails - modularized point lookup logic of instantiate_meas - added highlight mode (on-going) git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5404 99fdad57-331a-0410-800a-d7fa5415bdb3
This commit is contained in:
parent
bb7355d84b
commit
1a18292883
2
Makefile
2
Makefile
@ -17,7 +17,7 @@ OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \
|
||||
gui_tools.o
|
||||
|
||||
XPMS = point.xpm delete.xpm vec.xpm frame.xpm frame_locked.xpm frame_ready.xpm \
|
||||
line.xpm rect.xpm pad.xpm circ.xpm meas.xpm
|
||||
line.xpm rect.xpm pad.xpm circ.xpm meas.xpm meas_x.xpm meas_y.xpm
|
||||
|
||||
CFLAGS_GTK = `pkg-config --cflags gtk+-2.0`
|
||||
LIBS_GTK = `pkg-config --libs gtk+-2.0`
|
||||
|
8
README
8
README
@ -422,10 +422,10 @@ To change a point of an object, select the object, then drag the point
|
||||
to its new location. To edit the object's parameters, select it and
|
||||
make the changes in the input area at the bottom.
|
||||
|
||||
To delete an object, select it and press Delete. Deleted objects can
|
||||
be undeleted by pressing "u". If any other changes have been made
|
||||
since deletion, fped may misbehave. If deleting a vector, all items
|
||||
that reference it are deleted.
|
||||
To delete an object, select the delete tool and click on the object.
|
||||
Deleted objects can be undeleted by pressing "u". If any other changes
|
||||
have been made since deletion, fped may misbehave. If deleting a vector,
|
||||
all items that reference it are deleted as well.
|
||||
|
||||
|
||||
Experimental: new-style measurements
|
||||
|
2
gui.c
2
gui.c
@ -1225,7 +1225,7 @@ int gui_main(void)
|
||||
{
|
||||
root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
|
||||
gtk_window_set_default_size(GTK_WINDOW(root), 600, 400);
|
||||
gtk_window_set_default_size(GTK_WINDOW(root), 620, 460);
|
||||
gtk_window_set_title(GTK_WINDOW(root), "fped");
|
||||
|
||||
/* get root->window */
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "gui_canvas.h"
|
||||
|
||||
|
||||
void (*highlight)(struct draw_ctx *ctx) = NULL;
|
||||
|
||||
static struct draw_ctx ctx;
|
||||
static struct coord curr_pos;
|
||||
static struct coord user_origin = { 0, 0 };
|
||||
@ -101,9 +103,12 @@ void redraw(void)
|
||||
|
||||
aw = ctx.widget->allocation.width;
|
||||
ah = ctx.widget->allocation.height;
|
||||
gdk_draw_rectangle(ctx.widget->window, gc_bg, TRUE, 0, 0, aw, ah);
|
||||
gdk_draw_rectangle(ctx.widget->window,
|
||||
instantiation_ok ? gc_bg : gc_bg_error, TRUE, 0, 0, aw, ah);
|
||||
|
||||
inst_draw(&ctx);
|
||||
if (highlight)
|
||||
highlight(&ctx);
|
||||
tool_redraw(&ctx);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,14 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
/*
|
||||
* "highlight" is invoked at the end of each redraw, for optional highlighting
|
||||
* of objects.
|
||||
*/
|
||||
|
||||
extern void (*highlight)(struct draw_ctx *ctx);
|
||||
|
||||
|
||||
void redraw(void);
|
||||
|
||||
GtkWidget *make_canvas(void);
|
||||
|
@ -159,6 +159,14 @@ void gui_hover_vec(struct inst *self, struct draw_ctx *ctx)
|
||||
}
|
||||
|
||||
|
||||
void gui_highlight_vec(struct inst *self, struct draw_ctx *ctx)
|
||||
{
|
||||
struct coord center = translate(ctx, self->u.rect.end);
|
||||
|
||||
draw_circle(DA, gc_highlight, FALSE, center.x, center.y, VEC_EYE_R);
|
||||
}
|
||||
|
||||
|
||||
void gui_draw_vec(struct inst *self, struct draw_ctx *ctx)
|
||||
{
|
||||
struct coord from = translate(ctx, self->base);
|
||||
|
@ -50,6 +50,7 @@ void gui_draw_arc(struct inst *self, struct draw_ctx *ctx);
|
||||
void gui_draw_meas(struct inst *self, struct draw_ctx *ctx);
|
||||
void gui_draw_frame(struct inst *self, struct draw_ctx *ctx);
|
||||
|
||||
void gui_highlight_vec(struct inst *self, struct draw_ctx *ctx);
|
||||
void gui_hover_vec(struct inst *self, struct draw_ctx *ctx);
|
||||
void gui_hover_frame(struct inst *self, struct draw_ctx *ctx);
|
||||
|
||||
|
11
gui_style.c
11
gui_style.c
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* gui_style.c - GUI, style definitions
|
||||
/* * gui_style.c - GUI, style definitions
|
||||
*
|
||||
* Written 2009 by Werner Almesberger
|
||||
* Copyright 2009 by Werner Almesberger
|
||||
@ -22,8 +21,9 @@
|
||||
#define INVALID "#00ffff"
|
||||
|
||||
|
||||
GdkGC *gc_bg;
|
||||
GdkGC *gc_bg, *gc_bg_error;
|
||||
GdkGC *gc_drag;
|
||||
GdkGC *gc_highlight;
|
||||
GdkGC *gc_active_frame;
|
||||
GdkGC *gc_vec[mode_n];
|
||||
GdkGC *gc_obj[mode_n];
|
||||
@ -61,6 +61,7 @@ static void style(GdkGC *gcs[mode_n],
|
||||
void gui_setup_style(GdkDrawable *drawable)
|
||||
{
|
||||
gc_bg = gc("#000000", 0);
|
||||
gc_bg_error = gc("#000040", 0);
|
||||
gc_drag = gc("#ffffff", 2);
|
||||
/* inactive in+path active act+path selected */
|
||||
style(gc_vec, "#202000", "#404020", "#909040", "#c0c080", "#ffff80");
|
||||
@ -69,7 +70,9 @@ void gui_setup_style(GdkDrawable *drawable)
|
||||
style(gc_ptext, "#404040", INVALID, "#ffffff", INVALID, "#ffffff");
|
||||
style(gc_meas, "#280040", INVALID, "#ff00ff", INVALID, "#ffff80");
|
||||
style(gc_frame, "#004000", "#205020", "#009000", INVALID, "#ffff80");
|
||||
gc_active_frame = gc("#00ff00", 2);
|
||||
|
||||
gc_active_frame = gc("#00ff00", 2);
|
||||
// gc_highlight = gc("#ff8020", 2);
|
||||
gc_highlight = gc("#ff90d0", 2);
|
||||
gc_frame[mode_hover] = gc_vec[mode_hover] = gc("#c00000", 1);
|
||||
}
|
||||
|
@ -88,8 +88,9 @@
|
||||
/* ----- canvas drawing styles --------------------------------------------- */
|
||||
|
||||
|
||||
extern GdkGC *gc_bg;
|
||||
extern GdkGC *gc_bg, *gc_bg_error;
|
||||
extern GdkGC *gc_drag;
|
||||
extern GdkGC *gc_highlight;
|
||||
extern GdkGC *gc_active_frame;
|
||||
extern GdkGC *gc_vec[mode_n];
|
||||
extern GdkGC *gc_obj[mode_n];
|
||||
|
61
gui_tools.c
61
gui_tools.c
@ -22,6 +22,7 @@
|
||||
#include "gui_util.h"
|
||||
#include "gui_style.h"
|
||||
#include "gui_inst.h"
|
||||
#include "gui_canvas.h"
|
||||
#include "gui_status.h"
|
||||
#include "gui.h"
|
||||
#include "gui_tools.h"
|
||||
@ -33,6 +34,8 @@
|
||||
#include "icons/frame_ready.xpm"
|
||||
#include "icons/line.xpm"
|
||||
#include "icons/meas.xpm"
|
||||
#include "icons/meas_x.xpm"
|
||||
#include "icons/meas_y.xpm"
|
||||
#include "icons/pad.xpm"
|
||||
#include "icons/point.xpm"
|
||||
#include "icons/delete.xpm"
|
||||
@ -45,6 +48,7 @@
|
||||
|
||||
struct tool_ops {
|
||||
void (*tool_selected)(void);
|
||||
void (*tool_deselected)(void);
|
||||
void (*click)(struct draw_ctx *ctx, struct coord pos);
|
||||
struct pix_buf *(*drag_new)(struct draw_ctx *ctx, struct inst *from,
|
||||
struct coord to);
|
||||
@ -517,11 +521,63 @@ static int end_new_meas(struct draw_ctx *ctx,
|
||||
}
|
||||
|
||||
|
||||
static int meas_x_pick_vec(struct inst *inst, void *ctx)
|
||||
{
|
||||
struct vec *vec = inst->vec;
|
||||
struct coord min;
|
||||
|
||||
if (!vec->samples)
|
||||
return 0;
|
||||
min = meas_find_min(lt_xy, vec->samples);
|
||||
return inst->u.rect.end.x == min.x && inst->u.rect.end.y == min.y;
|
||||
}
|
||||
|
||||
|
||||
static void highlight_vecs(struct draw_ctx *ctx)
|
||||
{
|
||||
inst_highlight_vecs(ctx, meas_x_pick_vec, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void tool_selected_meas_x(void)
|
||||
{
|
||||
highlight = highlight_vecs;
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
static void tool_selected_meas_y(void)
|
||||
{
|
||||
highlight = NULL;
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
static void tool_deselected_meas(void)
|
||||
{
|
||||
highlight = NULL;
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
static struct tool_ops meas_ops = {
|
||||
.drag_new = drag_new_line,
|
||||
.end_new = end_new_meas,
|
||||
};
|
||||
|
||||
static struct tool_ops meas_ops_x = {
|
||||
.tool_selected = tool_selected_meas_x,
|
||||
.tool_deselected= tool_deselected_meas,
|
||||
.drag_new = drag_new_line,
|
||||
.end_new = end_new_meas,
|
||||
};
|
||||
static struct tool_ops meas_ops_y = {
|
||||
.tool_selected = tool_selected_meas_y,
|
||||
.tool_deselected= tool_deselected_meas,
|
||||
.drag_new = drag_new_line,
|
||||
.end_new = end_new_meas,
|
||||
};
|
||||
|
||||
|
||||
/* ----- frame helper ------------------------------------------------------ */
|
||||
|
||||
@ -828,6 +884,8 @@ static void tool_select(GtkWidget *evbox, struct tool_ops *ops)
|
||||
GdkColor col;
|
||||
|
||||
if (active_tool) {
|
||||
if (active_ops && active_ops->tool_deselected)
|
||||
active_ops->tool_deselected();
|
||||
col = get_color(TOOL_UNSELECTED);
|
||||
gtk_widget_modify_bg(active_tool, GTK_STATE_NORMAL, &col);
|
||||
active_tool = NULL;
|
||||
@ -940,7 +998,10 @@ GtkWidget *gui_setup_tools(GdkDrawable *drawable)
|
||||
last = tool_button(bar, drawable, xpm_line, last, &line_ops);
|
||||
last = tool_button(bar, drawable, xpm_rect, last, &rect_ops);
|
||||
last = tool_button(bar, drawable, xpm_circ, last, &circ_ops);
|
||||
tool_separator(bar);
|
||||
last = tool_button(bar, drawable, xpm_meas, last, &meas_ops);
|
||||
last = tool_button(bar, drawable, xpm_meas_x, last, &meas_ops_x);
|
||||
last = tool_button(bar, drawable, xpm_meas_y, last, &meas_ops_y);
|
||||
|
||||
frame_image = gtk_widget_ref(make_image(drawable, xpm_frame));
|
||||
frame_image_locked =
|
||||
|
@ -10,10 +10,10 @@ Single
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3600 2400 6000 2400 6000 4800 3600 4800 3600 2400
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3900 3300 3900 3900
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5700 3300 5700 3900
|
||||
3900 3600 4200 4200
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 1 1 2
|
||||
0 0 10.00 450.00 450.00
|
||||
0 0 10.00 450.00 450.00
|
||||
3900 3600 5700 3600
|
||||
4050 3900 5550 3150
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5400 2850 5700 3450
|
||||
|
23
icons/meas_x.fig
Normal file
23
icons/meas_x.fig
Normal file
@ -0,0 +1,23 @@
|
||||
#FIG 3.2 Produced by xfig version 3.2.5a
|
||||
Landscape
|
||||
Center
|
||||
Inches
|
||||
A4
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
6 3975 2775 5625 4125
|
||||
2 1 0 10 0 7 45 -1 -1 0.000 0 1 -1 0 0 2
|
||||
4050 3600 5550 2850
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 1 -1 0 0 2
|
||||
5550 2850 5550 3900
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 1 -1 0 0 2
|
||||
4050 3600 4050 3900
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 1 1 2
|
||||
0 0 10.00 450.00 450.00
|
||||
0 0 10.00 450.00 450.00
|
||||
4050 3900 5550 3900
|
||||
-6
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3600 2400 6000 2400 6000 4800 3600 4800 3600 2400
|
23
icons/meas_y.fig
Normal file
23
icons/meas_y.fig
Normal file
@ -0,0 +1,23 @@
|
||||
#FIG 3.2 Produced by xfig version 3.2.5a
|
||||
Landscape
|
||||
Center
|
||||
Inches
|
||||
A4
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
6 3825 2700 5475 4200
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 0 -1 1 1 2
|
||||
0 0 10.00 450.00 450.00
|
||||
0 0 10.00 450.00 450.00
|
||||
5250 2775 5250 4125
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 1 -1 0 0 2
|
||||
3900 4125 5250 4125
|
||||
2 1 0 10 0 7 45 -1 -1 0.000 0 1 -1 0 0 2
|
||||
3900 4125 4650 2775
|
||||
2 1 0 10 21 7 50 -1 -1 0.000 0 1 -1 0 0 2
|
||||
4650 2775 5250 2775
|
||||
-6
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3600 2400 6000 2400 6000 4800 3600 4800 3600 2400
|
11
inst.c
11
inst.c
@ -841,6 +841,17 @@ void inst_draw(struct draw_ctx *ctx)
|
||||
}
|
||||
|
||||
|
||||
void inst_highlight_vecs(struct draw_ctx *ctx,
|
||||
int (*pick)(struct inst *inst, void *user), void *user)
|
||||
{
|
||||
struct inst *inst;
|
||||
|
||||
for (inst = insts[ip_vec]; inst; inst = inst->next)
|
||||
if (pick(inst, user))
|
||||
gui_highlight_vec(inst, ctx);
|
||||
}
|
||||
|
||||
|
||||
struct pix_buf *inst_draw_move(struct inst *inst, struct draw_ctx *ctx,
|
||||
struct coord pos, int i)
|
||||
{
|
||||
|
2
inst.h
2
inst.h
@ -114,6 +114,8 @@ void inst_commit(void);
|
||||
void inst_revert(void);
|
||||
|
||||
void inst_draw(struct draw_ctx *ctx);
|
||||
void inst_highlight_vecs(struct draw_ctx *ctx,
|
||||
int (*pick)(struct inst *inst, void *user), void *user);
|
||||
struct pix_buf *inst_draw_move(struct inst *inst, struct draw_ctx *ctx,
|
||||
struct coord pos, int i);
|
||||
int inst_do_move_to(struct inst *inst, struct vec *vec, int i);
|
||||
|
96
meas.c
96
meas.c
@ -75,25 +75,25 @@ void meas_post(struct vec *vec, struct coord pos)
|
||||
}
|
||||
|
||||
|
||||
static int lt_x(struct coord a, struct coord b)
|
||||
int lt_x(struct coord a, struct coord b)
|
||||
{
|
||||
return a.x < b.x;
|
||||
}
|
||||
|
||||
|
||||
static int lt_y(struct coord a, struct coord b)
|
||||
int lt_y(struct coord a, struct coord b)
|
||||
{
|
||||
return a.y < b.y;
|
||||
}
|
||||
|
||||
|
||||
static int lt_xy(struct coord a, struct coord b)
|
||||
int lt_xy(struct coord a, struct coord b)
|
||||
{
|
||||
return a.y < b.y || (a.y == b.y && a.x < b.x);
|
||||
}
|
||||
|
||||
|
||||
static int (*lt_op[mt_n])(struct coord a, struct coord b) = {
|
||||
static lt_op_type lt_op[mt_n] = {
|
||||
lt_xy,
|
||||
lt_x,
|
||||
lt_y,
|
||||
@ -109,7 +109,7 @@ static int is_next[mt_n] = {
|
||||
};
|
||||
|
||||
|
||||
static int better_next(int (*lt)(struct coord a, struct coord b),
|
||||
static int better_next(lt_op_type lt,
|
||||
struct coord a0, struct coord b0, struct coord b)
|
||||
{
|
||||
/* if we don't have any suitable point A0 < B0 yet, use this one */
|
||||
@ -143,12 +143,64 @@ static int better_next(int (*lt)(struct coord a, struct coord b),
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In order to obtain a stable order, we sort points equal on the measured
|
||||
* coordinate also by xy:
|
||||
*
|
||||
* if (*a < a0) use *a
|
||||
* else if (*a == a0 && *a <xy a0) use *a
|
||||
*/
|
||||
|
||||
struct coord meas_find_min(lt_op_type lt, const struct sample *s)
|
||||
{
|
||||
struct coord min;
|
||||
|
||||
min = s->pos;
|
||||
while (s) {
|
||||
if (lt(s->pos, min) ||
|
||||
(!lt(min, s->pos) && lt_xy(s->pos, min)))
|
||||
min = s->pos;
|
||||
s = s->next;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
|
||||
struct coord meas_find_next(lt_op_type lt, const struct sample *s,
|
||||
struct coord ref)
|
||||
{
|
||||
struct coord next;
|
||||
|
||||
next = s->pos;
|
||||
while (s) {
|
||||
if (better_next(lt, ref, next, s->pos))
|
||||
next = s->pos;
|
||||
s = s->next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
struct coord meas_find_max(lt_op_type lt, const struct sample *s)
|
||||
{
|
||||
struct coord max;
|
||||
|
||||
max = s->pos;
|
||||
while (s) {
|
||||
if (lt(max, s->pos) ||
|
||||
(!lt(s->pos, max) && lt_xy(max, s->pos)))
|
||||
max = s->pos;
|
||||
s = s->next;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
int instantiate_meas(void)
|
||||
{
|
||||
struct meas *meas;
|
||||
struct coord a0, b0;
|
||||
const struct sample *a, *b;
|
||||
int (*lt)(struct coord a, struct coord b);
|
||||
lt_op_type lt;
|
||||
struct num offset;
|
||||
|
||||
for (meas = measurements; meas; meas = meas->next) {
|
||||
@ -156,31 +208,11 @@ int instantiate_meas(void)
|
||||
continue;
|
||||
|
||||
lt = lt_op[meas->type];
|
||||
|
||||
/*
|
||||
* In order to obtain a stable order, we sort points equal on
|
||||
* the measured coordinate also by xy:
|
||||
*
|
||||
* if (*a < a0) use *a
|
||||
* else if (*a == a0 && *a <xy a0) use *a
|
||||
*/
|
||||
a0 = meas->low->samples->pos;
|
||||
for (a = meas->low->samples; a; a = a->next)
|
||||
if (lt(a->pos, a0) ||
|
||||
(!lt(a0, a->pos) && lt_xy(a->pos, a0)))
|
||||
a0 = a->pos;
|
||||
|
||||
b0 = meas->high->samples->pos;
|
||||
for (b = meas->high->samples; b; b = b->next) {
|
||||
if (is_next[meas->type]) {
|
||||
if (better_next(lt, a0, b0, b->pos))
|
||||
b0 = b->pos;
|
||||
} else {
|
||||
if (lt(b0, b->pos) ||
|
||||
(!lt(b->pos, b0) && lt_xy(b0, b->pos)))
|
||||
b0 = b->pos;
|
||||
}
|
||||
}
|
||||
a0 = meas_find_min(lt, meas->low->samples);
|
||||
if (is_next[meas->type])
|
||||
b0 = meas_find_next(lt, meas->high->samples, a0);
|
||||
else
|
||||
b0 = meas_find_max(lt, meas->high->samples);
|
||||
|
||||
offset = eval_unit(meas->offset, root_frame);
|
||||
if (is_undef(offset))
|
||||
|
14
meas.h
14
meas.h
@ -17,6 +17,9 @@
|
||||
#include "obj.h"
|
||||
|
||||
|
||||
typedef int (*lt_op_type)(struct coord a, struct coord b);
|
||||
|
||||
|
||||
struct meas {
|
||||
enum meas_type {
|
||||
mt_xy_next,
|
||||
@ -35,10 +38,21 @@ struct meas {
|
||||
struct meas *next;
|
||||
};
|
||||
|
||||
struct sample;
|
||||
|
||||
|
||||
extern struct meas *measurements;
|
||||
|
||||
|
||||
int lt_x(struct coord a, struct coord b);
|
||||
int lt_y(struct coord a, struct coord b);
|
||||
int lt_xy(struct coord a, struct coord b);
|
||||
|
||||
struct coord meas_find_min(lt_op_type lt, const struct sample *s);
|
||||
struct coord meas_find_next(lt_op_type lt, const struct sample *s,
|
||||
struct coord ref);
|
||||
struct coord meas_find_max(lt_op_type lt, const struct sample *s);
|
||||
|
||||
void meas_start(void);
|
||||
void meas_post(struct vec *vec, struct coord pos);
|
||||
int instantiate_meas(void);
|
||||
|
2
obj.c
2
obj.c
@ -32,6 +32,7 @@ char *part_name = NULL;
|
||||
struct frame *frames = NULL;
|
||||
struct frame *root_frame = NULL;
|
||||
struct frame *active_frame = NULL;
|
||||
int instantiation_ok;
|
||||
|
||||
|
||||
static int generate_frame(struct frame *frame, struct coord base,
|
||||
@ -273,5 +274,6 @@ int instantiate(void)
|
||||
inst_commit();
|
||||
else
|
||||
inst_revert();
|
||||
instantiation_ok = ok;
|
||||
return ok;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user