コード例 #1
0
/**
 * Translate any popup regions (so we can drag them).
 */
void ui_popup_translate(ARegion *ar, const int mdiff[2])
{
  uiBlock *block;

  BLI_rcti_translate(&ar->winrct, UNPACK2(mdiff));

  ED_region_update_rect(ar);

  ED_region_tag_redraw(ar);

  /* update blocks */
  for (block = ar->uiblocks.first; block; block = block->next) {
    uiPopupBlockHandle *handle = block->handle;
    /* Make empty, will be initialized on next use, see T60608. */
    BLI_rctf_init(&handle->prev_block_rect, 0, 0, 0, 0);

    uiSafetyRct *saferct;
    for (saferct = block->saferct.first; saferct; saferct = saferct->next) {
      BLI_rctf_translate(&saferct->parent, UNPACK2(mdiff));
      BLI_rctf_translate(&saferct->safety, UNPACK2(mdiff));
    }
  }
}
コード例 #2
0
void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
{
	rctf rect;

	if ((!g->width) || (!g->height))
		return;

	if (g->build_tex == 0) {
		GlyphCacheBLF *gc = font->glyph_cache;

		if (font->max_tex_size == -1)
			glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);

		if (gc->cur_tex == BLF_CURTEX_UNSET) {
			blf_glyph_cache_texture(font, gc);
			gc->x_offs = gc->pad;
			gc->y_offs = 0;
		}

		if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) {
			gc->x_offs = gc->pad;
			gc->y_offs += gc->max_glyph_height;

			if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) {
				gc->y_offs = 0;
				blf_glyph_cache_texture(font, gc);
			}
		}

		g->tex = gc->textures[gc->cur_tex];
		g->xoff = gc->x_offs;
		g->yoff = gc->y_offs;

		/* prevent glTexSubImage2D from failing if the character
		 * asks for pixels out of bounds, this tends only to happen
		 * with very small sizes (5px high or less) */
		if (UNLIKELY((g->xoff + g->width)  > gc->p2_width)) {
			g->width  -= (g->xoff + g->width)  - gc->p2_width;
			BLI_assert(g->width > 0);
		}
		if (UNLIKELY((g->yoff + g->height) > gc->p2_height)) {
			g->height -= (g->yoff + g->height) - gc->p2_height;
			BLI_assert(g->height > 0);
		}


		glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
		glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
		glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

		glBindTexture(GL_TEXTURE_2D, g->tex);
		glTexSubImage2D(GL_TEXTURE_2D, 0, g->xoff, g->yoff, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap);
		glPopClientAttrib();

		g->uv[0][0] = ((float)g->xoff) / ((float)gc->p2_width);
		g->uv[0][1] = ((float)g->yoff) / ((float)gc->p2_height);
		g->uv[1][0] = ((float)(g->xoff + g->width)) / ((float)gc->p2_width);
		g->uv[1][1] = ((float)(g->yoff + g->height)) / ((float)gc->p2_height);

		/* update the x offset for the next glyph. */
		gc->x_offs += (int)BLI_rctf_size_x(&g->box) + gc->pad;

		gc->rem_glyphs--;
		g->build_tex = 1;
	}

	blf_glyph_calc_rect(&rect, g, x, y);

	if (font->flags & BLF_CLIPPING) {
		/* intentionally check clipping without shadow offset */
		rctf rect_test = rect;
		BLI_rctf_translate(&rect_test, font->pos[0], font->pos[1]);

		if (!BLI_rctf_inside_rctf(&font->clip_rec, &rect_test)) {
			return;
		}
	}

	if (font->tex_bind_state != g->tex) {
		glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex));
	}

	if (font->flags & BLF_SHADOW) {
		rctf rect_ofs;
		blf_glyph_calc_rect(&rect_ofs, g,
		                    x + (float)font->shadow_x,
		                    y + (float)font->shadow_y);

		switch (font->shadow) {
			case 3:
				blf_texture3_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
				break;
			case 5:
				blf_texture5_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
				break;
			default:
				glColor4fv(font->shadow_col);
				blf_texture_draw(g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
				break;
		}

		glColor4fv(font->orig_col);
	}

	switch (font->blur) {
		case 3:
			blf_texture3_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
			break;
		case 5:
			blf_texture5_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
			break;
		default:
			blf_texture_draw(g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
			break;
	}

	return;
}
コード例 #3
0
/* position block relative to but, result is in window space */
static void ui_popup_block_position(wmWindow *window,
                                    ARegion *butregion,
                                    uiBut *but,
                                    uiBlock *block)
{
  uiPopupBlockHandle *handle = block->handle;

  /* Compute button position in window coordinates using the source
   * button region/block, to position the popup attached to it. */
  rctf butrct;

  if (!handle->refresh) {
    ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);

    /* widget_roundbox_set has this correction too, keep in sync */
    if (but->type != UI_BTYPE_PULLDOWN) {
      if (but->drawflag & UI_BUT_ALIGN_TOP) {
        butrct.ymax += U.pixelsize;
      }
      if (but->drawflag & UI_BUT_ALIGN_LEFT) {
        butrct.xmin -= U.pixelsize;
      }
    }

    handle->prev_butrct = butrct;
  }
  else {
    /* For refreshes, keep same button position so popup doesn't move. */
    butrct = handle->prev_butrct;
  }

  /* Compute block size in window space, based on buttons contained in it. */
  if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
    if (block->buttons.first) {
      BLI_rctf_init_minmax(&block->rect);

      for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
        if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) {
          bt->rect.xmax += UI_MENU_SUBMENU_PADDING;
        }
        BLI_rctf_union(&block->rect, &bt->rect);
      }
    }
    else {
      /* we're nice and allow empty blocks too */
      block->rect.xmin = block->rect.ymin = 0;
      block->rect.xmax = block->rect.ymax = 20;
    }
  }

  ui_block_to_window_rctf(butregion, but->block, &block->rect, &block->rect);

  /* Compute direction relative to button, based on available space. */
  const int size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X; /* 4 for shadow */
  const int size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y;
  const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0;
  const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;

  short dir1 = 0, dir2 = 0;

  if (!handle->refresh) {
    bool left = 0, right = 0, top = 0, down = 0;

    const int win_x = WM_window_pixels_x(window);
    const int win_y = WM_window_pixels_y(window);

    /* Take into account maximum size so we don't have to flip on refresh. */
    const float max_size_x = max_ff(size_x, handle->max_size_x);
    const float max_size_y = max_ff(size_y, handle->max_size_y);

    /* check if there's space at all */
    if (butrct.xmin - max_size_x + center_x > 0.0f) {
      left = 1;
    }
    if (butrct.xmax + max_size_x - center_x < win_x) {
      right = 1;
    }
    if (butrct.ymin - max_size_y + center_y > 0.0f) {
      down = 1;
    }
    if (butrct.ymax + max_size_y - center_y < win_y) {
      top = 1;
    }

    if (top == 0 && down == 0) {
      if (butrct.ymin - max_size_y < win_y - butrct.ymax - max_size_y) {
        top = 1;
      }
      else {
        down = 1;
      }
    }

    dir1 = (block->direction & UI_DIR_ALL);

    /* Secondary directions. */
    if (dir1 & (UI_DIR_UP | UI_DIR_DOWN)) {
      if (dir1 & UI_DIR_LEFT) {
        dir2 = UI_DIR_LEFT;
      }
      else if (dir1 & UI_DIR_RIGHT) {
        dir2 = UI_DIR_RIGHT;
      }
      dir1 &= (UI_DIR_UP | UI_DIR_DOWN);
    }

    if ((dir2 == 0) && (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT)) {
      dir2 = UI_DIR_DOWN;
    }
    if ((dir2 == 0) && (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN)) {
      dir2 = UI_DIR_LEFT;
    }

    /* no space at all? don't change */
    if (left || right) {
      if (dir1 == UI_DIR_LEFT && left == 0) {
        dir1 = UI_DIR_RIGHT;
      }
      if (dir1 == UI_DIR_RIGHT && right == 0) {
        dir1 = UI_DIR_LEFT;
      }
      /* this is aligning, not append! */
      if (dir2 == UI_DIR_LEFT && right == 0) {
        dir2 = UI_DIR_RIGHT;
      }
      if (dir2 == UI_DIR_RIGHT && left == 0) {
        dir2 = UI_DIR_LEFT;
      }
    }
    if (down || top) {
      if (dir1 == UI_DIR_UP && top == 0) {
        dir1 = UI_DIR_DOWN;
      }
      if (dir1 == UI_DIR_DOWN && down == 0) {
        dir1 = UI_DIR_UP;
      }
      BLI_assert(dir2 != UI_DIR_UP);
      //          if (dir2 == UI_DIR_UP   && top == 0)  { dir2 = UI_DIR_DOWN; }
      if (dir2 == UI_DIR_DOWN && down == 0) {
        dir2 = UI_DIR_UP;
      }
    }

    handle->prev_dir1 = dir1;
    handle->prev_dir2 = dir2;
  }
  else {
    /* For refreshes, keep same popup direct so popup doesn't move
     * to a totally different position while editing in it. */
    dir1 = handle->prev_dir1;
    dir2 = handle->prev_dir2;
  }

  /* Compute offset based on direction. */
  float offset_x = 0, offset_y = 0;

  /* Ensure buttons don't come between the parent button and the popup, see: T63566. */
  const float offset_overlap = max_ff(U.pixelsize, 1.0f);

  if (dir1 == UI_DIR_LEFT) {
    offset_x = (butrct.xmin - block->rect.xmax) + offset_overlap;
    if (dir2 == UI_DIR_UP) {
      offset_y = butrct.ymin - block->rect.ymin - center_y - UI_MENU_PADDING;
    }
    else {
      offset_y = butrct.ymax - block->rect.ymax + center_y + UI_MENU_PADDING;
    }
  }
  else if (dir1 == UI_DIR_RIGHT) {
    offset_x = (butrct.xmax - block->rect.xmin) - offset_overlap;
    if (dir2 == UI_DIR_UP) {
      offset_y = butrct.ymin - block->rect.ymin - center_y - UI_MENU_PADDING;
    }
    else {
      offset_y = butrct.ymax - block->rect.ymax + center_y + UI_MENU_PADDING;
    }
  }
  else if (dir1 == UI_DIR_UP) {
    offset_y = (butrct.ymax - block->rect.ymin) - offset_overlap;
    if (dir2 == UI_DIR_RIGHT) {
      offset_x = butrct.xmax - block->rect.xmax + center_x;
    }
    else {
      offset_x = butrct.xmin - block->rect.xmin - center_x;
    }
    /* changed direction? */
    if ((dir1 & block->direction) == 0) {
      /* TODO: still do */
      UI_block_order_flip(block);
    }
  }
  else if (dir1 == UI_DIR_DOWN) {
    offset_y = (butrct.ymin - block->rect.ymax) + offset_overlap;
    if (dir2 == UI_DIR_RIGHT) {
      offset_x = butrct.xmax - block->rect.xmax + center_x;
    }
    else {
      offset_x = butrct.xmin - block->rect.xmin - center_x;
    }
    /* changed direction? */
    if ((dir1 & block->direction) == 0) {
      /* TODO: still do */
      UI_block_order_flip(block);
    }
  }

  /* Center over popovers for eg. */
  if (block->direction & UI_DIR_CENTER_X) {
    offset_x += BLI_rctf_size_x(&butrct) / ((dir2 == UI_DIR_LEFT) ? 2 : -2);
  }

  /* Apply offset, buttons in window coords. */
  for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
    ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect);

    BLI_rctf_translate(&bt->rect, offset_x, offset_y);

    /* ui_but_update recalculates drawstring size in pixels */
    ui_but_update(bt);
  }

  BLI_rctf_translate(&block->rect, offset_x, offset_y);

  /* Safety calculus. */
  {
    const float midx = BLI_rctf_cent_x(&butrct);
    const float midy = BLI_rctf_cent_y(&butrct);

    /* when you are outside parent button, safety there should be smaller */

    /* parent button to left */
    if (midx < block->rect.xmin) {
      block->safety.xmin = block->rect.xmin - 3;
    }
    else {
      block->safety.xmin = block->rect.xmin - 40;
    }
    /* parent button to right */
    if (midx > block->rect.xmax) {
      block->safety.xmax = block->rect.xmax + 3;
    }
    else {
      block->safety.xmax = block->rect.xmax + 40;
    }

    /* parent button on bottom */
    if (midy < block->rect.ymin) {
      block->safety.ymin = block->rect.ymin - 3;
    }
    else {
      block->safety.ymin = block->rect.ymin - 40;
    }
    /* parent button on top */
    if (midy > block->rect.ymax) {
      block->safety.ymax = block->rect.ymax + 3;
    }
    else {
      block->safety.ymax = block->rect.ymax + 40;
    }

    /* exception for switched pulldowns... */
    if (dir1 && (dir1 & block->direction) == 0) {
      if (dir2 == UI_DIR_RIGHT) {
        block->safety.xmax = block->rect.xmax + 3;
      }
      if (dir2 == UI_DIR_LEFT) {
        block->safety.xmin = block->rect.xmin - 3;
      }
    }
    block->direction = dir1;
  }

  /* keep a list of these, needed for pulldown menus */
  uiSafetyRct *saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
  saferct->parent = butrct;
  saferct->safety = block->safety;
  BLI_freelistN(&block->saferct);
  BLI_duplicatelist(&block->saferct, &but->block->saferct);
  BLI_addhead(&block->saferct, saferct);
}
コード例 #4
0
ファイル: rct.c プロジェクト: flair2005/mechanical-blender
void BLI_rctf_recenter(rctf *rect, float x, float y)
{
	const float dx = x - BLI_rctf_cent_x(rect);
	const float dy = y - BLI_rctf_cent_y(rect);
	BLI_rctf_translate(rect, dx, dy);
}