1/**************************************************************************/
2/* progress_bar.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "progress_bar.h"
32
33#include "scene/resources/text_line.h"
34#include "scene/theme/theme_db.h"
35
36Size2 ProgressBar::get_minimum_size() const {
37 Size2 minimum_size = theme_cache.background_style->get_minimum_size();
38 minimum_size.height = MAX(minimum_size.height, theme_cache.fill_style->get_minimum_size().height);
39 minimum_size.width = MAX(minimum_size.width, theme_cache.fill_style->get_minimum_size().width);
40 if (show_percentage) {
41 String txt = "100%";
42 TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
43 minimum_size.height = MAX(minimum_size.height, theme_cache.background_style->get_minimum_size().height + tl.get_size().y);
44 } else { // this is needed, else the progressbar will collapse
45 minimum_size.width = MAX(minimum_size.width, 1);
46 minimum_size.height = MAX(minimum_size.height, 1);
47 }
48 return minimum_size;
49}
50
51void ProgressBar::_notification(int p_what) {
52 switch (p_what) {
53 case NOTIFICATION_DRAW: {
54 draw_style_box(theme_cache.background_style, Rect2(Point2(), get_size()));
55
56 float r = get_as_ratio();
57
58 switch (mode) {
59 case FILL_BEGIN_TO_END:
60 case FILL_END_TO_BEGIN: {
61 int mp = theme_cache.fill_style->get_minimum_size().width;
62 int p = round(r * (get_size().width - mp));
63 // We want FILL_BEGIN_TO_END to map to right to left when UI layout is RTL,
64 // and left to right otherwise. And likewise for FILL_END_TO_BEGIN.
65 bool right_to_left = is_layout_rtl() ? (mode == FILL_BEGIN_TO_END) : (mode == FILL_END_TO_BEGIN);
66 if (p > 0) {
67 if (right_to_left) {
68 int p_remaining = round((1.0 - r) * (get_size().width - mp));
69 draw_style_box(theme_cache.fill_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fill_style->get_minimum_size().width, get_size().height)));
70 } else {
71 draw_style_box(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fill_style->get_minimum_size().width, get_size().height)));
72 }
73 }
74 } break;
75 case FILL_TOP_TO_BOTTOM:
76 case FILL_BOTTOM_TO_TOP: {
77 int mp = theme_cache.fill_style->get_minimum_size().height;
78 int p = round(r * (get_size().height - mp));
79
80 if (p > 0) {
81 if (mode == FILL_TOP_TO_BOTTOM) {
82 draw_style_box(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height)));
83 } else {
84 int p_remaining = round((1.0 - r) * (get_size().height - mp));
85 draw_style_box(theme_cache.fill_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height)));
86 }
87 }
88 } break;
89 case FILL_MODE_MAX:
90 break;
91 }
92
93 if (show_percentage) {
94 String txt = itos(int(get_as_ratio() * 100));
95 if (is_localizing_numeral_system()) {
96 txt = TS->format_number(txt) + TS->percent_sign();
97 } else {
98 txt += String("%");
99 }
100 TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
101 Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
102
103 if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
104 tl.draw_outline(get_canvas_item(), text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
105 }
106
107 tl.draw(get_canvas_item(), text_pos, theme_cache.font_color);
108 }
109 } break;
110 }
111}
112
113void ProgressBar::set_fill_mode(int p_fill) {
114 ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX);
115 mode = (FillMode)p_fill;
116 queue_redraw();
117}
118
119int ProgressBar::get_fill_mode() {
120 return mode;
121}
122
123void ProgressBar::set_show_percentage(bool p_visible) {
124 if (show_percentage == p_visible) {
125 return;
126 }
127 show_percentage = p_visible;
128 update_minimum_size();
129 queue_redraw();
130}
131
132bool ProgressBar::is_percentage_shown() const {
133 return show_percentage;
134}
135
136void ProgressBar::_bind_methods() {
137 ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &ProgressBar::set_fill_mode);
138 ClassDB::bind_method(D_METHOD("get_fill_mode"), &ProgressBar::get_fill_mode);
139 ClassDB::bind_method(D_METHOD("set_show_percentage", "visible"), &ProgressBar::set_show_percentage);
140 ClassDB::bind_method(D_METHOD("is_percentage_shown"), &ProgressBar::is_percentage_shown);
141
142 ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Begin to End,End to Begin,Top to Bottom,Bottom to Top"), "set_fill_mode", "get_fill_mode");
143 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_percentage"), "set_show_percentage", "is_percentage_shown");
144
145 BIND_ENUM_CONSTANT(FILL_BEGIN_TO_END);
146 BIND_ENUM_CONSTANT(FILL_END_TO_BEGIN);
147 BIND_ENUM_CONSTANT(FILL_TOP_TO_BOTTOM);
148 BIND_ENUM_CONSTANT(FILL_BOTTOM_TO_TOP);
149
150 BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ProgressBar, background_style, "background");
151 BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ProgressBar, fill_style, "fill");
152
153 BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, ProgressBar, font);
154 BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, ProgressBar, font_size);
155 BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ProgressBar, font_color);
156 BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ProgressBar, font_outline_size, "outline_size");
157 BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ProgressBar, font_outline_color);
158}
159
160ProgressBar::ProgressBar() {
161 set_v_size_flags(0);
162 set_step(0.01);
163}
164