| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357 |
- // Copyright (C) 2004-2022 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF 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 Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "gl-app.h"
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #ifndef FREEGLUT
- /* freeglut extension no-ops */
- void glutExit(void) {}
- void glutMouseWheelFunc(void *fn) {}
- void glutInitErrorFunc(void *fn) {}
- void glutInitWarningFunc(void *fn) {}
- #define glutSetOption(X,Y)
- #endif
- enum
- {
- /* Default UI sizes */
- DEFAULT_UI_FONTSIZE = 15,
- DEFAULT_UI_BASELINE = 14,
- DEFAULT_UI_LINEHEIGHT = 18,
- DEFAULT_UI_GRIDSIZE = DEFAULT_UI_LINEHEIGHT + 6,
- };
- struct ui ui;
- #if defined(FREEGLUT) && (GLUT_API_VERSION >= 6)
- void ui_set_clipboard(const char *buf)
- {
- glutSetClipboard(GLUT_PRIMARY, buf);
- glutSetClipboard(GLUT_CLIPBOARD, buf);
- }
- const char *ui_get_clipboard(void)
- {
- return glutGetClipboard(GLUT_CLIPBOARD);
- }
- #else
- static char *clipboard_buffer = NULL;
- void ui_set_clipboard(const char *buf)
- {
- fz_free(ctx, clipboard_buffer);
- clipboard_buffer = fz_strdup(ctx, buf);
- }
- const char *ui_get_clipboard(void)
- {
- return clipboard_buffer;
- }
- #endif
- static const char *ogl_error_string(GLenum code)
- {
- #define CASE(E) case E: return #E; break
- switch (code)
- {
- /* glGetError */
- CASE(GL_NO_ERROR);
- CASE(GL_INVALID_ENUM);
- CASE(GL_INVALID_VALUE);
- CASE(GL_INVALID_OPERATION);
- CASE(GL_OUT_OF_MEMORY);
- CASE(GL_STACK_UNDERFLOW);
- CASE(GL_STACK_OVERFLOW);
- default: return "(unknown)";
- }
- #undef CASE
- }
- static int has_ARB_texture_non_power_of_two = 1;
- static GLint max_texture_size = 8192;
- void ui_init_draw(void)
- {
- }
- static unsigned int next_power_of_two(unsigned int n)
- {
- --n;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- return ++n;
- }
- void ui_texture_from_pixmap(struct texture *tex, fz_pixmap *pix)
- {
- if (!tex->id)
- glGenTextures(1, &tex->id);
- glBindTexture(GL_TEXTURE_2D, tex->id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- tex->x = pix->x;
- tex->y = pix->y;
- tex->w = pix->w;
- tex->h = pix->h;
- if (has_ARB_texture_non_power_of_two)
- {
- if (tex->w > max_texture_size || tex->h > max_texture_size)
- fz_warn(ctx, "texture size (%d x %d) exceeds implementation limit (%d)", tex->w, tex->h, max_texture_size);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->w, tex->h, 0, pix->n == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pix->samples);
- tex->s = 1;
- tex->t = 1;
- }
- else
- {
- int w2 = next_power_of_two(tex->w);
- int h2 = next_power_of_two(tex->h);
- if (w2 > max_texture_size || h2 > max_texture_size)
- fz_warn(ctx, "texture size (%d x %d) exceeds implementation limit (%d)", w2, h2, max_texture_size);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w2, h2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex->w, tex->h, pix->n == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pix->samples);
- tex->s = (float) tex->w / w2;
- tex->t = (float) tex->h / h2;
- }
- }
- void ui_draw_image(struct texture *tex, float x, float y)
- {
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glBindTexture(GL_TEXTURE_2D, tex->id);
- glEnable(GL_TEXTURE_2D);
- glBegin(GL_TRIANGLE_STRIP);
- {
- glColor4f(1, 1, 1, 1);
- glTexCoord2f(0, tex->t);
- glVertex2f(x + tex->x, y + tex->y + tex->h);
- glTexCoord2f(0, 0);
- glVertex2f(x + tex->x, y + tex->y);
- glTexCoord2f(tex->s, tex->t);
- glVertex2f(x + tex->x + tex->w, y + tex->y + tex->h);
- glTexCoord2f(tex->s, 0);
- glVertex2f(x + tex->x + tex->w, y + tex->y);
- }
- glEnd();
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
- }
- void glColorHex(unsigned int hex)
- {
- float r = ((hex>>16)&0xff) / 255.0f;
- float g = ((hex>>8)&0xff) / 255.0f;
- float b = ((hex)&0xff) / 255.0f;
- glColor3f(r, g, b);
- }
- void ui_draw_bevel_imp(fz_irect area, unsigned ot, unsigned it, unsigned ib, unsigned ob)
- {
- glColorHex(ot);
- glRectf(area.x0, area.y0, area.x1-1, area.y0+1);
- glRectf(area.x0, area.y0+1, area.x0+1, area.y1-1);
- glColorHex(ob);
- glRectf(area.x1-1, area.y0, area.x1, area.y1);
- glRectf(area.x0, area.y1-1, area.x1-1, area.y1);
- glColorHex(it);
- glRectf(area.x0+1, area.y0+1, area.x1-2, area.y0+2);
- glRectf(area.x0+1, area.y0+2, area.x0+2, area.y1-2);
- glColorHex(ib);
- glRectf(area.x1-2, area.y0+1, area.x1-1, area.y1-1);
- glRectf(area.x0+1, area.y1-2, area.x1-2, area.y1-1);
- }
- void ui_draw_bevel(fz_irect area, int depressed)
- {
- if (depressed)
- ui_draw_bevel_imp(area, UI_COLOR_BEVEL_2, UI_COLOR_BEVEL_1, UI_COLOR_BEVEL_3, UI_COLOR_BEVEL_4);
- else
- ui_draw_bevel_imp(area, UI_COLOR_BEVEL_4, UI_COLOR_BEVEL_3, UI_COLOR_BEVEL_2, UI_COLOR_BEVEL_1);
- }
- void ui_draw_ibevel(fz_irect area, int depressed)
- {
- if (depressed)
- ui_draw_bevel_imp(area, UI_COLOR_BEVEL_2, UI_COLOR_BEVEL_1, UI_COLOR_BEVEL_3, UI_COLOR_BEVEL_4);
- else
- ui_draw_bevel_imp(area, UI_COLOR_BEVEL_3, UI_COLOR_BEVEL_4, UI_COLOR_BEVEL_2, UI_COLOR_BEVEL_1);
- }
- void ui_draw_bevel_rect(fz_irect area, unsigned int fill, int depressed)
- {
- ui_draw_bevel(area, depressed);
- glColorHex(fill);
- glRectf(area.x0+2, area.y0+2, area.x1-2, area.y1-2);
- }
- void ui_draw_ibevel_rect(fz_irect area, unsigned int fill, int depressed)
- {
- ui_draw_ibevel(area, depressed);
- glColorHex(fill);
- glRectf(area.x0+2, area.y0+2, area.x1-2, area.y1-2);
- }
- #if defined(FREEGLUT) && (GLUT_API_VERSION >= 6)
- static void on_keyboard(int key, int x, int y)
- #else
- static void on_keyboard(unsigned char key, int x, int y)
- #endif
- {
- #ifdef __APPLE__
- /* Apple's GLUT has swapped DELETE and BACKSPACE */
- if (key == 8)
- key = 127;
- else if (key == 127)
- key = 8;
- #endif
- ui.x = x;
- ui.y = y;
- ui.key = key;
- ui.mod = glutGetModifiers();
- ui.plain = !(ui.mod & ~GLUT_ACTIVE_SHIFT);
- run_main_loop();
- ui.key = ui.plain = 0;
- ui_invalidate(); // TODO: leave this to caller
- }
- static void on_special(int key, int x, int y)
- {
- ui.x = x;
- ui.y = y;
- ui.key = 0;
- switch (key)
- {
- case GLUT_KEY_INSERT: ui.key = KEY_INSERT; break;
- #ifdef GLUT_KEY_DELETE
- case GLUT_KEY_DELETE: ui.key = KEY_DELETE; break;
- #endif
- case GLUT_KEY_RIGHT: ui.key = KEY_RIGHT; break;
- case GLUT_KEY_LEFT: ui.key = KEY_LEFT; break;
- case GLUT_KEY_DOWN: ui.key = KEY_DOWN; break;
- case GLUT_KEY_UP: ui.key = KEY_UP; break;
- case GLUT_KEY_PAGE_UP: ui.key = KEY_PAGE_UP; break;
- case GLUT_KEY_PAGE_DOWN: ui.key = KEY_PAGE_DOWN; break;
- case GLUT_KEY_HOME: ui.key = KEY_HOME; break;
- case GLUT_KEY_END: ui.key = KEY_END; break;
- case GLUT_KEY_F1: ui.key = KEY_F1; break;
- case GLUT_KEY_F2: ui.key = KEY_F2; break;
- case GLUT_KEY_F3: ui.key = KEY_F3; break;
- case GLUT_KEY_F4: ui.key = KEY_F4; break;
- case GLUT_KEY_F5: ui.key = KEY_F5; break;
- case GLUT_KEY_F6: ui.key = KEY_F6; break;
- case GLUT_KEY_F7: ui.key = KEY_F7; break;
- case GLUT_KEY_F8: ui.key = KEY_F8; break;
- case GLUT_KEY_F9: ui.key = KEY_F9; break;
- case GLUT_KEY_F10: ui.key = KEY_F10; break;
- case GLUT_KEY_F11: ui.key = KEY_F11; break;
- case GLUT_KEY_F12: ui.key = KEY_F12; break;
- }
- if (ui.key)
- {
- ui.mod = glutGetModifiers();
- ui.plain = !(ui.mod & ~GLUT_ACTIVE_SHIFT);
- run_main_loop();
- ui.key = ui.plain = 0;
- ui_invalidate(); // TODO: leave this to caller
- }
- }
- static void on_wheel(int wheel, int direction, int x, int y)
- {
- ui.scroll_x = wheel == 1 ? direction : 0;
- ui.scroll_y = wheel == 0 ? direction : 0;
- ui.mod = glutGetModifiers();
- run_main_loop();
- ui_invalidate(); // TODO: leave this to caller
- ui.scroll_x = ui.scroll_y = 0;
- }
- static void on_mouse(int button, int action, int x, int y)
- {
- ui.x = x;
- ui.y = y;
- if (action == GLUT_DOWN)
- {
- switch (button)
- {
- case GLUT_LEFT_BUTTON:
- ui.down_x = x;
- ui.down_y = y;
- ui.down = 1;
- break;
- case GLUT_MIDDLE_BUTTON:
- ui.middle_x = x;
- ui.middle_y = y;
- ui.middle = 1;
- break;
- case GLUT_RIGHT_BUTTON:
- ui.right_x = x;
- ui.right_y = y;
- ui.right = 1;
- break;
- case 3: on_wheel(0, 1, x, y); break;
- case 4: on_wheel(0, -1, x, y); break;
- case 5: on_wheel(1, 1, x, y); break;
- case 6: on_wheel(1, -1, x, y); break;
- }
- }
- else if (action == GLUT_UP)
- {
- switch (button)
- {
- case GLUT_LEFT_BUTTON: ui.down = 0; break;
- case GLUT_MIDDLE_BUTTON: ui.middle = 0; break;
- case GLUT_RIGHT_BUTTON: ui.right = 0; break;
- }
- }
- ui.mod = glutGetModifiers();
- run_main_loop();
- ui_invalidate(); // TODO: leave this to caller
- }
- static void on_motion(int x, int y)
- {
- ui.x = x;
- ui.y = y;
- ui_invalidate();
- }
- static void on_passive_motion(int x, int y)
- {
- ui.x = x;
- ui.y = y;
- ui_invalidate();
- }
- static void on_reshape(int w, int h)
- {
- ui.window_w = w;
- ui.window_h = h;
- }
- static void on_display(void)
- {
- run_main_loop();
- }
- static void on_error(const char *fmt, va_list ap)
- {
- #ifdef _WIN32
- char buf[1000];
- fz_vsnprintf(buf, sizeof buf, fmt, ap);
- MessageBoxA(NULL, buf, "MuPDF GLUT Error", MB_ICONERROR);
- #else
- fprintf(stderr, "GLUT error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- #endif
- }
- static void on_warning(const char *fmt, va_list ap)
- {
- fprintf(stderr, "GLUT warning: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- }
- static void on_timer(int timer_id)
- {
- if (reloadrequested)
- {
- reload();
- ui_invalidate();
- reloadrequested = 0;
- }
- glutTimerFunc(500, on_timer, 0);
- }
- void ui_init_dpi(float override_scale)
- {
- ui.scale = 1;
- if (override_scale)
- {
- ui.scale = override_scale;
- }
- else
- {
- int wmm = glutGet(GLUT_SCREEN_WIDTH_MM);
- int wpx = glutGet(GLUT_SCREEN_WIDTH);
- int hmm = glutGet(GLUT_SCREEN_HEIGHT_MM);
- int hpx = glutGet(GLUT_SCREEN_HEIGHT);
- if (wmm > 0 && hmm > 0)
- {
- float ppi = ((wpx * 254) / wmm + (hpx * 254) / hmm) / 20;
- if (ppi >= 288) ui.scale = 3;
- else if (ppi >= 192) ui.scale = 2;
- else if (ppi >= 144) ui.scale = 1.5f;
- }
- }
- ui.fontsize = DEFAULT_UI_FONTSIZE * ui.scale;
- ui.baseline = DEFAULT_UI_BASELINE * ui.scale;
- ui.lineheight = DEFAULT_UI_LINEHEIGHT * ui.scale;
- ui.gridsize = DEFAULT_UI_GRIDSIZE * ui.scale;
- ui.padsize = 2 * ui.scale;
- }
- void ui_init(int w, int h, const char *title)
- {
- #ifdef FREEGLUT
- glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
- #endif
- glutInitErrorFunc(on_error);
- glutInitWarningFunc(on_warning);
- glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
- glutInitWindowSize(w, h);
- glutCreateWindow(title);
- glutTimerFunc(500, on_timer, 0);
- glutReshapeFunc(on_reshape);
- glutDisplayFunc(on_display);
- #if defined(FREEGLUT) && (GLUT_API_VERSION >= 6)
- glutKeyboardExtFunc(on_keyboard);
- #else
- fz_warn(ctx, "This version of MuPDF has been built WITHOUT clipboard or unicode input support!");
- fz_warn(ctx, "Please file a complaint with your friendly local distribution manager.");
- glutKeyboardFunc(on_keyboard);
- #endif
- glutSpecialFunc(on_special);
- glutMouseFunc(on_mouse);
- glutMotionFunc(on_motion);
- glutPassiveMotionFunc(on_passive_motion);
- glutMouseWheelFunc(on_wheel);
- has_ARB_texture_non_power_of_two = glutExtensionSupported("GL_ARB_texture_non_power_of_two");
- if (!has_ARB_texture_non_power_of_two)
- fz_warn(ctx, "OpenGL implementation does not support non-power of two texture sizes");
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
- ui_init_fonts();
- ui.overlay_list = glGenLists(1);
- }
- void ui_finish(void)
- {
- pdf_drop_annot(ctx, ui.selected_annot);
- glDeleteLists(ui.overlay_list, 1);
- ui_finish_fonts();
- glutExit();
- }
- void ui_invalidate(void)
- {
- glutPostRedisplay();
- }
- void ui_begin(void)
- {
- ui.hot = NULL;
- ui.cavity = ui.cavity_stack;
- ui.cavity->x0 = 0;
- ui.cavity->y0 = 0;
- ui.cavity->x1 = ui.window_w;
- ui.cavity->y1 = ui.window_h;
- ui.layout = ui.layout_stack;
- ui.layout->side = ALL;
- ui.layout->fill = BOTH;
- ui.layout->anchor = NW;
- ui.layout->padx = 0;
- ui.layout->pady = 0;
- ui.cursor = GLUT_CURSOR_INHERIT;
- ui.overlay = 0;
- glViewport(0, 0, ui.window_w, ui.window_h);
- glClear(GL_COLOR_BUFFER_BIT);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, ui.window_w, ui.window_h, 0, -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- void ui_end(void)
- {
- int code;
- if (ui.overlay)
- glCallList(ui.overlay_list);
- if (ui.cursor != ui.last_cursor)
- {
- glutSetCursor(ui.cursor);
- ui.last_cursor = ui.cursor;
- }
- code = glGetError();
- if (code != GL_NO_ERROR)
- fz_warn(ctx, "glGetError: %s", ogl_error_string(code));
- if (!ui.active && (ui.down || ui.middle || ui.right))
- ui.active = "dummy";
- if ((ui.grab_down && !ui.down) || (ui.grab_middle && !ui.middle) || (ui.grab_right && !ui.right))
- {
- ui.grab_down = ui.grab_middle = ui.grab_right = 0;
- ui.active = NULL;
- }
- if (ui.active)
- {
- if (ui.active != ui.focus)
- ui.focus = NULL;
- if (!ui.grab_down && !ui.grab_middle && !ui.grab_right)
- {
- ui.grab_down = ui.down;
- ui.grab_middle = ui.middle;
- ui.grab_right = ui.right;
- }
- }
- glutSwapBuffers();
- }
- /* Widgets */
- int ui_mouse_inside(fz_irect area)
- {
- if (ui.x >= area.x0 && ui.x < area.x1 && ui.y >= area.y0 && ui.y < area.y1)
- return 1;
- return 0;
- }
- fz_irect ui_pack_layout(int slave_w, int slave_h, enum side side, enum fill fill, enum anchor anchor, int padx, int pady)
- {
- fz_irect parcel, slave;
- int parcel_w, parcel_h;
- int anchor_x, anchor_y;
- switch (side)
- {
- default:
- case ALL:
- parcel.x0 = ui.cavity->x0 + padx;
- parcel.x1 = ui.cavity->x1 - padx;
- parcel.y0 = ui.cavity->y0 + pady;
- parcel.y1 = ui.cavity->y1 - pady;
- ui.cavity->x0 = ui.cavity->x1;
- ui.cavity->y0 = ui.cavity->y1;
- break;
- case T:
- parcel.x0 = ui.cavity->x0 + padx;
- parcel.x1 = ui.cavity->x1 - padx;
- parcel.y0 = ui.cavity->y0 + pady;
- parcel.y1 = ui.cavity->y0 + pady + slave_h;
- ui.cavity->y0 = parcel.y1 + pady;
- break;
- case B:
- parcel.x0 = ui.cavity->x0 + padx;
- parcel.x1 = ui.cavity->x1 - padx;
- parcel.y0 = ui.cavity->y1 - pady - slave_h;
- parcel.y1 = ui.cavity->y1 - pady;
- ui.cavity->y1 = parcel.y0 - pady;
- break;
- case L:
- parcel.x0 = ui.cavity->x0 + padx;
- parcel.x1 = ui.cavity->x0 + padx + slave_w;
- parcel.y0 = ui.cavity->y0 + pady;
- parcel.y1 = ui.cavity->y1 - pady;
- ui.cavity->x0 = parcel.x1 + padx;
- break;
- case R:
- parcel.x0 = ui.cavity->x1 - padx - slave_w;
- parcel.x1 = ui.cavity->x1 - padx;
- parcel.y0 = ui.cavity->y0 + pady;
- parcel.y1 = ui.cavity->y1 - pady;
- ui.cavity->x1 = parcel.x0 - padx;
- break;
- }
- parcel_w = parcel.x1 - parcel.x0;
- parcel_h = parcel.y1 - parcel.y0;
- if (fill & X)
- slave_w = parcel_w;
- if (fill & Y)
- slave_h = parcel_h;
- anchor_x = parcel_w - slave_w;
- anchor_y = parcel_h - slave_h;
- switch (anchor)
- {
- default:
- case CENTER:
- slave.x0 = parcel.x0 + anchor_x / 2;
- slave.y0 = parcel.y0 + anchor_y / 2;
- break;
- case N:
- slave.x0 = parcel.x0 + anchor_x / 2;
- slave.y0 = parcel.y0;
- break;
- case NE:
- slave.x0 = parcel.x0 + anchor_x;
- slave.y0 = parcel.y0;
- break;
- case E:
- slave.x0 = parcel.x0 + anchor_x;
- slave.y0 = parcel.y0 + anchor_y / 2;
- break;
- case SE:
- slave.x0 = parcel.x0 + anchor_x;
- slave.y0 = parcel.y0 + anchor_y;
- break;
- case S:
- slave.x0 = parcel.x0 + anchor_x / 2;
- slave.y0 = parcel.y0 + anchor_y;
- break;
- case SW:
- slave.x0 = parcel.x0;
- slave.y0 = parcel.y0 + anchor_y;
- break;
- case W:
- slave.x0 = parcel.x0;
- slave.y0 = parcel.y0 + anchor_y / 2;
- break;
- case NW:
- slave.x0 = parcel.x0;
- slave.y0 = parcel.y0;
- break;
- }
- slave.x1 = slave.x0 + slave_w;
- slave.y1 = slave.y0 + slave_h;
- return slave;
- }
- fz_irect ui_pack(int slave_w, int slave_h)
- {
- return ui_pack_layout(slave_w, slave_h, ui.layout->side, ui.layout->fill, ui.layout->anchor, ui.layout->padx, ui.layout->pady);
- }
- int ui_available_width(void)
- {
- return ui.cavity->x1 - ui.cavity->x0 - ui.layout->padx * 2;
- }
- int ui_available_height(void)
- {
- return ui.cavity->y1 - ui.cavity->y0 - ui.layout->pady * 2;
- }
- void ui_pack_push(fz_irect cavity)
- {
- *(++ui.cavity) = cavity;
- ++ui.layout;
- ui.layout->side = ALL;
- ui.layout->fill = BOTH;
- ui.layout->anchor = NW;
- ui.layout->padx = 0;
- ui.layout->pady = 0;
- }
- void ui_pack_pop(void)
- {
- --ui.cavity;
- --ui.layout;
- }
- void ui_layout(enum side side, enum fill fill, enum anchor anchor, int padx, int pady)
- {
- ui.layout->side = side;
- ui.layout->fill = fill;
- ui.layout->anchor = anchor;
- ui.layout->padx = padx;
- ui.layout->pady = pady;
- }
- void ui_panel_begin(int w, int h, int padx, int pady, int opaque)
- {
- fz_irect area = ui_pack(w, h);
- if (opaque)
- {
- glColorHex(UI_COLOR_PANEL);
- glRectf(area.x0, area.y0, area.x1, area.y1);
- }
- area.x0 += padx; area.y0 += pady;
- area.x1 -= padx; area.y1 -= pady;
- ui_pack_push(area);
- }
- void ui_panel_end(void)
- {
- ui_pack_pop();
- }
- void ui_dialog_begin(int w, int h)
- {
- fz_irect area;
- int x, y;
- w += 24 + 4;
- h += 24 + 4;
- if (w > ui.window_w) w = ui.window_w - 20;
- if (h > ui.window_h) h = ui.window_h - 20;
- x = (ui.window_w-w)/2;
- y = (ui.window_h-h)/3;
- area = fz_make_irect(x, y, x+w, y+h);
- ui_draw_bevel_rect(area, UI_COLOR_PANEL, 0);
- area = fz_expand_irect(area, -14);
- ui_pack_push(area);
- }
- void ui_dialog_end(void)
- {
- ui_pack_pop();
- }
- void ui_spacer(void)
- {
- ui_pack(ui.lineheight / 2, ui.lineheight / 2);
- }
- void ui_label(const char *fmt, ...)
- {
- char buf[512];
- struct line lines[20];
- int avail, used, n;
- fz_irect area;
- va_list ap;
- va_start(ap, fmt);
- fz_vsnprintf(buf, sizeof buf, fmt, ap);
- va_end(ap);
- avail = ui_available_width();
- n = ui_break_lines(buf, lines, nelem(lines), avail, &used);
- area = ui_pack(used, n * ui.lineheight);
- glColorHex(UI_COLOR_TEXT_FG);
- ui_draw_lines(area.x0, area.y0, lines, n);
- }
- int ui_button(const char *label)
- {
- return ui_button_aux(label, 0);
- }
- int ui_button_aux(const char *label, int flags)
- {
- int width = ui_measure_string(label);
- fz_irect area = ui_pack(width + 20, ui.gridsize);
- int text_x = area.x0 + ((area.x1 - area.x0) - width) / 2;
- int pressed = 0;
- int disabled = (flags & 1);
- if (!disabled)
- {
- if (ui_mouse_inside(area))
- {
- ui.hot = label;
- if (!ui.active && ui.down)
- ui.active = label;
- }
- pressed = (ui.hot == label && ui.active == label && ui.down);
- }
- ui_draw_bevel_rect(area, UI_COLOR_BUTTON, pressed);
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- ui_draw_string(text_x + pressed, area.y0+3 + pressed, label);
- return !disabled && ui.hot == label && ui.active == label && !ui.down;
- }
- int ui_checkbox(const char *label, int *value)
- {
- return ui_checkbox_aux(label, value, 0);
- }
- int ui_checkbox_aux(const char *label, int *value, int flags)
- {
- int width = ui_measure_string(label);
- fz_irect area = ui_pack(13 + 4 + width, ui.lineheight);
- fz_irect mark = { area.x0, area.y0 + ui.baseline-12, area.x0 + 13, area.y0 + ui.baseline+1 };
- int pressed = 0;
- int disabled = (flags & 1);
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- ui_draw_string(mark.x1 + 4, area.y0, label);
- if (!disabled)
- {
- if (ui_mouse_inside(area))
- {
- ui.hot = label;
- if (!ui.active && ui.down)
- ui.active = label;
- }
- if (ui.hot == label && ui.active == label && !ui.down)
- *value = !*value;
- pressed = (ui.hot == label && ui.active == label && ui.down);
- }
- ui_draw_bevel_rect(mark, (disabled || pressed) ? UI_COLOR_PANEL : UI_COLOR_TEXT_BG, 1);
- if (*value)
- {
- float ax = mark.x0+2 + 1, ay = mark.y0+2 + 3;
- float bx = mark.x0+2 + 4, by = mark.y0+2 + 5;
- float cx = mark.x0+2 + 8, cy = mark.y0+2 + 1;
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- glBegin(GL_TRIANGLE_STRIP);
- glVertex2f(ax, ay); glVertex2f(ax, ay+3);
- glVertex2f(bx, by); glVertex2f(bx, by+3);
- glVertex2f(cx, cy); glVertex2f(cx, cy+3);
- glEnd();
- }
- return !disabled && ui.hot == label && ui.active == label && !ui.down;
- }
- int ui_slider(int *value, int min, int max, int width)
- {
- static int start_value = 0;
- fz_irect area = ui_pack(width, ui.lineheight);
- int m = 6;
- int w = area.x1 - area.x0 - m * 2;
- int h = area.y1 - area.y0;
- fz_irect gutter = { area.x0, area.y0+h/2-2, area.x1, area.y0+h/2+2 };
- fz_irect thumb;
- int x;
- if (ui_mouse_inside(area))
- {
- ui.hot = value;
- if (!ui.active && ui.down)
- {
- ui.active = value;
- start_value = *value;
- }
- }
- if (ui.active == value)
- {
- if (ui.y < area.y0 || ui.y > area.y1)
- *value = start_value;
- else
- {
- float v = (float)(ui.x - (area.x0+m)) / w;
- *value = fz_clamp(min + v * (max - min), min, max);
- }
- }
- x = ((*value - min) * w) / (max - min);
- thumb = fz_make_irect(area.x0+m + x-m, area.y0, area.x0+m + x+m, area.y1);
- ui_draw_bevel(gutter, 1);
- ui_draw_bevel_rect(thumb, UI_COLOR_BUTTON, 0);
- return *value != start_value && ui.active == value && !ui.down;
- }
- void ui_splitter(int *start, int *v, int min, int max, enum side side)
- {
- fz_irect area = { 0 };
- if (side == L || side == R)
- area = ui_pack(4, 0);
- else if (side == T || side == B)
- area = ui_pack(0, 4);
- if (ui_mouse_inside(area))
- {
- ui.hot = v;
- if (!ui.active && ui.down)
- {
- ui.active = v;
- *start = *v;
- }
- }
- if (ui.active == v)
- {
- // how we slide the splitter coords depends on the packing direction
- switch (ui.layout->side)
- {
- default:
- case L: *v = fz_clampi(*start + (ui.x - ui.down_x), min, max); break;
- case R: *v = fz_clampi(*start + (ui.down_x - ui.x), min, max); break;
- case B: *v = fz_clampi(*start + (ui.down_y - ui.y), min, max); break;
- case T: *v = fz_clampi(*start + (ui.y - ui.down_y), min, max); break;
- }
- }
- if (ui.hot == v || ui.active == v)
- {
- if (side == L || side == R)
- ui.cursor = GLUT_CURSOR_LEFT_RIGHT;
- else if (side == T || side == B)
- ui.cursor = GLUT_CURSOR_UP_DOWN;
- }
- if (side == R)
- {
- glColorHex(UI_COLOR_PANEL);
- glRectf(area.x0+0, area.y0, area.x0+2, area.y1);
- glColorHex(UI_COLOR_BEVEL_2);
- glRectf(area.x0+2, area.y0, area.x0+3, area.y1);
- glColorHex(UI_COLOR_BEVEL_1);
- glRectf(area.x0+3, area.y0, area.x0+4, area.y1);
- }
- else if (side == L)
- {
- glColorHex(UI_COLOR_BEVEL_4);
- glRectf(area.x0+0, area.y0, area.x0+1, area.y1);
- glColorHex(UI_COLOR_BEVEL_3);
- glRectf(area.x0+1, area.y0, area.x0+3, area.y1);
- glColorHex(UI_COLOR_PANEL);
- glRectf(area.x0+2, area.y0, area.x0+4, area.y1);
- }
- else if (side == T)
- {
- glColorHex(UI_COLOR_BEVEL_4);
- glRectf(area.x0, area.y0+0, area.x1, area.y0+1);
- glColorHex(UI_COLOR_BEVEL_3);
- glRectf(area.x0, area.y0+1, area.x1, area.y0+2);
- glColorHex(UI_COLOR_PANEL);
- glRectf(area.x0, area.y0+2, area.x1, area.y0+4);
- }
- else if (side == B)
- {
- glColorHex(UI_COLOR_PANEL);
- glRectf(area.x0, area.y0+0, area.x1, area.y0+2);
- glColorHex(UI_COLOR_BEVEL_2);
- glRectf(area.x0, area.y0+2, area.x1, area.y0+3);
- glColorHex(UI_COLOR_BEVEL_1);
- glRectf(area.x0, area.y0+3, area.x1, area.y0+4);
- }
- }
- void ui_scrollbar(int x0, int y0, int x1, int y1, int *value, int page_size, int max, int *sticky)
- {
- static float start_top = 0; /* we can only drag in one scrollbar at a time, so static is safe */
- float top;
- int total_h = y1 - y0;
- int thumb_h = fz_maxi(x1 - x0, total_h * page_size / max);
- int avail_h = total_h - thumb_h;
- max -= page_size;
- if (max <= 0)
- {
- *value = 0;
- glColorHex(UI_COLOR_SCROLLBAR);
- glRectf(x0, y0, x1, y1);
- return;
- }
- if (sticky)
- {
- if (*sticky <= -1)
- *value = 0;
- else if (*sticky >= 1)
- *value = max;
- }
- top = (float) *value * avail_h / max;
- if (ui.down && !ui.active)
- {
- if (ui.x >= x0 && ui.x < x1 && ui.y >= y0 && ui.y < y1)
- {
- if (ui.y < y0 + top)
- {
- ui.active = "pgup";
- *value -= page_size;
- }
- else if (ui.y >= y0 + top + thumb_h)
- {
- ui.active = "pgdn";
- *value += page_size;
- }
- else
- {
- ui.hot = value;
- ui.active = value;
- start_top = top;
- }
- }
- }
- if (ui.active == value)
- {
- *value = (start_top + ui.y - ui.down_y) * max / avail_h;
- }
- if (*value < 0)
- *value = 0;
- else if (*value > max)
- *value = max;
- if (sticky)
- {
- if (*sticky == 0 && *value == 0)
- *sticky = -1;
- else if (*sticky == 0 && *value == max)
- *sticky = 1;
- else if (*sticky <= -1 && *value != 0)
- *sticky = 0;
- else if (*sticky >= 1 && *value != max)
- *sticky = 0;
- }
- top = (float) *value * avail_h / max;
- glColorHex(UI_COLOR_SCROLLBAR);
- glRectf(x0, y0, x1, y1);
- ui_draw_ibevel_rect(fz_make_irect(x0, y0+top, x1, y0+top+thumb_h), UI_COLOR_BUTTON, 0);
- }
- void ui_tree_begin(struct list *list, int count, int req_w, int req_h, int is_tree)
- {
- static int start_scroll_y = 0; /* we can only drag in one list at a time, so static is safe */
- fz_irect outer_area = ui_pack(req_w, req_h);
- fz_irect area = { outer_area.x0+2, outer_area.y0+2, outer_area.x1-2, outer_area.y1-2 };
- int max_scroll_y = count * ui.lineheight - (area.y1-area.y0);
- if (max_scroll_y > 0)
- area.x1 -= 16;
- if (ui_mouse_inside(area))
- {
- ui.hot = list;
- if (!ui.active && ui.middle)
- {
- ui.active = list;
- start_scroll_y = list->scroll_y;
- }
- }
- /* middle button dragging */
- if (ui.active == list)
- list->scroll_y = start_scroll_y + (ui.middle_y - ui.y) * 5;
- /* scroll wheel events */
- if (ui.hot == list)
- list->scroll_y -= ui.scroll_y * ui.lineheight * 3;
- /* keyboard keys */
- if (ui.hot == list && ui.key == KEY_HOME)
- list->scroll_y = 0;
- if (ui.hot == list && ui.key == KEY_END)
- list->scroll_y = max_scroll_y;
- if (ui.hot == list && ui.key == KEY_PAGE_UP)
- list->scroll_y -= ((area.y1 - area.y0) / ui.lineheight) * ui.lineheight;
- if (ui.hot == list && ui.key == KEY_PAGE_DOWN)
- list->scroll_y += ((area.y1 - area.y0) / ui.lineheight) * ui.lineheight;
- /* clamp scrolling to client area */
- if (list->scroll_y >= max_scroll_y)
- list->scroll_y = max_scroll_y;
- if (list->scroll_y < 0)
- list->scroll_y = 0;
- ui_draw_bevel_rect(outer_area, UI_COLOR_TEXT_BG, 1);
- if (max_scroll_y > 0)
- {
- ui_scrollbar(area.x1, area.y0, area.x1+16, area.y1,
- &list->scroll_y, area.y1-area.y0, count * ui.lineheight, NULL);
- }
- list->is_tree = is_tree;
- list->area = area;
- list->item_y = area.y0 - list->scroll_y;
- glScissor(list->area.x0, ui.window_h-list->area.y1, list->area.x1-list->area.x0, list->area.y1-list->area.y0);
- glEnable(GL_SCISSOR_TEST);
- }
- int ui_tree_item(struct list *list, const void *id, const char *label, int selected, int depth, int is_branch, int *is_open)
- {
- fz_irect area = { list->area.x0, list->item_y, list->area.x1, list->item_y + ui.lineheight };
- int x_handle, x_item;
- x_item = ui.lineheight / 4;
- x_item += depth * ui.lineheight;
- x_handle = x_item;
- if (list->is_tree)
- x_item += ui_measure_character(0x25BC) + ui.lineheight / 4;
- /* only process visible items */
- if (area.y1 >= list->area.y0 && area.y0 <= list->area.y1)
- {
- if (ui_mouse_inside(list->area) && ui_mouse_inside(area))
- {
- if (list->is_tree && ui.x < area.x0 + x_item)
- {
- ui.hot = is_open;
- }
- else
- ui.hot = id;
- if (!ui.active && ui.down)
- {
- if (list->is_tree && ui.hot == is_open)
- *is_open = !*is_open;
- ui.active = ui.hot;
- }
- }
- if (ui.active == id || selected)
- {
- glColorHex(UI_COLOR_TEXT_SEL_BG);
- glRectf(area.x0, area.y0, area.x1, area.y1);
- glColorHex(UI_COLOR_TEXT_SEL_FG);
- }
- else
- {
- glColorHex(UI_COLOR_TEXT_FG);
- }
- ui_draw_string(area.x0 + x_item, area.y0, label);
- if (list->is_tree && is_branch)
- ui_draw_character(area.x0 + x_handle, area.y0,
- *is_open ? 0x25BC : 0x25B6);
- }
- list->item_y += ui.lineheight;
- /* trigger on mouse up */
- return ui.active == id && !ui.down;
- }
- void ui_list_begin(struct list *list, int count, int req_w, int req_h)
- {
- ui_tree_begin(list, count, req_w, req_h, 0);
- }
- int ui_list_item(struct list *list, const void *id, const char *label, int selected)
- {
- return ui_tree_item(list, id, label, selected, 0, 0, NULL);
- }
- void ui_tree_end(struct list *list)
- {
- glDisable(GL_SCISSOR_TEST);
- }
- void ui_list_end(struct list *list)
- {
- ui_tree_end(list);
- }
- void ui_label_with_scrollbar(char *text, int width, int height, int *scroll, int *sticky)
- {
- struct line lines[500];
- fz_irect area;
- int n;
- area = ui_pack(width, height);
- n = ui_break_lines(text, lines, nelem(lines), area.x1-area.x0 - 16, NULL);
- if (n > (area.y1-area.y0) / ui.lineheight)
- {
- if (ui_mouse_inside(area))
- {
- *scroll -= ui.scroll_y * ui.lineheight * 3;
- if (ui.scroll_y != 0 && sticky)
- *sticky = 0;
- }
- ui_scrollbar(area.x1-16, area.y0, area.x1, area.y1,
- scroll, area.y1-area.y0, n * ui.lineheight, sticky);
- }
- else
- *scroll = 0;
- glScissor(area.x0, ui.window_h-area.y1, area.x1-area.x0-16, area.y1-area.y0);
- glEnable(GL_SCISSOR_TEST);
- glColorHex(UI_COLOR_TEXT_FG);
- ui_draw_lines(area.x0, area.y0 - *scroll, lines, n);
- glDisable(GL_SCISSOR_TEST);
- }
- int ui_popup(const void *id, const char *label, int is_button, int count)
- {
- return ui_popup_aux(id, label, is_button, count, 0);
- }
- int ui_popup_aux(const void *id, const char *label, int is_button, int count, int flags)
- {
- int width = ui_measure_string(label);
- fz_irect area = ui_pack(width + 22 + 6, ui.gridsize);
- fz_irect menu_area;
- int pressed = 0;
- int disabled = (flags & 1);
- if (!disabled)
- {
- if (ui_mouse_inside(area))
- {
- ui.hot = id;
- if (!ui.active && ui.down)
- ui.active = id;
- }
- pressed = (ui.active == id);
- }
- if (is_button)
- {
- ui_draw_bevel_rect(area, UI_COLOR_BUTTON, pressed);
- glColorHex(disabled? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- ui_draw_string(area.x0 + 6+pressed, area.y0+3+pressed, label);
- glBegin(GL_TRIANGLES);
- glVertex2f(area.x1+pressed-8-10, area.y0+pressed+9);
- glVertex2f(area.x1+pressed-8, area.y0+pressed+9);
- glVertex2f(area.x1+pressed-8-4, area.y0+pressed+14);
- glEnd();
- }
- else
- {
- fz_irect arrow = { area.x1-22, area.y0+2, area.x1-2, area.y1-2 };
- ui_draw_bevel_rect(area, UI_COLOR_TEXT_BG, 1);
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- ui_draw_string(area.x0 + 6, area.y0+3, label);
- ui_draw_ibevel_rect(arrow, UI_COLOR_BUTTON, pressed);
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- glBegin(GL_TRIANGLES);
- glVertex2f(area.x1+pressed-8-10, area.y0+pressed+9);
- glVertex2f(area.x1+pressed-8, area.y0+pressed+9);
- glVertex2f(area.x1+pressed-8-4, area.y0+pressed+14);
- glEnd();
- }
- if (pressed)
- {
- ui.overlay = 1;
- glNewList(ui.overlay_list, GL_COMPILE);
- /* Area inside the border line */
- menu_area.x0 = area.x0+1;
- menu_area.x1 = area.x1-1; // TODO: width of submenu
- if (area.y1+2 + count * ui.lineheight < ui.window_h)
- {
- menu_area.y0 = area.y1+2;
- menu_area.y1 = menu_area.y0 + count * ui.lineheight;
- }
- else
- {
- menu_area.y1 = area.y0-2;
- menu_area.y0 = menu_area.y1 - count * ui.lineheight;
- }
- glColorHex(UI_COLOR_TEXT_FG);
- glRectf(menu_area.x0-1, menu_area.y0-1, menu_area.x1+1, menu_area.y1+1);
- glColorHex(UI_COLOR_TEXT_BG);
- glRectf(menu_area.x0, menu_area.y0, menu_area.x1, menu_area.y1);
- ui_pack_push(menu_area);
- ui_layout(T, X, NW, 0, 0);
- }
- return pressed;
- }
- int ui_popup_item(const char *title)
- {
- return ui_popup_item_aux(title, 0);
- }
- int ui_popup_item_aux(const char *title, int flags)
- {
- fz_irect area = ui_pack(0, ui.lineheight);
- int disabled = (flags & 1);
- if (!disabled && ui_mouse_inside(area))
- {
- ui.hot = title;
- glColorHex(UI_COLOR_TEXT_SEL_BG);
- glRectf(area.x0, area.y0, area.x1, area.y1);
- glColorHex(UI_COLOR_TEXT_SEL_FG);
- ui_draw_string(area.x0 + 4, area.y0, title);
- }
- else
- {
- glColorHex(disabled ? UI_COLOR_TEXT_GRAY : UI_COLOR_TEXT_FG);
- ui_draw_string(area.x0 + 4, area.y0, title);
- }
- return !disabled && ui.hot == title && !ui.down;
- }
- void ui_popup_end(void)
- {
- glEndList();
- ui_pack_pop();
- }
- int ui_select(const void *id, const char *current, const char *options[], int n)
- {
- return ui_select_aux(id, current, options, n, 0);
- }
- int ui_select_aux(const void *id, const char *current, const char *options[], int n, int flags)
- {
- int i, choice = -1;
- if (ui_popup_aux(id, current, 0, n, flags))
- {
- for (i = 0; i < n; ++i)
- if (ui_popup_item_aux(options[i], flags))
- choice = i;
- ui_popup_end();
- }
- return choice;
- }
- void ui_select_annot(pdf_annot *annot)
- {
- pdf_drop_annot(ctx, ui.selected_annot);
- ui.selected_annot = annot;
- }
|