mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
made the exercise 2 and 10 selection be able to just be clicked instead of just dragged
This commit is contained in:
parent
c106f5d0e2
commit
cc838ee5db
1 changed files with 163 additions and 2 deletions
165
sprechen.c
165
sprechen.c
|
|
@ -1434,11 +1434,13 @@ typedef struct {
|
|||
GtkWidget *pool;
|
||||
GtkWidget *target;
|
||||
GtkWidget *group;
|
||||
GtkWidget *stage; /* transparent overlay layer for the fly sprite */
|
||||
GtkWidget *trans; /* hidden meaning label under the group */
|
||||
GtkWidget *chips[6];
|
||||
int placed[6];
|
||||
int placed_count;
|
||||
int n_words;
|
||||
gboolean flying; /* a click-move animation is in progress */
|
||||
} SentBuilder;
|
||||
|
||||
static void sent_rebuild(SentBuilder *sb) {
|
||||
|
|
@ -1555,6 +1557,148 @@ static gboolean asm_drop_to_pool(GtkDropTarget *target, const GValue *value,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Click-to-move with a fly ("glide") animation */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
typedef struct {
|
||||
SentBuilder *sb;
|
||||
GtkWidget *chip; /* real chip, kept invisible in its final slot */
|
||||
GtkWidget *ghost; /* sprite flying from start to finish */
|
||||
GtkWidget *stage;
|
||||
double sx, sy; /* start position (stage coords) */
|
||||
double tx, ty; /* target position (stage coords) */
|
||||
guint wait; /* ticks waited for relayout */
|
||||
gint64 t0; /* < 0 while still measuring the target */
|
||||
} FlyCtx;
|
||||
|
||||
static void asm_finish_fly(FlyCtx *fc) {
|
||||
gtk_widget_remove_css_class(fc->chip, "ghost-host");
|
||||
gtk_fixed_remove(GTK_FIXED(fc->stage), fc->ghost);
|
||||
fc->sb->flying = FALSE;
|
||||
g_free(fc);
|
||||
}
|
||||
|
||||
static gboolean asm_fly_tick(gpointer data) {
|
||||
FlyCtx *fc = data;
|
||||
gint64 now = g_get_monotonic_time() / 1000;
|
||||
|
||||
if (fc->t0 < 0) {
|
||||
double nx = 0.0, ny = 0.0;
|
||||
gboolean ok;
|
||||
|
||||
fc->wait++;
|
||||
ok = gtk_widget_translate_coordinates(fc->chip, fc->stage,
|
||||
0, 0, &nx, &ny);
|
||||
if (fc->wait < 2)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
if (ok && fc->wait < 14 &&
|
||||
fabs(nx - fc->sx) + fabs(ny - fc->sy) < 0.5)
|
||||
return G_SOURCE_CONTINUE; /* still waiting for relayout */
|
||||
|
||||
if (ok) {
|
||||
fc->tx = nx;
|
||||
fc->ty = ny;
|
||||
} else {
|
||||
fc->tx = fc->sx;
|
||||
fc->ty = fc->sy;
|
||||
}
|
||||
fc->t0 = now;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
{
|
||||
double t = (double)(now - fc->t0) / 240.0;
|
||||
double e, x, y;
|
||||
|
||||
if (t > 1.0)
|
||||
t = 1.0;
|
||||
e = 1.0 - pow(1.0 - t, 3.0); /* ease-out cubic */
|
||||
x = fc->sx + (fc->tx - fc->sx) * e;
|
||||
y = fc->sy + (fc->ty - fc->sy) * e;
|
||||
gtk_fixed_move(GTK_FIXED(fc->stage), fc->ghost, (int)x, (int)y);
|
||||
|
||||
if (t >= 1.0) {
|
||||
asm_finish_fly(fc);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void asm_move_by_click(GtkButton *button, gpointer data) {
|
||||
ChipRef *ref = data;
|
||||
SentBuilder *sb = ref->sb;
|
||||
int idx = ref->idx;
|
||||
int pos = -1;
|
||||
double sx = 0.0, sy = 0.0;
|
||||
GtkWidget *chip = GTK_WIDGET(button);
|
||||
GtkWidget *ghost;
|
||||
GtkWidget *child;
|
||||
const char *txt = NULL;
|
||||
FlyCtx *fc;
|
||||
|
||||
(void)button;
|
||||
|
||||
if (sb->flying)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < sb->placed_count; i++) {
|
||||
if (sb->placed[i] == idx) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sb->stage &&
|
||||
gtk_widget_translate_coordinates(chip, sb->stage, 0, 0, &sx, &sy)) {
|
||||
if (pos >= 0) {
|
||||
for (int i = pos; i < sb->placed_count - 1; i++)
|
||||
sb->placed[i] = sb->placed[i + 1];
|
||||
sb->placed_count--;
|
||||
} else {
|
||||
sb->placed[sb->placed_count++] = idx;
|
||||
}
|
||||
|
||||
sent_rebuild(sb);
|
||||
|
||||
child = gtk_button_get_child(GTK_BUTTON(chip));
|
||||
if (child && GTK_IS_LABEL(child))
|
||||
txt = gtk_label_get_text(GTK_LABEL(child));
|
||||
|
||||
ghost = gtk_button_new_with_label(txt ? txt : "");
|
||||
gtk_widget_add_css_class(ghost, "chip");
|
||||
gtk_widget_set_sensitive(ghost, FALSE);
|
||||
gtk_widget_set_can_focus(ghost, FALSE);
|
||||
gtk_fixed_put(GTK_FIXED(sb->stage), ghost, (int)sx, (int)sy);
|
||||
|
||||
fc = g_new0(FlyCtx, 1);
|
||||
fc->sb = sb;
|
||||
fc->chip = chip;
|
||||
fc->ghost = ghost;
|
||||
fc->stage = sb->stage;
|
||||
fc->sx = sx;
|
||||
fc->sy = sy;
|
||||
fc->t0 = -1;
|
||||
sb->flying = TRUE;
|
||||
|
||||
gtk_widget_add_css_class(chip, "ghost-host");
|
||||
|
||||
g_timeout_add(16, asm_fly_tick, fc);
|
||||
} else {
|
||||
/* No usable animation layer yet – just move instantly. */
|
||||
if (pos >= 0) {
|
||||
for (int i = pos; i < sb->placed_count - 1; i++)
|
||||
sb->placed[i] = sb->placed[i + 1];
|
||||
sb->placed_count--;
|
||||
} else {
|
||||
sb->placed[sb->placed_count++] = idx;
|
||||
}
|
||||
sent_rebuild(sb);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SentBuilder **sbs;
|
||||
int n;
|
||||
|
|
@ -1618,9 +1762,11 @@ static GtkWidget *build_assembly(const char *title, const char *subtitle,
|
|||
for (int s = 0; s < n; s++) {
|
||||
const AssemblyItem *item = &items[s];
|
||||
SentBuilder *sb = g_new0(SentBuilder, 1);
|
||||
GtkWidget *holder;
|
||||
GtkWidget *group;
|
||||
GtkWidget *target;
|
||||
GtkWidget *pool;
|
||||
GtkWidget *stage;
|
||||
|
||||
sb->n_words = item->n;
|
||||
ctx->sbs[s] = sb;
|
||||
|
|
@ -1632,9 +1778,13 @@ static GtkWidget *build_assembly(const char *title, const char *subtitle,
|
|||
gtk_box_append(GTK_BOX(body), prompt);
|
||||
}
|
||||
|
||||
holder = gtk_overlay_new();
|
||||
gtk_widget_set_hexpand(holder, TRUE);
|
||||
|
||||
group = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
|
||||
gtk_widget_add_css_class(group, "sent-group");
|
||||
sb->group = group;
|
||||
gtk_overlay_set_child(GTK_OVERLAY(holder), group);
|
||||
|
||||
target = gtk_flow_box_new();
|
||||
gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(target), GTK_SELECTION_NONE);
|
||||
|
|
@ -1650,6 +1800,13 @@ static GtkWidget *build_assembly(const char *title, const char *subtitle,
|
|||
sb->pool = pool;
|
||||
gtk_box_append(GTK_BOX(group), pool);
|
||||
|
||||
stage = gtk_fixed_new();
|
||||
gtk_widget_set_halign(stage, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_valign(stage, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_can_target(stage, FALSE);
|
||||
gtk_overlay_add_overlay(GTK_OVERLAY(holder), stage);
|
||||
sb->stage = stage;
|
||||
|
||||
{
|
||||
GtkDropTarget *dt = gtk_drop_target_new(G_TYPE_INT, GDK_ACTION_COPY);
|
||||
GtkDropTarget *dp = gtk_drop_target_new(G_TYPE_INT, GDK_ACTION_COPY);
|
||||
|
|
@ -1671,6 +1828,7 @@ static GtkWidget *build_assembly(const char *title, const char *subtitle,
|
|||
gtk_drag_source_set_actions(src, GDK_ACTION_COPY);
|
||||
g_signal_connect(src, "prepare", G_CALLBACK(asm_drag_prepare), ref);
|
||||
g_signal_connect(src, "drag-end", G_CALLBACK(asm_drag_end), ref);
|
||||
g_signal_connect(chip, "clicked", G_CALLBACK(asm_move_by_click), ref);
|
||||
gtk_widget_add_controller(chip, GTK_EVENT_CONTROLLER(src));
|
||||
}
|
||||
|
||||
|
|
@ -1683,7 +1841,7 @@ static GtkWidget *build_assembly(const char *title, const char *subtitle,
|
|||
gtk_flow_box_insert(GTK_FLOW_BOX(pool), sb->chips[order[w]], -1);
|
||||
}
|
||||
|
||||
gtk_box_append(GTK_BOX(body), group);
|
||||
gtk_box_append(GTK_BOX(body), holder);
|
||||
|
||||
if (meanings[s])
|
||||
sb->trans = meaning_add(body, meanings[s]);
|
||||
|
|
@ -1821,7 +1979,7 @@ static const AssemblyItem ex2_items[] = {
|
|||
{NULL, {"Ich", "heiße", "Anna", "."}, 4},
|
||||
{NULL, {"Woher", "kommst", "du", "?"}, 4},
|
||||
{NULL, {"Ich", "komme", "aus", "Tschechien", "."}, 5},
|
||||
{NULL, {"Wie", "geht", "es", "dir", "?"}, 4},
|
||||
{NULL, {"Wie", "geht", "es", "dir", "?"}, 5},
|
||||
};
|
||||
|
||||
static const char *ex2_meaning[] = {
|
||||
|
|
@ -3142,6 +3300,9 @@ static void activate(GtkApplication *app, gpointer user_data) {
|
|||
" background-color: #45475a;"
|
||||
" border-color: #cba6f7;"
|
||||
"}"
|
||||
".chip.ghost-host {"
|
||||
" opacity: 0;"
|
||||
"}"
|
||||
".group-btn {"
|
||||
" background-color: #2b2d40;"
|
||||
" color: #cdd6f4;"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue