Merge branch 'buttonset-issues' (fix #3554, merge #3565)

This commit is contained in:
David Capello 2023-02-28 15:08:50 -03:00
commit 355ceacff4
34 changed files with 826 additions and 388 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -7,7 +7,7 @@
</authors> </authors>
<fonts> <fonts>
<font id="default" font="Aseprite" /> <font id="default" font="Aseprite" />
<font id="mini" font="Aseprite Mini" /> <font id="mini" font="Aseprite Mini" mnemonics="off" />
</fonts> </fonts>
<dimensions> <dimensions>
<dim id="scrollbar_size" value="12" /> <dim id="scrollbar_size" value="12" />
@ -28,7 +28,7 @@
<dim id="timeline_base_size" value="12" /> <dim id="timeline_base_size" value="12" />
<dim id="color_bar_buttons_height" value="16" /> <dim id="color_bar_buttons_height" value="16" />
<dim id="context_bar_height" value="18" /> <dim id="context_bar_height" value="18" />
<dim id="brush_type_width" value="16" /> <dim id="brush_type_width" value="15" />
<dim id="color_selector_bar_size" value="8" /> <dim id="color_selector_bar_size" value="8" />
</dimensions> </dimensions>
<colors> <colors>
@ -113,7 +113,6 @@
<color id="flag_clicked" value="#41444a" /> <color id="flag_clicked" value="#41444a" />
<color id="select_box_ruler" value="#0000ff" /> <color id="select_box_ruler" value="#0000ff" />
<color id="select_box_grid" value="#64c864" /> <color id="select_box_grid" value="#64c864" />
<color id="edit_pal_face" value="#333333" />
<color id="palette_entries_separator" value="#000000" /> <color id="palette_entries_separator" value="#000000" />
</colors> </colors>
<parts> <parts>
@ -184,18 +183,18 @@
<part id="mini_slider_thumb_focused" x="48" y="176" w="5" h="4" /> <part id="mini_slider_thumb_focused" x="48" y="176" w="5" h="4" />
<part id="separator_horz" x="32" y="80" w="9" h="5" /> <part id="separator_horz" x="32" y="80" w="9" h="5" />
<part id="separator_vert" x="32" y="96" w="5" h="9" /> <part id="separator_vert" x="32" y="96" w="5" h="9" />
<part id="combobox_arrow_down" x="100" y="148" w="9" h="9" /> <part id="combobox_arrow_down" x="100" y="148" w="9" h="8" />
<part id="combobox_arrow_down_selected" x="116" y="148" w="9" h="9" /> <part id="combobox_arrow_down_selected" x="116" y="148" w="9" h="8" />
<part id="combobox_arrow_down_disabled" x="132" y="148" w="9" h="9" /> <part id="combobox_arrow_down_disabled" x="132" y="148" w="9" h="8" />
<part id="combobox_arrow_up" x="100" y="163" w="9" h="9" /> <part id="combobox_arrow_up" x="100" y="163" w="9" h="8" />
<part id="combobox_arrow_up_selected" x="116" y="163" w="9" h="9" /> <part id="combobox_arrow_up_selected" x="116" y="163" w="9" h="8" />
<part id="combobox_arrow_up_disabled" x="132" y="163" w="9" h="9" /> <part id="combobox_arrow_up_disabled" x="132" y="163" w="9" h="8" />
<part id="combobox_arrow_left" x="99" y="180" w="9" h="9" /> <part id="combobox_arrow_left" x="99" y="180" w="9" h="8" />
<part id="combobox_arrow_left_selected" x="115" y="180" w="9" h="9" /> <part id="combobox_arrow_left_selected" x="115" y="180" w="9" h="8" />
<part id="combobox_arrow_left_disabled" x="131" y="180" w="9" h="9" /> <part id="combobox_arrow_left_disabled" x="131" y="180" w="9" h="8" />
<part id="combobox_arrow_right" x="99" y="196" w="9" h="9" /> <part id="combobox_arrow_right" x="99" y="196" w="9" h="8" />
<part id="combobox_arrow_right_selected" x="115" y="196" w="9" h="9" /> <part id="combobox_arrow_right_selected" x="115" y="196" w="9" h="8" />
<part id="combobox_arrow_right_disabled" x="131" y="196" w="9" h="9" /> <part id="combobox_arrow_right_disabled" x="131" y="196" w="9" h="8" />
<part id="arrow_circle_cw" x="99" y="243" w="10" h="10" /> <part id="arrow_circle_cw" x="99" y="243" w="10" h="10" />
<part id="arrow_circle_cw_selected" x="115" y="243" w="10" h="10" /> <part id="arrow_circle_cw_selected" x="115" y="243" w="10" h="10" />
<part id="newfolder" x="99" y="211" w="9" h="9" /> <part id="newfolder" x="99" y="211" w="9" h="9" />
@ -207,11 +206,12 @@
<part id="toolbutton_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="toolbutton_last" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_last" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="toolbutton_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="buttonset_item_normal" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_normal" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_hot_focused" x="128" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_hot_focused" x="128" y="0" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_focused" x="128" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_focused" x="128" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_active" x="112" y="32" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="tab_normal" x="2" y="112" w1="4" w2="5" w3="5" h1="4" h2="6" h3="2" /> <part id="tab_normal" x="2" y="112" w1="4" w2="5" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_active" x="16" y="112" w1="4" w2="7" w3="5" h1="4" h2="6" h3="2" /> <part id="tab_active" x="16" y="112" w1="4" w2="7" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_bottom_active" x="16" y="124" w1="4" w2="7" w3="5" h1="2" h2="1" h3="2" /> <part id="tab_bottom_active" x="16" y="124" w1="4" w2="7" w3="5" h1="2" h2="1" h3="2" />
@ -425,10 +425,10 @@
<part id="folder_icon_small" x="144" y="272" w="10" h="8" /> <part id="folder_icon_small" x="144" y="272" w="10" h="8" />
<part id="folder_icon_big" x="176" y="272" w="32" h="32" /> <part id="folder_icon_big" x="176" y="272" w="32" h="32" />
<part id="folder_icon_medium" x="160" y="272" w="16" h="16" /> <part id="folder_icon_medium" x="160" y="272" w="16" h="16" />
<part id="outline_circle" x="144" y="224" w="13" h="15" /> <part id="outline_circle" x="144" y="226" w="13" h="13" />
<part id="outline_square" x="160" y="224" w="13" h="15" /> <part id="outline_square" x="160" y="226" w="13" h="13" />
<part id="outline_horizontal" x="176" y="224" w="13" h="15" /> <part id="outline_horizontal" x="176" y="226" w="13" h="13" />
<part id="outline_vertical" x="192" y="224" w="13" h="15" /> <part id="outline_vertical" x="192" y="226" w="13" h="13" />
<part id="outline_empty_pixel" x="208" y="224" w="5" h="5" /> <part id="outline_empty_pixel" x="208" y="224" w="5" h="5" />
<part id="outline_full_pixel" x="214" y="224" w="5" h="5" /> <part id="outline_full_pixel" x="214" y="224" w="5" h="5" />
<part id="dynamics" x="176" y="144" w="16" h="16" /> <part id="dynamics" x="176" y="144" w="16" h="16" />
@ -615,7 +615,7 @@
<icon part="radio_selected" align="left middle" x="2" state="selected" /> <icon part="radio_selected" align="left middle" x="2" state="selected" />
<icon part="radio_disabled" align="left middle" x="2" state="disabled" /> <icon part="radio_disabled" align="left middle" x="2" state="disabled" />
</style> </style>
<style id="mini_button"> <style id="mini_button" padding-top="1" border="3" border-bottom="5">
<background-border part="buttonset_item_normal" /> <background-border part="buttonset_item_normal" />
<background-border part="buttonset_item_hot" state="mouse" /> <background-border part="buttonset_item_hot" state="mouse" />
<background-border part="buttonset_item_hot" state="focus" /> <background-border part="buttonset_item_hot" state="focus" />
@ -625,7 +625,7 @@
<text color="button_selected_text" state="selected" /> <text color="button_selected_text" state="selected" />
</style> </style>
<style id="mini_check_box" extends="check_box" font="mini" /> <style id="mini_check_box" extends="check_box" font="mini" />
<style id="combobox_button" extends="mini_button"> <style id="combobox_button" extends="mini_button" padding="0">
<icon part="combobox_arrow_down" /> <icon part="combobox_arrow_down" />
<icon part="combobox_arrow_down_selected" state="selected" /> <icon part="combobox_arrow_down_selected" state="selected" />
<icon part="combobox_arrow_down_disabled" state="disabled" /> <icon part="combobox_arrow_down_disabled" state="disabled" />
@ -645,17 +645,17 @@
<icon part="combobox_arrow_down_selected" state="selected" /> <icon part="combobox_arrow_down_selected" state="selected" />
<icon part="combobox_arrow_down_disabled" state="disabled" /> <icon part="combobox_arrow_down_disabled" state="disabled" />
</style> </style>
<style id="go_back_button" extends="mini_button"> <style id="go_back_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_left" /> <icon part="combobox_arrow_left" />
<icon part="combobox_arrow_left_selected" state="selected" /> <icon part="combobox_arrow_left_selected" state="selected" />
<icon part="combobox_arrow_left_disabled" state="disabled" /> <icon part="combobox_arrow_left_disabled" state="disabled" />
</style> </style>
<style id="go_forward_button" extends="mini_button"> <style id="go_forward_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_right" /> <icon part="combobox_arrow_right" />
<icon part="combobox_arrow_right_selected" state="selected" /> <icon part="combobox_arrow_right_selected" state="selected" />
<icon part="combobox_arrow_right_disabled" state="disabled" /> <icon part="combobox_arrow_right_disabled" state="disabled" />
</style> </style>
<style id="go_up_button" extends="mini_button"> <style id="go_up_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_up" /> <icon part="combobox_arrow_up" />
<icon part="combobox_arrow_up_selected" state="selected" /> <icon part="combobox_arrow_up_selected" state="selected" />
<icon part="combobox_arrow_up_disabled" state="disabled" /> <icon part="combobox_arrow_up_disabled" state="disabled" />
@ -664,7 +664,7 @@
<icon part="arrow_circle_cw" /> <icon part="arrow_circle_cw" />
<icon part="arrow_circle_cw_selected" state="selected" /> <icon part="arrow_circle_cw_selected" state="selected" />
</style> </style>
<style id="new_folder_button" extends="mini_button"> <style id="new_folder_button" extends="mini_button" padding-top="2">
<icon part="newfolder" /> <icon part="newfolder" />
<icon part="newfolder_selected" state="selected" /> <icon part="newfolder_selected" state="selected" />
</style> </style>
@ -1018,10 +1018,109 @@
<text color="slider_empty_text" align="center middle" /> <text color="slider_empty_text" align="center middle" />
<text color="slider_empty_text" align="center middle" state="focus" y="1" /> <text color="slider_empty_text" align="center middle" state="focus" y="1" />
</style> </style>
<style id="mini_slider" extends="slider" font="mini" padding-top="1" padding-bottom="3"> <style id="mini_slider" extends="slider" font="mini">
<background part="mini_slider_empty" /> <background part="mini_slider_empty" />
<text color="slider_empty_text" align="center middle" /> <text color="slider_empty_text" align="center middle" />
<text color="slider_empty_text" align="center middle" state="focus" /> <text color="slider_empty_text" align="center middle" state="focus" />
</style> </style>
<style id="buttonset" gap-rows="-3" gap-columns="-1" />
<style id="buttonset_item" font="mini" border="3" border-bottom="5">
<background-border part="buttonset_item_normal" />
<background-border part="buttonset_item_hot" state="selected" />
<background-border part="buttonset_item_hot" state="mouse" />
<background-border part="buttonset_item_hot_focused" state="selected focus" />
<background-border part="buttonset_item_hot_focused" state="mouse focus" />
<background-border part="buttonset_item_pushed" state="capture selected" />
<background-border part="buttonset_item_pushed" state="mouse capture" />
<background-border part="buttonset_item_focused" state="focus" />
</style>
<style id="buttonset_item_icon" extends="buttonset_item">
<icon />
<icon state="disabled" color="disabled" />
<icon state="capture selected" color="button_selected_text" />
</style>
<style id="buttonset_item_icon_mono" extends="buttonset_item_icon">
<icon color="button_normal_text" />
</style>
<style id="buttonset_item_text" extends="buttonset_item" padding="1">
<text color="button_normal_text" />
<text color="button_hot_text" state="selected" />
<text color="button_hot_text" state="mouse" />
<text color="button_selected_text" state="mouse capture" />
<text color="button_selected_text" state="capture selected" />
<text color="background" x="1" y="1" state="disabled" />
<newlayer />
<text color="disabled" state="disabled" align="top" />
</style>
<style id="buttonset_item_text_top" extends="buttonset_item">
<text color="button_normal_text" align="top" />
<text color="button_hot_text" state="selected" align="top" />
<text color="button_hot_text" state="mouse" align="top" />
<text color="button_selected_text" state="mouse capture" align="top" />
<text color="button_selected_text" state="capture selected" align="top" />
<text color="background" x="1" y="1" state="disabled" align="top" />
<newlayer />
<text color="disabled" state="disabled" align="top" />
</style>
<style id="buttonset_item_text_top_icon_bottom" extends="buttonset_item_text_top" padding-top="2" padding-bottom="1">
<icon align="bottom" />
<icon align="bottom" state="disabled" color="disabled" />
<icon align="bottom" state="capture selected" color="button_selected_text" />
</style>
<style id="new_sprite_rgb" extends="buttonset_item_text_top_icon_bottom" />
<style id="new_sprite_grayscale" extends="buttonset_item_text_top_icon_bottom" />
<style id="new_sprite_indexed" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_transparent" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_white" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_black" extends="buttonset_item_text_top_icon_bottom" />
<style id="dir_item" extends="buttonset_item_icon" width="18" height="20" />
<style id="context_bar_button" extends="buttonset_item_icon" width="15" />
<style id="context_bar_text_button" extends="buttonset_item_text" width="15" />
<style id="brush_type" extends="context_bar_button" />
<style id="brush_type_mono" extends="context_bar_button">
<icon color="button_normal_text" />
</style>
<style id="ink_type" extends="context_bar_button" padding-left="1" />
<style id="dynamics_field" extends="context_bar_button" padding-left="1" />
<style id="pivot_field" extends="context_bar_button" padding-top="1" />
<style id="pivot_dir" extends="buttonset_item_icon" width="17" height="19" />
<style id="selection_mode" extends="context_bar_button" padding-top="1" />
<style id="symmetry_field" extends="context_bar_button" padding-top="1" />
<style id="symmetry_options" extends="context_bar_text_button" padding-left="3" padding-bottom="3" />
<style id="pal_edit_lock" extends="buttonset_item_icon" width="15">
<icon part="timeline_closed_padlock_normal" />
<icon part="timeline_closed_padlock_normal" state="capture selected" />
</style>
<style id="pal_edit_unlock" extends="pal_edit_lock">
<background-border part="buttonset_item_active" />
<background-border part="buttonset_item_active" state="selected" />
<background-border part="buttonset_item_active" state="focus" />
<background-border part="buttonset_item_active" state="mouse" />
<background-border part="buttonset_item_active" state="mouse focus" />
<background-border part="buttonset_item_active" state="capture" />
<background-border part="buttonset_item_active" state="capture selected" />
<newlayer />
<icon part="timeline_open_padlock_active" />
</style>
<style id="pal_button" extends="buttonset_item_icon" minwidth="15" padding-top="1" />
<style id="debugger_button" extends="buttonset_item_icon" width="17" height="19" />
<style id="edit_pixels_mode" extends="buttonset_item_icon" width="15">
<icon color="button_normal_text" />
</style>
<style id="edit_tiles_mode" extends="edit_pixels_mode" width="15">
<background-border part="buttonset_item_active" />
<background-border part="buttonset_item_active" state="selected" />
<background-border part="buttonset_item_active" state="focus" />
<background-border part="buttonset_item_active" state="mouse" />
<background-border part="buttonset_item_active" state="mouse focus" />
<background-border part="buttonset_item_active" state="capture" />
<background-border part="buttonset_item_active" state="capture selected" />
<newlayer />
<icon color="button_selected_text" />
</style>
<style id="standard_brush" extends="buttonset_item_icon_mono" width="17" height="19" />
<style id="outline_cell" extends="buttonset_item_icon" width="17" height="19" />
<style id="ani_button" extends="buttonset_item_icon" width="17" />
<style id="multi_window_item" extends="buttonset_item_icon" width="17" height="17" />
</styles> </styles>
</theme> </theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -6,7 +6,7 @@
</authors> </authors>
<fonts> <fonts>
<font id="default" font="Aseprite" /> <font id="default" font="Aseprite" />
<font id="mini" font="Aseprite Mini" /> <font id="mini" font="Aseprite Mini" mnemonics="off" />
</fonts> </fonts>
<dimensions> <dimensions>
<dim id="scrollbar_size" value="12" /> <dim id="scrollbar_size" value="12" />
@ -27,7 +27,7 @@
<dim id="timeline_base_size" value="12" /> <dim id="timeline_base_size" value="12" />
<dim id="color_bar_buttons_height" value="16" /> <dim id="color_bar_buttons_height" value="16" />
<dim id="context_bar_height" value="18" /> <dim id="context_bar_height" value="18" />
<dim id="brush_type_width" value="16" /> <dim id="brush_type_width" value="15" />
<dim id="color_selector_bar_size" value="8" /> <dim id="color_selector_bar_size" value="8" />
</dimensions> </dimensions>
<colors> <colors>
@ -109,7 +109,6 @@
<color id="flag_clicked" value="#7d929e" /> <color id="flag_clicked" value="#7d929e" />
<color id="select_box_ruler" value="#0000ff" /> <color id="select_box_ruler" value="#0000ff" />
<color id="select_box_grid" value="#64c864" /> <color id="select_box_grid" value="#64c864" />
<color id="edit_pal_face" value="#655561" />
<color id="palette_entries_separator" value="#000000" /> <color id="palette_entries_separator" value="#000000" />
</colors> </colors>
<parts> <parts>
@ -180,18 +179,18 @@
<part id="mini_slider_thumb_focused" x="48" y="176" w="5" h="4" /> <part id="mini_slider_thumb_focused" x="48" y="176" w="5" h="4" />
<part id="separator_horz" x="32" y="80" w="9" h="5" /> <part id="separator_horz" x="32" y="80" w="9" h="5" />
<part id="separator_vert" x="32" y="96" w="5" h="9" /> <part id="separator_vert" x="32" y="96" w="5" h="9" />
<part id="combobox_arrow_down" x="100" y="148" w="9" h="9" /> <part id="combobox_arrow_down" x="100" y="148" w="9" h="8" />
<part id="combobox_arrow_down_selected" x="116" y="148" w="9" h="9" /> <part id="combobox_arrow_down_selected" x="116" y="148" w="9" h="8" />
<part id="combobox_arrow_down_disabled" x="132" y="148" w="9" h="9" /> <part id="combobox_arrow_down_disabled" x="132" y="148" w="9" h="8" />
<part id="combobox_arrow_up" x="100" y="163" w="9" h="9" /> <part id="combobox_arrow_up" x="100" y="163" w="9" h="8" />
<part id="combobox_arrow_up_selected" x="116" y="163" w="9" h="9" /> <part id="combobox_arrow_up_selected" x="116" y="163" w="9" h="8" />
<part id="combobox_arrow_up_disabled" x="132" y="163" w="9" h="9" /> <part id="combobox_arrow_up_disabled" x="132" y="163" w="9" h="8" />
<part id="combobox_arrow_left" x="99" y="180" w="9" h="9" /> <part id="combobox_arrow_left" x="99" y="180" w="9" h="8" />
<part id="combobox_arrow_left_selected" x="115" y="180" w="9" h="9" /> <part id="combobox_arrow_left_selected" x="115" y="180" w="9" h="8" />
<part id="combobox_arrow_left_disabled" x="131" y="180" w="9" h="9" /> <part id="combobox_arrow_left_disabled" x="131" y="180" w="9" h="8" />
<part id="combobox_arrow_right" x="99" y="196" w="9" h="9" /> <part id="combobox_arrow_right" x="99" y="196" w="9" h="8" />
<part id="combobox_arrow_right_selected" x="115" y="196" w="9" h="9" /> <part id="combobox_arrow_right_selected" x="115" y="196" w="9" h="8" />
<part id="combobox_arrow_right_disabled" x="131" y="196" w="9" h="9" /> <part id="combobox_arrow_right_disabled" x="131" y="196" w="9" h="8" />
<part id="arrow_circle_cw" x="99" y="243" w="10" h="10" /> <part id="arrow_circle_cw" x="99" y="243" w="10" h="10" />
<part id="arrow_circle_cw_selected" x="115" y="243" w="10" h="10" /> <part id="arrow_circle_cw_selected" x="115" y="243" w="10" h="10" />
<part id="newfolder" x="99" y="211" w="9" h="9" /> <part id="newfolder" x="99" y="211" w="9" h="9" />
@ -203,11 +202,12 @@
<part id="toolbutton_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="toolbutton_last" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_last" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="toolbutton_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="toolbutton_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" />
<part id="buttonset_item_normal" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_normal" x="96" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_hot" x="112" y="0" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_hot_focused" x="128" y="0" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_hot_focused" x="128" y="0" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_focused" x="128" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_focused" x="128" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="9" h3="4" /> <part id="buttonset_item_pushed" x="112" y="16" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="buttonset_item_active" x="112" y="32" w1="3" w2="10" w3="3" h1="3" h2="8" h3="5" />
<part id="tab_normal" x="2" y="112" w1="4" w2="5" w3="5" h1="4" h2="6" h3="2" /> <part id="tab_normal" x="2" y="112" w1="4" w2="5" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_active" x="16" y="112" w1="4" w2="7" w3="5" h1="4" h2="6" h3="2" /> <part id="tab_active" x="16" y="112" w1="4" w2="7" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_bottom_active" x="16" y="124" w1="4" w2="7" w3="5" h1="2" h2="1" h3="2" /> <part id="tab_bottom_active" x="16" y="124" w1="4" w2="7" w3="5" h1="2" h2="1" h3="2" />
@ -421,10 +421,10 @@
<part id="folder_icon_small" x="144" y="272" w="10" h="8" /> <part id="folder_icon_small" x="144" y="272" w="10" h="8" />
<part id="folder_icon_big" x="176" y="272" w="32" h="32" /> <part id="folder_icon_big" x="176" y="272" w="32" h="32" />
<part id="folder_icon_medium" x="160" y="272" w="16" h="16" /> <part id="folder_icon_medium" x="160" y="272" w="16" h="16" />
<part id="outline_circle" x="144" y="224" w="13" h="15" /> <part id="outline_circle" x="144" y="226" w="13" h="13" />
<part id="outline_square" x="160" y="224" w="13" h="15" /> <part id="outline_square" x="160" y="226" w="13" h="13" />
<part id="outline_horizontal" x="176" y="224" w="13" h="15" /> <part id="outline_horizontal" x="176" y="226" w="13" h="13" />
<part id="outline_vertical" x="192" y="224" w="13" h="15" /> <part id="outline_vertical" x="192" y="226" w="13" h="13" />
<part id="outline_empty_pixel" x="208" y="224" w="5" h="5" /> <part id="outline_empty_pixel" x="208" y="224" w="5" h="5" />
<part id="outline_full_pixel" x="214" y="224" w="5" h="5" /> <part id="outline_full_pixel" x="214" y="224" w="5" h="5" />
<part id="dynamics" x="176" y="144" w="16" h="16" /> <part id="dynamics" x="176" y="144" w="16" h="16" />
@ -608,7 +608,7 @@
<icon part="radio_selected" align="left middle" x="2" state="selected" /> <icon part="radio_selected" align="left middle" x="2" state="selected" />
<icon part="radio_disabled" align="left middle" x="2" state="disabled" /> <icon part="radio_disabled" align="left middle" x="2" state="disabled" />
</style> </style>
<style id="mini_button"> <style id="mini_button" padding-top="1" border="3" border-bottom="5">
<background-border part="buttonset_item_normal" /> <background-border part="buttonset_item_normal" />
<background-border part="buttonset_item_hot" state="mouse" /> <background-border part="buttonset_item_hot" state="mouse" />
<background-border part="buttonset_item_hot" state="focus" /> <background-border part="buttonset_item_hot" state="focus" />
@ -618,7 +618,7 @@
<text color="button_selected_text" state="selected" /> <text color="button_selected_text" state="selected" />
</style> </style>
<style id="mini_check_box" extends="check_box" font="mini" /> <style id="mini_check_box" extends="check_box" font="mini" />
<style id="combobox_button" extends="mini_button"> <style id="combobox_button" extends="mini_button" padding="0">
<icon part="combobox_arrow_down" /> <icon part="combobox_arrow_down" />
<icon part="combobox_arrow_down_selected" state="selected" /> <icon part="combobox_arrow_down_selected" state="selected" />
<icon part="combobox_arrow_down_disabled" state="disabled" /> <icon part="combobox_arrow_down_disabled" state="disabled" />
@ -638,17 +638,17 @@
<icon part="combobox_arrow_down_selected" state="selected" /> <icon part="combobox_arrow_down_selected" state="selected" />
<icon part="combobox_arrow_down_disabled" state="disabled" /> <icon part="combobox_arrow_down_disabled" state="disabled" />
</style> </style>
<style id="go_back_button" extends="mini_button"> <style id="go_back_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_left" /> <icon part="combobox_arrow_left" />
<icon part="combobox_arrow_left_selected" state="selected" /> <icon part="combobox_arrow_left_selected" state="selected" />
<icon part="combobox_arrow_left_disabled" state="disabled" /> <icon part="combobox_arrow_left_disabled" state="disabled" />
</style> </style>
<style id="go_forward_button" extends="mini_button"> <style id="go_forward_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_right" /> <icon part="combobox_arrow_right" />
<icon part="combobox_arrow_right_selected" state="selected" /> <icon part="combobox_arrow_right_selected" state="selected" />
<icon part="combobox_arrow_right_disabled" state="disabled" /> <icon part="combobox_arrow_right_disabled" state="disabled" />
</style> </style>
<style id="go_up_button" extends="mini_button"> <style id="go_up_button" extends="mini_button" padding-top="2">
<icon part="combobox_arrow_up" /> <icon part="combobox_arrow_up" />
<icon part="combobox_arrow_up_selected" state="selected" /> <icon part="combobox_arrow_up_selected" state="selected" />
<icon part="combobox_arrow_up_disabled" state="disabled" /> <icon part="combobox_arrow_up_disabled" state="disabled" />
@ -657,7 +657,7 @@
<icon part="arrow_circle_cw" /> <icon part="arrow_circle_cw" />
<icon part="arrow_circle_cw_selected" state="selected" /> <icon part="arrow_circle_cw_selected" state="selected" />
</style> </style>
<style id="new_folder_button" extends="mini_button"> <style id="new_folder_button" extends="mini_button" padding-top="2">
<icon part="newfolder" /> <icon part="newfolder" />
<icon part="newfolder_selected" state="selected" /> <icon part="newfolder_selected" state="selected" />
</style> </style>
@ -1008,10 +1008,109 @@
<text color="slider_empty_text" align="center middle" /> <text color="slider_empty_text" align="center middle" />
<text color="slider_empty_text" align="center middle" state="focus" y="1" /> <text color="slider_empty_text" align="center middle" state="focus" y="1" />
</style> </style>
<style id="mini_slider" extends="slider" font="mini" padding-top="1" padding-bottom="3"> <style id="mini_slider" extends="slider" font="mini">
<background part="mini_slider_empty" /> <background part="mini_slider_empty" />
<text color="slider_empty_text" align="center middle" /> <text color="slider_empty_text" align="center middle" />
<text color="slider_empty_text" align="center middle" state="focus" /> <text color="slider_empty_text" align="center middle" state="focus" />
</style> </style>
<style id="buttonset" gap-rows="-3" gap-columns="-1" />
<style id="buttonset_item" font="mini" border="3" border-bottom="5">
<background-border part="buttonset_item_normal" />
<background-border part="buttonset_item_hot" state="selected" />
<background-border part="buttonset_item_hot" state="mouse" />
<background-border part="buttonset_item_hot_focused" state="selected focus" />
<background-border part="buttonset_item_hot_focused" state="mouse focus" />
<background-border part="buttonset_item_pushed" state="capture selected" />
<background-border part="buttonset_item_pushed" state="mouse capture" />
<background-border part="buttonset_item_focused" state="focus" />
</style>
<style id="buttonset_item_icon" extends="buttonset_item">
<icon />
<icon state="disabled" color="disabled" />
<icon state="capture selected" color="button_selected_text" />
</style>
<style id="buttonset_item_icon_mono" extends="buttonset_item_icon">
<icon color="button_normal_text" />
</style>
<style id="buttonset_item_text" extends="buttonset_item" padding="1">
<text color="button_normal_text" />
<text color="button_hot_text" state="selected" />
<text color="button_hot_text" state="mouse" />
<text color="button_selected_text" state="mouse capture" />
<text color="button_selected_text" state="capture selected" />
<text color="background" x="1" y="1" state="disabled" />
<newlayer />
<text color="disabled" state="disabled" align="top" />
</style>
<style id="buttonset_item_text_top" extends="buttonset_item">
<text color="button_normal_text" align="top" />
<text color="button_hot_text" state="selected" align="top" />
<text color="button_hot_text" state="mouse" align="top" />
<text color="button_selected_text" state="mouse capture" align="top" />
<text color="button_selected_text" state="capture selected" align="top" />
<text color="background" x="1" y="1" state="disabled" align="top" />
<newlayer />
<text color="disabled" state="disabled" align="top" />
</style>
<style id="buttonset_item_text_top_icon_bottom" extends="buttonset_item_text_top" padding-top="2" padding-bottom="1">
<icon align="bottom" />
<icon align="bottom" state="disabled" color="disabled" />
<icon align="bottom" state="capture selected" color="button_selected_text" />
</style>
<style id="new_sprite_rgb" extends="buttonset_item_text_top_icon_bottom" />
<style id="new_sprite_grayscale" extends="buttonset_item_text_top_icon_bottom" />
<style id="new_sprite_indexed" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_transparent" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_white" extends="buttonset_item_text_top_icon_bottom" />
<style id="bg_black" extends="buttonset_item_text_top_icon_bottom" />
<style id="dir_item" extends="buttonset_item_icon" width="18" height="20" />
<style id="context_bar_button" extends="buttonset_item_icon" width="15" />
<style id="context_bar_text_button" extends="buttonset_item_text" width="15" />
<style id="brush_type" extends="context_bar_button" />
<style id="brush_type_mono" extends="context_bar_button">
<icon color="button_normal_text" />
</style>
<style id="ink_type" extends="context_bar_button" padding-left="1" />
<style id="dynamics_field" extends="context_bar_button" padding-left="1" />
<style id="pivot_field" extends="context_bar_button" padding-top="1" />
<style id="pivot_dir" extends="buttonset_item_icon" width="17" height="19" />
<style id="selection_mode" extends="context_bar_button" padding-top="1" />
<style id="symmetry_field" extends="context_bar_button" padding-top="1" />
<style id="symmetry_options" extends="context_bar_text_button" padding-left="3" padding-bottom="3" />
<style id="pal_edit_lock" extends="buttonset_item_icon" width="15">
<icon part="timeline_closed_padlock_normal" />
<icon part="timeline_closed_padlock_normal" state="capture selected" />
</style>
<style id="pal_edit_unlock" extends="pal_edit_lock">
<background-border part="buttonset_item_active" />
<background-border part="buttonset_item_active" state="selected" />
<background-border part="buttonset_item_active" state="focus" />
<background-border part="buttonset_item_active" state="mouse" />
<background-border part="buttonset_item_active" state="mouse focus" />
<background-border part="buttonset_item_active" state="capture" />
<background-border part="buttonset_item_active" state="capture selected" />
<newlayer />
<icon part="timeline_open_padlock_active" />
</style>
<style id="pal_button" extends="buttonset_item_icon" minwidth="15" padding-top="1" />
<style id="debugger_button" extends="buttonset_item_icon" width="17" height="19" />
<style id="edit_pixels_mode" extends="buttonset_item_icon" width="15">
<icon color="button_normal_text" />
</style>
<style id="edit_tiles_mode" extends="edit_pixels_mode" width="15">
<background-border part="buttonset_item_active" />
<background-border part="buttonset_item_active" state="selected" />
<background-border part="buttonset_item_active" state="focus" />
<background-border part="buttonset_item_active" state="mouse" />
<background-border part="buttonset_item_active" state="mouse focus" />
<background-border part="buttonset_item_active" state="capture" />
<background-border part="buttonset_item_active" state="capture selected" />
<newlayer />
<icon color="button_selected_text" />
</style>
<style id="standard_brush" extends="buttonset_item_icon_mono" width="17" height="19" />
<style id="outline_cell" extends="buttonset_item_icon" width="17" height="19" />
<style id="ani_button" extends="buttonset_item_icon" width="17" />
<style id="multi_window_item" extends="buttonset_item_icon" width="17" height="17" />
</styles> </styles>
</theme> </theme>

View File

@ -14,15 +14,15 @@
<hbox filler="true" cell_hspan="2" /> <hbox filler="true" cell_hspan="2" />
</grid> </grid>
<buttonset columns="3" id="dir"> <buttonset columns="3" id="dir">
<item icon="canvas_nw" /> <item icon="canvas_nw" style="dir_item" />
<item icon="canvas_n" /> <item icon="canvas_n" style="dir_item" />
<item icon="canvas_ne" /> <item icon="canvas_ne" style="dir_item" />
<item icon="canvas_w" /> <item icon="canvas_w" style="dir_item" />
<item icon="canvas_c" /> <item icon="canvas_c" style="dir_item" />
<item icon="canvas_e" /> <item icon="canvas_e" style="dir_item" />
<item icon="canvas_sw" /> <item icon="canvas_sw" style="dir_item" />
<item icon="canvas_s" /> <item icon="canvas_s" style="dir_item" />
<item icon="canvas_se" /> <item icon="canvas_se" style="dir_item" />
</buttonset> </buttonset>
</hbox> </hbox>

View File

@ -5,10 +5,10 @@
<vbox childspacing="0"> <vbox childspacing="0">
<hbox> <hbox>
<buttonset columns="4" id="control"> <buttonset columns="4" id="control">
<item icon="debug_continue" tooltip="@.continue" tooltip_dir="bottom" /> <item icon="debug_continue" style="debugger_button" tooltip="@.continue" tooltip_dir="bottom" />
<item icon="debug_step_into" tooltip="@.step_into" tooltip_dir="bottom" /> <item icon="debug_step_into" style="debugger_button" tooltip="@.step_into" tooltip_dir="bottom" />
<item icon="debug_step_over" tooltip="@.step_over" tooltip_dir="bottom" /> <item icon="debug_step_over" style="debugger_button" tooltip="@.step_over" tooltip_dir="bottom" />
<item icon="debug_step_out" tooltip="@.step_out" tooltip_dir="bottom" /> <item icon="debug_step_out" style="debugger_button" tooltip="@.step_out" tooltip_dir="bottom" />
</buttonset> </buttonset>
<buttonset columns="1" id="breakpoint"> <buttonset columns="1" id="breakpoint">
<item icon="debug_breakpoint" tooltip="@.toggle_breakpoint" tooltip_dir="bottom" /> <item icon="debug_breakpoint" tooltip="@.toggle_breakpoint" tooltip_dir="bottom" />

View File

@ -16,16 +16,16 @@
<item text="@.velocity" tooltip="@.velocity_tooltip" tooltip_dir="bottom" /> <item text="@.velocity" tooltip="@.velocity_tooltip" tooltip_dir="bottom" />
<item text="@.size" tooltip="@.size_tooltip" tooltip_dir="right" /> <item text="@.size" tooltip="@.size_tooltip" tooltip_dir="right" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
<item text="@.angle" tooltip="@.angle_tooltip" tooltip_dir="right" /> <item text="@.angle" tooltip="@.angle_tooltip" tooltip_dir="right" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
<item text="@.gradient" tooltip="@.gradient_tooltip" tooltip_dir="right" /> <item text="@.gradient" tooltip="@.gradient_tooltip" tooltip_dir="right" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" /> <item minheight="1" maxheight="1" />
</buttonset> </buttonset>
</hbox> </hbox>

View File

@ -67,28 +67,36 @@
</vbox> </vbox>
<buttonset columns="3" id="drag_angle"> <buttonset columns="3" id="drag_angle">
<item icon="canvas_nw" <item icon="canvas_nw"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_n" <item icon="canvas_n"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_ne" <item icon="canvas_ne"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_w" <item icon="canvas_w"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="right" /> tooltip_dir="right" />
<item /> <item />
<item icon="canvas_e" <item icon="canvas_e"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="left" /> tooltip_dir="left" />
<item icon="canvas_sw" <item icon="canvas_sw"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
<item icon="canvas_s" <item icon="canvas_s"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
<item icon="canvas_se" <item icon="canvas_se"
style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
</buttonset> </buttonset>

View File

@ -15,16 +15,16 @@
<separator text="@.color_mode" left="true" horizontal="true" /> <separator text="@.color_mode" left="true" horizontal="true" />
<buttonset columns="3" id="color_mode"> <buttonset columns="3" id="color_mode">
<item text="@.rgba" icon="icon_rgb" tooltip="@.rgba_tooltip" tooltip_dir="bottom" /> <item text="@.rgba" icon="icon_rgb" style="new_sprite_rgb" tooltip="@.rgba_tooltip" tooltip_dir="bottom" />
<item text="@.grayscale" icon="icon_grayscale" tooltip="@.grayscale_tooltip" tooltip_dir="bottom" /> <item text="@.grayscale" icon="icon_grayscale" style="new_sprite_grayscale" tooltip="@.grayscale_tooltip" tooltip_dir="bottom" />
<item text="@.indexed" icon="icon_indexed" tooltip="@.indexed_tooltip" tooltip_dir="bottom" /> <item text="@.indexed" icon="icon_indexed" style="new_sprite_indexed" tooltip="@.indexed_tooltip" tooltip_dir="bottom" />
</buttonset> </buttonset>
<separator text="@.background" left="true" horizontal="true" /> <separator text="@.background" left="true" horizontal="true" />
<buttonset columns="3" id="bg_color"> <buttonset columns="3" id="bg_color">
<item text="@.transparent" icon="icon_transparent" /> <item text="@.transparent" icon="icon_transparent" style="bg_transparent" />
<item text="@.white" icon="icon_white" /> <item text="@.white" icon="icon_white" style="bg_white" />
<item text="@.black" icon="icon_black" /> <item text="@.black" icon="icon_black" style="bg_black" />
</buttonset> </buttonset>
<check id="advanced_check" text="@general.advanced_options" /> <check id="advanced_check" text="@general.advanced_options" />

View File

@ -35,8 +35,8 @@
<label text="@.ui_windows" /> <label text="@.ui_windows" />
<hbox> <hbox>
<buttonset columns="2" id="ui_windows"> <buttonset columns="2" id="ui_windows">
<item icon="one_win_icon" tooltip="@.one_win" tooltip_dir="bottom" /> <item icon="one_win_icon" tooltip="@.one_win" tooltip_dir="bottom" style="multi_window_item" />
<item icon="multi_win_icon" tooltip="@.multi_win" tooltip_dir="bottom" /> <item icon="multi_win_icon" tooltip="@.multi_win" tooltip_dir="bottom" style="multi_window_item" />
</buttonset> </buttonset>
<hbox id="theme_variants"> <hbox id="theme_variants">
<label text="@.theme_mode" /> <label text="@.theme_mode" />

View File

@ -20,15 +20,15 @@
</hbox> </hbox>
<hbox> <hbox>
<buttonset id="outline_matrix" columns="3"> <buttonset id="outline_matrix" columns="3">
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" /> <item icon="outline_empty_pixel" style="outline_cell" />
</buttonset> </buttonset>
</hbox> </hbox>
</vbox> </vbox>

View File

@ -15,7 +15,6 @@
#include "app/doc_api.h" #include "app/doc_api.h"
#include "app/modules/gui.h" #include "app/modules/gui.h"
#include "app/tx.h" #include "app/tx.h"
#include "app/ui/button_set.h"
#include "app/ui/color_bar.h" #include "app/ui/color_bar.h"
#include "app/ui/doc_view.h" #include "app/ui/doc_view.h"
#include "app/ui/editor/editor.h" #include "app/ui/editor/editor.h"

View File

@ -20,7 +20,6 @@
#include "app/i18n/strings.h" #include "app/i18n/strings.h"
#include "app/modules/palettes.h" #include "app/modules/palettes.h"
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/ui/button_set.h"
#include "app/ui/workspace.h" #include "app/ui/workspace.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/util/clipboard.h" #include "app/util/clipboard.h"

View File

@ -954,6 +954,7 @@ private:
} }
m_themeVars = list; m_themeVars = list;
themeVariants()->setVisible(list ? true: false); themeVariants()->setVisible(list ? true: false);
themeVariants()->initTheme();
} }
void fillExtensionsCombobox(ui::ComboBox* combobox, void fillExtensionsCombobox(ui::ComboBox* combobox,

View File

@ -80,6 +80,7 @@ public:
m_sliders.setMode(ColorSliders::Mode::Relative); m_sliders.setMode(ColorSliders::Mode::Relative);
m_sliders.ColorChange.connect([this]{ onChangeControls(); }); m_sliders.ColorChange.connect([this]{ onChangeControls(); });
initTheme();
onChangeMode(); onChangeMode();
} }

View File

@ -68,6 +68,7 @@ FilterTargetButtons::FilterTargetButtons(int imgtype, bool withChannels)
// Create the button to select which cels will be modified by the // Create the button to select which cels will be modified by the
// filter. // filter.
m_cels = addItem(getCelsTargetText(), 4, 1); m_cels = addItem(getCelsTargetText(), 4, 1);
initTheme();
} }
void FilterTargetButtons::setTarget(const int target) void FilterTargetButtons::setTarget(const int target)

View File

@ -154,7 +154,7 @@ public:
, m_brushes(App::instance()->brushes()) , m_brushes(App::instance()->brushes())
, m_slot(slot) { , m_slot(slot) {
auto theme = skin::SkinTheme::get(this); auto theme = skin::SkinTheme::get(this);
setIcon(theme->parts.iconArrowDown(), true); setIcon(theme->parts.iconArrowDown());
} }
private: private:
@ -283,7 +283,7 @@ class NewBrushOptionsItem : public ButtonSet::Item {
public: public:
NewBrushOptionsItem() { NewBrushOptionsItem() {
auto theme = skin::SkinTheme::get(this); auto theme = skin::SkinTheme::get(this);
setIcon(theme->parts.iconArrowDown(), true); setIcon(theme->parts.iconArrowDown());
} }
private: private:
@ -362,8 +362,7 @@ BrushPopup::BrushPopup()
for (const auto& brush : brushes.getStandardBrushes()) { for (const auto& brush : brushes.getStandardBrushes()) {
m_standardBrushes.addItem( m_standardBrushes.addItem(
new SelectBrushItem( new SelectBrushItem(
BrushSlot(BrushSlot::Flags::BrushType, brush))) BrushSlot(BrushSlot::Flags::BrushType, brush)), "standard_brush");
->setMono(true);
} }
m_standardBrushes.setTransparent(true); m_standardBrushes.setTransparent(true);
@ -428,12 +427,13 @@ void BrushPopup::regenerate(ui::Display* display,
} }
m_customBrushes->addItem(new SelectBrushItem(brush, slot)); m_customBrushes->addItem(new SelectBrushItem(brush, slot));
m_customBrushes->addItem(new BrushShortcutItem(shortcut, slot)); m_customBrushes->addItem(new BrushShortcutItem(shortcut, slot));
m_customBrushes->addItem(new BrushOptionsItem(this, slot)); m_customBrushes->addItem(new BrushOptionsItem(this, slot), "buttonset_item_icon_mono");
} }
m_customBrushes->addItem(new NewCustomBrushItem, 2, 1); m_customBrushes->addItem(new NewCustomBrushItem, 2, 1);
m_customBrushes->addItem(new NewBrushOptionsItem); m_customBrushes->addItem(new NewBrushOptionsItem, "buttonset_item_icon_mono");
m_customBrushes->setExpansive(true); m_customBrushes->setExpansive(true);
m_customBrushes->initTheme();
m_box.addChild(m_customBrushes); m_box.addChild(m_customBrushes);
// Resize the window and change the hot region. // Resize the window and change the hot region.
@ -460,12 +460,14 @@ void BrushPopup::onBrushChanges()
os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush, os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush,
const bool useOriginalImage) const bool useOriginalImage)
{ {
constexpr int kMaxSize = 9;
Image* image = nullptr; Image* image = nullptr;
BrushRef brush = origBrush; BrushRef brush = origBrush;
if (brush) { if (brush) {
if (brush->type() != kImageBrushType && brush->size() > 10) { if (brush->type() != kImageBrushType && brush->size() > kMaxSize) {
brush.reset(new Brush(*brush)); brush.reset(new Brush(*brush));
brush->setSize(10); brush->setSize(kMaxSize);
} }
// Show the original image in the popup (without the image colors // Show the original image in the popup (without the image colors
// modified if there were some modification). // modified if there were some modification).
@ -476,8 +478,8 @@ os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush,
} }
os::SurfaceRef surface = os::instance()->makeRgbaSurface( os::SurfaceRef surface = os::instance()->makeRgbaSurface(
std::min(10, image ? image->width(): 4), std::min(kMaxSize, (image ? image->width(): 4)),
std::min(10, image ? image->height(): 4)); std::min(kMaxSize, (image ? image->height(): 4)));
if (image) { if (image) {
Palette* palette = get_current_palette(); Palette* palette = get_current_palette();
@ -493,6 +495,8 @@ os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush,
if (image->pixelFormat() == IMAGE_BITMAP) if (image->pixelFormat() == IMAGE_BITMAP)
delete palette; delete palette;
surface->applyScale(guiscale());
} }
else { else {
surface->clear(); surface->clear();

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2022 Igara Studio S.A. // Copyright (C) 2018-2023 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -13,6 +13,7 @@
#include "app/modules/gui.h" #include "app/modules/gui.h"
#include "app/ui/skin/skin_theme.h" #include "app/ui/skin/skin_theme.h"
#include "fmt/format.h"
#include "gfx/color.h" #include "gfx/color.h"
#include "os/surface.h" #include "os/surface.h"
#include "ui/box.h" #include "ui/box.h"
@ -48,22 +49,15 @@ WidgetType buttonset_item_type()
ButtonSet::Item::Item() ButtonSet::Item::Item()
: Widget(buttonset_item_type()) : Widget(buttonset_item_type())
, m_icon(NULL) , m_icon(NULL)
, m_hotColor(gfx::ColorNone)
{ {
setup_mini_font(this); setup_mini_font(this);
setAlign(CENTER | MIDDLE); setAlign(CENTER | MIDDLE);
setFocusStop(true); setFocusStop(true);
} }
void ButtonSet::Item::setHotColor(gfx::Color color) void ButtonSet::Item::setIcon(const SkinPartPtr& icon)
{
m_hotColor = color;
}
void ButtonSet::Item::setIcon(const SkinPartPtr& icon, bool mono)
{ {
m_icon = icon; m_icon = icon;
m_mono = mono;
invalidate(); invalidate();
} }
@ -74,97 +68,17 @@ ButtonSet* ButtonSet::Item::buttonSet()
void ButtonSet::Item::onPaint(ui::PaintEvent& ev) void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
{ {
auto theme = SkinTheme::get(this); if (style()) {
Graphics* g = ev.graphics();
gfx::Rect rc = clientBounds(); gfx::Rect rc = clientBounds();
gfx::Color fg;
SkinPartPtr nw;
gfx::Rect boxRc, textRc, iconRc;
gfx::Size iconSize;
if (m_icon)
iconSize = m_icon->size();
getTextIconInfo(
&boxRc, &textRc, &iconRc,
CENTER | (hasText() ? BOTTOM: MIDDLE),
iconSize.w, iconSize.h);
Grid::Info info = buttonSet()->getChildInfo(this); Grid::Info info = buttonSet()->getChildInfo(this);
bool isLastCol = (info.col + info.hspan >= info.grid_cols); bool isLastCol = (info.col + info.hspan >= info.grid_cols);
bool isLastRow = (info.row + info.vspan >= info.grid_rows); bool isLastRow = (info.row + info.vspan >= info.grid_rows);
// When gaps are negative we need to compensate client bounds size so the painting is based on a
// complete button, and not just the part not overlapped.
if (buttonSet()->m_colgap < 0 && !isLastCol) rc.w -= buttonSet()->m_colgap;
if (buttonSet()->m_rowgap < 0 && !isLastRow) rc.h -= buttonSet()->m_rowgap;
if (m_icon || isLastRow) { theme()->paintWidget(ev.graphics(), this, style(), rc);
textRc.y -= 2*guiscale();
iconRc.y -= 1*guiscale();
if (isLastRow && info.row > 0) iconRc.y -= 2*guiscale();
}
if (!gfx::is_transparent(bgColor()))
g->fillRect(bgColor(), g->getClipBounds());
if (isSelected() || hasMouseOver()) {
if (hasCapture()) {
nw = theme->parts.buttonsetItemPushed();
fg = theme->colors.buttonSelectedText();
}
else {
nw = (hasFocus() ? theme->parts.buttonsetItemHotFocused():
theme->parts.buttonsetItemHot());
fg = theme->colors.buttonHotText();
}
}
else {
nw = (hasFocus() ? theme->parts.buttonsetItemFocused():
theme->parts.buttonsetItemNormal());
fg = theme->colors.buttonNormalText();
}
if (!isLastCol)
rc.w += 1*guiscale();
if (!isLastRow) {
if (nw == theme->parts.buttonsetItemHotFocused())
rc.h += 2*guiscale();
else
rc.h += 3*guiscale();
}
theme->drawRect(g, rc, nw.get(),
gfx::is_transparent(m_hotColor));
if (!gfx::is_transparent(m_hotColor)) {
gfx::Rect rc2(rc);
gfx::Rect sprite(nw->spriteBounds());
gfx::Rect slices(nw->slicesBounds());
rc2.shrink(
gfx::Border(
slices.x-1, // TODO this "-1" is an ugly hack for the pal edit
// button, replace all this with styles
slices.y-1,
sprite.w-slices.w-slices.x-1,
sprite.h-slices.h-slices.y));
g->fillRect(m_hotColor, rc2);
}
if (m_icon) {
os::Surface* bmp = m_icon->bitmap(0);
if (!isEnabled())
g->drawColoredRgbaSurface(bmp, theme->colors.disabled(),
iconRc.x, iconRc.y);
else if (isSelected() && hasCapture())
g->drawColoredRgbaSurface(bmp, theme->colors.buttonSelectedText(),
iconRc.x, iconRc.y);
else if (m_mono)
g->drawColoredRgbaSurface(bmp, theme->colors.buttonNormalText(),
iconRc.x, iconRc.y);
else
g->drawRgbaSurface(bmp, iconRc.x, iconRc.y);
}
if (hasText()) {
g->setFont(AddRef(font()));
g->drawUIText(text(), fg, gfx::ColorNone, textRc.origin(), 0);
} }
} }
@ -195,6 +109,7 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
break; break;
case ui::kMouseDownMessage: case ui::kMouseDownMessage:
if (!isEnabled()) return true;
// Only for single-item and trigerred on mouse up ButtonSets: We // Only for single-item and trigerred on mouse up ButtonSets: We
// save the current selected item to restore it just in case the // save the current selected item to restore it just in case the
// user leaves the ButtonSet without releasing the mouse button // user leaves the ButtonSet without releasing the mouse button
@ -259,38 +174,13 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
case ui::kMouseLeaveMessage: case ui::kMouseLeaveMessage:
case ui::kMouseEnterMessage: case ui::kMouseEnterMessage:
if (!isEnabled()) return true;
invalidate(); invalidate();
break; break;
} }
return Widget::onProcessMessage(msg); return Widget::onProcessMessage(msg);
} }
void ButtonSet::Item::onSizeHint(ui::SizeHintEvent& ev)
{
gfx::Size iconSize;
if (m_icon) {
iconSize = m_icon->size();
iconSize.w = std::max(iconSize.w, 16*guiscale());
iconSize.h = std::max(iconSize.h, 16*guiscale());
}
gfx::Rect boxRc;
getTextIconInfo(
&boxRc, NULL, NULL,
CENTER | (hasText() ? BOTTOM: MIDDLE),
iconSize.w, iconSize.h);
gfx::Size sz = boxRc.size();
if (hasText())
sz += 8*guiscale();
Grid::Info info = buttonSet()->getChildInfo(this);
if (info.row == info.grid_rows-1)
sz.h += 3*guiscale();
ev.setSizeHint(sz);
}
void ButtonSet::Item::onClick() void ButtonSet::Item::onClick()
{ {
buttonSet()->onItemChange(this); buttonSet()->onItemChange(this);
@ -310,28 +200,70 @@ ButtonSet::ButtonSet(int columns)
InitTheme.connect( InitTheme.connect(
[this]{ [this]{
noBorderNoChildSpacing(); noBorderNoChildSpacing();
// Set default buttonset style if it wasn't already set.
if (style() == SkinTheme::instance()->styles.grid()) {
setStyle(SkinTheme::instance()->styles.buttonset());
}
}); });
initTheme(); initTheme();
} }
ButtonSet::Item* ButtonSet::addItem(const std::string& text, int hspan, int vspan) ButtonSet::Item* ButtonSet::addItem(const std::string& text, const char* styleId)
{
return addItem(text, 1, 1, styleId);
}
ButtonSet::Item* ButtonSet::addItem(const std::string& text, int hspan, int vspan, const char* styleId)
{ {
Item* item = new Item(); Item* item = new Item();
item->setText(text); item->setText(text);
addItem(item, hspan, vspan); addItem(item, hspan, vspan, styleId);
return item; return item;
} }
ButtonSet::Item* ButtonSet::addItem(const skin::SkinPartPtr& icon, int hspan, int vspan) ButtonSet::Item* ButtonSet::addItem(const skin::SkinPartPtr& icon, const char* styleId)
{
return addItem(icon, 1, 1, styleId);
}
ButtonSet::Item* ButtonSet::addItem(const skin::SkinPartPtr& icon, int hspan, int vspan, const char* styleId)
{ {
Item* item = new Item(); Item* item = new Item();
item->setIcon(icon); item->setIcon(icon);
addItem(item, hspan, vspan); addItem(item, hspan, vspan, styleId);
return item; return item;
} }
ButtonSet::Item* ButtonSet::addItem(Item* item, const char* styleId)
ButtonSet::Item* ButtonSet::addItem(Item* item, int hspan, int vspan)
{ {
return addItem(item, 1, 1, styleId);
}
ButtonSet::Item* ButtonSet::addItem(Item* item, int hspan, int vspan, const char* styleIdStr)
{
std::string styleId;
if (styleIdStr)
styleId = styleIdStr;
item->InitTheme.connect(
[item, styleId] {
auto theme = SkinTheme::get(item);
ui::Style* style;
if (!styleId.empty()) {
style = theme->getStyleById(styleId);
if (!style)
throw base::Exception(fmt::format("Style {} not found", styleId));
}
else {
style = theme->styles.buttonsetItemIcon();
if (!item->text().empty()) {
style = (item->icon() ? theme->styles.buttonsetItemTextTopIconBottom() :
theme->styles.buttonsetItemText());
}
}
item->setStyle(style);
}
);
addChildInCell(item, hspan, vspan, HORIZONTAL | VERTICAL); addChildInCell(item, hspan, vspan, HORIZONTAL | VERTICAL);
return item; return item;
} }

View File

@ -12,6 +12,7 @@
#include "app/ui/skin/skin_part.h" #include "app/ui/skin/skin_part.h"
#include "obs/signal.h" #include "obs/signal.h"
#include "ui/grid.h" #include "ui/grid.h"
#include "ui/style.h"
#include <string> #include <string>
@ -19,24 +20,20 @@ namespace app {
class ButtonSet : public ui::Grid { class ButtonSet : public ui::Grid {
public: public:
class Item : public ui::Widget { class Item : public ui::Widget, public ui::Style::Layer::IconSurfaceProvider {
public: public:
Item(); Item();
void setHotColor(gfx::Color color); void setIcon(const skin::SkinPartPtr& icon);
void setIcon(const skin::SkinPartPtr& icon, bool mono = false); os::Surface* iconSurface() const override { return m_icon ? m_icon->bitmap(0) : nullptr; }
void setMono(const bool mono) { m_mono = mono; }
skin::SkinPartPtr icon() const { return m_icon; } skin::SkinPartPtr icon() const { return m_icon; }
ButtonSet* buttonSet(); ButtonSet* buttonSet();
protected: protected:
void onPaint(ui::PaintEvent& ev) override; void onPaint(ui::PaintEvent& ev) override;
bool onProcessMessage(ui::Message* msg) override; bool onProcessMessage(ui::Message* msg) override;
void onSizeHint(ui::SizeHintEvent& ev) override;
virtual void onClick(); virtual void onClick();
virtual void onRightClick(); virtual void onRightClick();
private: private:
skin::SkinPartPtr m_icon; skin::SkinPartPtr m_icon;
bool m_mono;
gfx::Color m_hotColor;
}; };
enum class MultiMode { enum class MultiMode {
@ -47,9 +44,12 @@ namespace app {
ButtonSet(int columns); ButtonSet(int columns);
Item* addItem(const std::string& text, int hspan = 1, int vspan = 1); Item* addItem(const std::string& text, const char* styleId);
Item* addItem(const skin::SkinPartPtr& icon, int hspan = 1, int vspan = 1); Item* addItem(const std::string& text, int hspan = 1, int vspan = 1, const char* styleId = nullptr);
Item* addItem(Item* item, int hspan = 1, int vspan = 1); Item* addItem(const skin::SkinPartPtr& icon, const char* styleId);
Item* addItem(const skin::SkinPartPtr& icon, int hspan = 1, int vspan = 1, const char* styleId = nullptr);
Item* addItem(Item* item, const char* styleId);
Item* addItem(Item* item, int hspan = 1, int vspan = 1, const char* styleId = nullptr);
Item* getItem(int index); Item* getItem(int index);
int getItemIndex(const Item* item) const; int getItemIndex(const Item* item) const;

View File

@ -186,19 +186,35 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
m_editPal.addItem(theme->parts.timelineOpenPadlockActive()); auto item = m_editPal.addItem("");
m_buttons.addItem(theme->parts.palSort()); item->InitTheme.connect(
m_buttons.addItem(theme->parts.palPresets()); [this, item](){
m_buttons.addItem(theme->parts.palOptions()); auto style =
m_tilesButton.addItem(theme->parts.tiles()); (m_editMode ? SkinTheme::instance()->styles.palEditUnlock() :
SkinTheme::instance()->styles.palEditLock());
item->setStyle(style);
});
m_buttons.addItem(theme->parts.palSort(), "pal_button");
m_buttons.addItem(theme->parts.palPresets(), "pal_button");
m_buttons.addItem(theme->parts.palOptions(), "pal_button");
item = m_tilesButton.addItem(theme->parts.tiles());
item->InitTheme.connect(
[this, item]() {
auto theme = SkinTheme::instance();
const bool editTiles = (canEditTiles() &&
m_tilemapMode == TilemapMode::Tiles);
auto style = (editTiles ? theme->styles.editTilesMode() :
theme->styles.editPixelsMode());
item->setStyle(style);
});
static_assert(0 == int(TilesetMode::Manual) && static_assert(0 == int(TilesetMode::Manual) &&
1 == int(TilesetMode::Auto) && 1 == int(TilesetMode::Auto) &&
2 == int(TilesetMode::Stack), "Tileset mode buttons doesn't match TilesetMode enum values"); 2 == int(TilesetMode::Stack), "Tileset mode buttons doesn't match TilesetMode enum values");
m_tilesetModeButtons.addItem(theme->parts.tilesManual()); m_tilesetModeButtons.addItem(theme->parts.tilesManual(), "pal_button");
m_tilesetModeButtons.addItem(theme->parts.tilesAuto()); m_tilesetModeButtons.addItem(theme->parts.tilesAuto(), "pal_button");
m_tilesetModeButtons.addItem(theme->parts.tilesStack()); m_tilesetModeButtons.addItem(theme->parts.tilesStack(), "pal_button");
setTilesetMode(m_tilesetMode); setTilesetMode(m_tilesetMode);
m_paletteView.setColumns(8); m_paletteView.setColumns(8);
@ -516,13 +532,12 @@ bool ColorBar::inEditMode() const
void ColorBar::setEditMode(bool state) void ColorBar::setEditMode(bool state)
{ {
auto theme = SkinTheme::get(this);
ButtonSet::Item* item = m_editPal.getItem(0);
m_editMode = state; m_editMode = state;
item->setIcon(state ? theme->parts.timelineOpenPadlockActive():
theme->parts.timelineClosedPadlockNormal()); // The item icon/style will be set depending on m_editMode state.
item->setHotColor(state ? theme->colors.editPalFace(): gfx::ColorNone); ButtonSet::Item* item = m_editPal.getItem(0);
item->initTheme();
item->invalidate();
// Deselect color entries when we cancel editing // Deselect color entries when we cancel editing
if (!state) if (!state)
@ -553,16 +568,11 @@ void ColorBar::setTilemapMode(TilemapMode mode)
void ColorBar::updateFromTilemapMode() void ColorBar::updateFromTilemapMode()
{ {
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
ButtonSet::Item* item = m_tilesButton.getItem(0); ButtonSet::Item* item = m_tilesButton.getItem(0);
const bool canEditTiles = this->canEditTiles(); const bool canEditTiles = this->canEditTiles();
const bool editTiles = (canEditTiles && const bool editTiles = (canEditTiles &&
m_tilemapMode == TilemapMode::Tiles); m_tilemapMode == TilemapMode::Tiles);
item->initTheme();
item->setHotColor(editTiles ? theme->colors.editPalFace():
gfx::ColorNone);
item->setMono(true);
if (Preferences::instance().colorBar.showColorAndTiles()) { if (Preferences::instance().colorBar.showColorAndTiles()) {
m_scrollablePalView.setVisible(true); m_scrollablePalView.setVisible(true);

View File

@ -241,7 +241,6 @@ ColorSliders::ColorSliders()
, m_color(app::Color::fromMask()) , m_color(app::Color::fromMask())
{ {
addChild(&m_grid); addChild(&m_grid);
m_grid.setChildSpacing(0);
// Same order as in Channel enum // Same order as in Channel enum
static_assert(Channel::Red == (Channel)0, ""); static_assert(Channel::Red == (Channel)0, "");
@ -258,6 +257,12 @@ ColorSliders::ColorSliders()
addSlider(Channel::Gray, "V", 0, 255, -100, 100); addSlider(Channel::Gray, "V", 0, 255, -100, 100);
addSlider(Channel::Alpha, "A", 0, 255, -100, 100); addSlider(Channel::Alpha, "A", 0, 255, -100, 100);
InitTheme.connect(
[this] {
m_grid.setChildSpacing(0);
}
);
m_appConn = App::instance() m_appConn = App::instance()
->ColorSpaceChange.connect([this]{ invalidate(); }); ->ColorSpaceChange.connect([this]{ invalidate(); });
} }

View File

@ -162,7 +162,7 @@ public:
, m_brushes(App::instance()->brushes()) { , m_brushes(App::instance()->brushes()) {
SkinPartPtr part(new SkinPart); SkinPartPtr part(new SkinPart);
part->setBitmap(0, BrushPopup::createSurfaceForBrush(BrushRef(nullptr))); part->setBitmap(0, BrushPopup::createSurfaceForBrush(BrushRef(nullptr)));
addItem(part); addItem(part, "brush_type");
m_popupWindow.Open.connect( m_popupWindow.Open.connect(
[this]{ [this]{
@ -182,7 +182,11 @@ public:
part->setBitmap(0, BrushPopup::createSurfaceForBrush(brush)); part->setBitmap(0, BrushPopup::createSurfaceForBrush(brush));
const bool mono = (brush->type() != kImageBrushType); const bool mono = (brush->type() != kImageBrushType);
getItem(0)->setIcon(part, mono); getItem(0)->setIcon(part);
auto style = mono ? SkinTheme::instance()->styles.brushTypeMono() :
SkinTheme::instance()->styles.brushType();
getItem(0)->setStyle(style);
} }
void switchPopup() { void switchPopup() {
@ -380,7 +384,7 @@ class ContextBar::PaintBucketSettingsField : public ButtonSet {
public: public:
PaintBucketSettingsField() : ButtonSet(1) { PaintBucketSettingsField() : ButtonSet(1) {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.timelineGear()); addItem(theme->parts.timelineGear(), "context_bar_button");
} }
protected: protected:
@ -454,6 +458,7 @@ protected:
} }
}); });
menu.initTheme();
menu.showPopup(gfx::Point(bounds.x, bounds.y2()), menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
display()); display());
deselectItems(); deselectItems();
@ -466,7 +471,7 @@ public:
InkTypeField(ContextBar* owner) : ButtonSet(1) InkTypeField(ContextBar* owner) : ButtonSet(1)
, m_owner(owner) { , m_owner(owner) {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.inkSimple()); addItem(theme->parts.inkSimple(), "ink_type");
} }
void setInkType(InkType inkType) { void setInkType(InkType inkType) {
@ -863,7 +868,7 @@ class ContextBar::PivotField : public ButtonSet {
public: public:
PivotField() PivotField()
: ButtonSet(1) { : ButtonSet(1) {
addItem(SkinTheme::get(this)->parts.pivotCenter()); addItem(SkinTheme::get(this)->parts.pivotCenter(), "pivot_field");
m_pivotConn = Preferences::instance().selection.pivotPosition.AfterChange.connect( m_pivotConn = Preferences::instance().selection.pivotPosition.AfterChange.connect(
[this]{ onPivotChange(); }); [this]{ onPivotChange(); });
@ -883,15 +888,15 @@ private:
CheckBox visible(Strings::context_bar_default_display_pivot()); CheckBox visible(Strings::context_bar_default_display_pivot());
HBox box; HBox box;
ButtonSet buttonset(3); ButtonSet buttonset(3);
buttonset.addItem(theme->parts.pivotNorthwest()); buttonset.addItem(theme->parts.pivotNorthwest(), "pivot_dir");
buttonset.addItem(theme->parts.pivotNorth()); buttonset.addItem(theme->parts.pivotNorth(), "pivot_dir");
buttonset.addItem(theme->parts.pivotNortheast()); buttonset.addItem(theme->parts.pivotNortheast(), "pivot_dir");
buttonset.addItem(theme->parts.pivotWest()); buttonset.addItem(theme->parts.pivotWest(), "pivot_dir");
buttonset.addItem(theme->parts.pivotCenter()); buttonset.addItem(theme->parts.pivotCenter(), "pivot_dir");
buttonset.addItem(theme->parts.pivotEast()); buttonset.addItem(theme->parts.pivotEast(), "pivot_dir");
buttonset.addItem(theme->parts.pivotSouthwest()); buttonset.addItem(theme->parts.pivotSouthwest(), "pivot_dir");
buttonset.addItem(theme->parts.pivotSouth()); buttonset.addItem(theme->parts.pivotSouth(), "pivot_dir");
buttonset.addItem(theme->parts.pivotSoutheast()); buttonset.addItem(theme->parts.pivotSoutheast(), "pivot_dir");
box.addChild(&buttonset); box.addChild(&buttonset);
menu.addChild(&visible); menu.addChild(&visible);
@ -902,6 +907,7 @@ private:
app::gen::PivotPosition pos = Preferences::instance().selection.pivotPosition(); app::gen::PivotPosition pos = Preferences::instance().selection.pivotPosition();
visible.setSelected(isVisible); visible.setSelected(isVisible);
buttonset.setSelectedItem(int(pos)); buttonset.setSelectedItem(int(pos));
buttonset.initTheme();
visible.Click.connect( visible.Click.connect(
[&visible](){ [&visible](){
@ -1144,7 +1150,7 @@ public:
DynamicsField(ContextBar* ctxBar) DynamicsField(ContextBar* ctxBar)
: ButtonSet(1) : ButtonSet(1)
, m_ctxBar(ctxBar) { , m_ctxBar(ctxBar) {
addItem(SkinTheme::get(this)->parts.dynamics()); addItem(SkinTheme::get(this)->parts.dynamics(), "dynamics_field");
} }
void switchPopup() { void switchPopup() {
@ -1276,8 +1282,8 @@ public:
GradientTypeField() : ButtonSet(2) { GradientTypeField() : ButtonSet(2) {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.linearGradient()); addItem(theme->parts.linearGradient(), "context_bar_button");
addItem(theme->parts.radialGradient()); addItem(theme->parts.radialGradient(), "context_bar_button");
setSelectedItem(0); setSelectedItem(0);
} }
@ -1299,8 +1305,8 @@ public:
DropPixelsField() : ButtonSet(2) { DropPixelsField() : ButtonSet(2) {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.dropPixelsOk()); addItem(theme->parts.dropPixelsOk(), "context_bar_button");
addItem(theme->parts.dropPixelsCancel()); addItem(theme->parts.dropPixelsCancel(), "context_bar_button");
setOfferCapture(false); setOfferCapture(false);
} }
@ -1407,9 +1413,9 @@ public:
SymmetryField() : ButtonSet(3) { SymmetryField() : ButtonSet(3) {
setMultiMode(MultiMode::Set); setMultiMode(MultiMode::Set);
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.horizontalSymmetry()); addItem(theme->parts.horizontalSymmetry(), "symmetry_field");
addItem(theme->parts.verticalSymmetry()); addItem(theme->parts.verticalSymmetry(), "symmetry_field");
addItem("..."); addItem("...", "symmetry_options");
} }
void setupTooltips(TooltipManager* tooltipManager) { void setupTooltips(TooltipManager* tooltipManager) {
@ -1544,8 +1550,8 @@ public:
m_combobox.setExpansive(true); m_combobox.setExpansive(true);
m_combobox.setMinSize(gfx::Size(256*guiscale(), 0)); m_combobox.setMinSize(gfx::Size(256*guiscale(), 0));
m_action.addItem(theme->parts.iconUserData())->setMono(true); m_action.addItem(theme->parts.iconUserData(), "buttonset_item_icon_mono");
m_action.addItem(theme->parts.iconClose())->setMono(true); m_action.addItem(theme->parts.iconClose(), "buttonset_item_icon_mono");
m_action.ItemChange.connect( m_action.ItemChange.connect(
[this](ButtonSet::Item* item){ [this](ButtonSet::Item* item){
onAction(m_action.selectedItem()); onAction(m_action.selectedItem());

View File

@ -24,10 +24,10 @@ SelectionModeField::SelectionModeField()
{ {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.selectionReplace()); addItem(theme->parts.selectionReplace(), "selection_mode");
addItem(theme->parts.selectionAdd()); addItem(theme->parts.selectionAdd(), "selection_mode");
addItem(theme->parts.selectionSubtract()); addItem(theme->parts.selectionSubtract(), "selection_mode");
addItem(theme->parts.selectionIntersect()); addItem(theme->parts.selectionIntersect(), "selection_mode");
setSelectedItem((int)Preferences::instance().selection.mode()); setSelectedItem((int)Preferences::instance().selection.mode());
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019-2022 Igara Studio S.A. // Copyright (C) 2019-2023 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -44,6 +44,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <memory>
#define BGCOLOR (getWidgetBgColor(widget)) #define BGCOLOR (getWidgetBgColor(widget))
@ -56,37 +57,76 @@ using namespace ui;
// TODO For backward compatibility, in future versions we should remove this (extensions are preferred) // TODO For backward compatibility, in future versions we should remove this (extensions are preferred)
const char* SkinTheme::kThemesFolderName = "themes"; const char* SkinTheme::kThemesFolderName = "themes";
// This class offer backward compatibility with old themes, completing // Offers backward compatibility with old themes, copying missing
// or changing styles from the default theme to match the default // styles (raw XML <style> elements) from the default theme to the
// theme of previous versions, so third-party themes can look like // current theme. This must be done so all <style> elements in the new
// they are running in the old Aseprite without any modification. // theme use colors and parts from the new theme instead of the
struct app::skin::SkinTheme::BackwardCompatibility { // default one (as when they were loaded).
bool hasSliderStyle = false; class app::skin::SkinTheme::BackwardCompatibility {
void notifyStyleExistence(const char* styleId) {
if (std::strcmp(styleId, "slider") == 0) enum class State {
hasSliderStyle = true; // When we are loading the default theme
LoadingStyles,
// When we are loading the selected theme (so we must copy missing
// styles from the previously loaded default theme)
CopyingStyles,
};
State m_state = State::LoadingStyles;
// Loaded XML <style> element from the original theme (cloned
// elements). Must be in order to insert them in the same order in
// the selected theme.
std::vector<std::unique_ptr<TiXmlElement>> m_styles;
public:
void copyingStyles() {
m_state = State::CopyingStyles;
} }
void createMissingStyles(SkinTheme* theme) {
if (!hasSliderStyle &&
theme->styles.slider() &&
theme->styles.miniSlider()) {
// Old slider style
ui::Style style(nullptr);
os::Font* font = theme->getDefaultFont();
const int h = font->height();
style.setId(theme->styles.slider()->id()); // Called for each <style> element found in theme.xml.
style.setFont(AddRef(font)); void onStyle(TiXmlElement* xmlStyle) {
// Loading <style> from the default theme
if (m_state == State::LoadingStyles)
m_styles.emplace_back((TiXmlElement*)xmlStyle->Clone());
}
auto part = theme->parts.sliderEmpty(); void removeExistentStyles(TiXmlElement* xmlStyle) {
style.setBorder( if (m_state != State::CopyingStyles)
gfx::Border(part->bitmapW()->width()-1*guiscale(), return;
part->bitmapN()->height()+h/2,
part->bitmapE()->width()-1*guiscale(),
part->bitmapS()->height()-1*guiscale()+h/2));
*theme->styles.slider() = style; while (xmlStyle) {
*theme->styles.miniSlider() = style; const char* s = xmlStyle->Attribute("id");
if (!s)
break;
std::string styleId = s;
// Remove any existent style in the selected theme.
auto it = std::find_if(m_styles.begin(),
m_styles.end(),
[styleId](auto& style){
return (style->Attribute("id") == styleId);
});
if (it != m_styles.end())
m_styles.erase(it);
xmlStyle = xmlStyle->NextSiblingElement();
}
}
// Copies all missing <style> elements to the new theme. xmlStyles
// is the <styles> element from the theme.xml of the selected theme
// (non the default one).
void copyMissingStyles(TiXmlNode* xmlStyles) {
if (m_state != State::CopyingStyles)
return;
for (auto& style : m_styles) {
LOG(VERBOSE, "THEME: Copying <style id='%s'> from default theme\n",
style->Attribute("id"));
// InsertEndChild() clones the node
xmlStyles->InsertEndChild(*style.get());
} }
} }
}; };
@ -265,15 +305,16 @@ SkinTheme::~SkinTheme()
void SkinTheme::onRegenerateTheme() void SkinTheme::onRegenerateTheme()
{ {
Preferences& pref = Preferences::instance(); Preferences& pref = Preferences::instance();
BackwardCompatibility backward;
// First we load the skin from default theme, which is more proper // First we load the skin from default theme, which is more proper
// to have every single needed skin part/color/dimension. // to have every single needed skin part/color/dimension.
loadAll(pref.theme.selected.defaultValue()); loadAll(pref.theme.selected.defaultValue(), &backward);
// Then we load the selected theme to redefine default theme parts. // Then we load the selected theme to redefine default theme parts.
if (pref.theme.selected.defaultValue() != pref.theme.selected()) { if (pref.theme.selected.defaultValue() != pref.theme.selected()) {
try { try {
BackwardCompatibility backward; backward.copyingStyles();
loadAll(pref.theme.selected(), &backward); loadAll(pref.theme.selected(), &backward);
} }
catch (const std::exception& e) { catch (const std::exception& e) {
@ -409,8 +450,11 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
if (sizeStr) if (sizeStr)
size = std::strtol(sizeStr, nullptr, 10); size = std::strtol(sizeStr, nullptr, 10);
const char* mnemonicsStr = xmlFont->Attribute("mnemonics");
bool mnemonics = mnemonicsStr ? (std::string(mnemonicsStr) != "off") : true;
os::FontRef font = fontData->getFont(size); os::FontRef font = fontData->getFont(size);
m_themeFonts[idStr] = font; m_themeFonts[idStr] = ThemeFont(font, mnemonics);
if (id == "default") if (id == "default")
m_defaultFont = font; m_defaultFont = font;
@ -551,6 +595,11 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
if (!xmlStyle) // Without styles? if (!xmlStyle) // Without styles?
throw base::Exception("There are no styles"); throw base::Exception("There are no styles");
if (backward) {
backward->removeExistentStyles(xmlStyle);
backward->copyMissingStyles(xmlStyle->Parent());
}
while (xmlStyle) { while (xmlStyle) {
const char* style_id = xmlStyle->Attribute("id"); const char* style_id = xmlStyle->Attribute("id");
if (!style_id) { if (!style_id) {
@ -564,7 +613,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
base = m_styles[extends_id]; base = m_styles[extends_id];
if (backward) if (backward)
backward->notifyStyleExistence(style_id); backward->onStyle(xmlStyle);
ui::Style* style = m_styles[style_id]; ui::Style* style = m_styles[style_id];
if (!style) { if (!style) {
@ -582,7 +631,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
const char* t = xmlStyle->Attribute("margin-top"); const char* t = xmlStyle->Attribute("margin-top");
const char* r = xmlStyle->Attribute("margin-right"); const char* r = xmlStyle->Attribute("margin-right");
const char* b = xmlStyle->Attribute("margin-bottom"); const char* b = xmlStyle->Attribute("margin-bottom");
gfx::Border margin = ui::Style::UndefinedBorder(); gfx::Border margin = style->margin();
if (m || l) margin.left(scale*std::strtol(l ? l: m, nullptr, 10)); if (m || l) margin.left(scale*std::strtol(l ? l: m, nullptr, 10));
if (m || t) margin.top(scale*std::strtol(t ? t: m, nullptr, 10)); if (m || t) margin.top(scale*std::strtol(t ? t: m, nullptr, 10));
if (m || r) margin.right(scale*std::strtol(r ? r: m, nullptr, 10)); if (m || r) margin.right(scale*std::strtol(r ? r: m, nullptr, 10));
@ -597,7 +646,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
const char* t = xmlStyle->Attribute("border-top"); const char* t = xmlStyle->Attribute("border-top");
const char* r = xmlStyle->Attribute("border-right"); const char* r = xmlStyle->Attribute("border-right");
const char* b = xmlStyle->Attribute("border-bottom"); const char* b = xmlStyle->Attribute("border-bottom");
gfx::Border border = ui::Style::UndefinedBorder(); gfx::Border border = style->border();
if (m || l) border.left(scale*std::strtol(l ? l: m, nullptr, 10)); if (m || l) border.left(scale*std::strtol(l ? l: m, nullptr, 10));
if (m || t) border.top(scale*std::strtol(t ? t: m, nullptr, 10)); if (m || t) border.top(scale*std::strtol(t ? t: m, nullptr, 10));
if (m || r) border.right(scale*std::strtol(r ? r: m, nullptr, 10)); if (m || r) border.right(scale*std::strtol(r ? r: m, nullptr, 10));
@ -612,7 +661,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
const char* t = xmlStyle->Attribute("padding-top"); const char* t = xmlStyle->Attribute("padding-top");
const char* r = xmlStyle->Attribute("padding-right"); const char* r = xmlStyle->Attribute("padding-right");
const char* b = xmlStyle->Attribute("padding-bottom"); const char* b = xmlStyle->Attribute("padding-bottom");
gfx::Border padding = ui::Style::UndefinedBorder(); gfx::Border padding = style->padding();
if (m || l) padding.left(scale*std::strtol(l ? l: m, nullptr, 10)); if (m || l) padding.left(scale*std::strtol(l ? l: m, nullptr, 10));
if (m || t) padding.top(scale*std::strtol(t ? t: m, nullptr, 10)); if (m || t) padding.top(scale*std::strtol(t ? t: m, nullptr, 10));
if (m || r) padding.right(scale*std::strtol(r ? r: m, nullptr, 10)); if (m || r) padding.right(scale*std::strtol(r ? r: m, nullptr, 10));
@ -620,12 +669,57 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
style->setPadding(padding); style->setPadding(padding);
} }
// Size
{
const char* width = xmlStyle->Attribute("width");
const char* height = xmlStyle->Attribute("height");
const char* minwidth = xmlStyle->Attribute("minwidth");
const char* minheight = xmlStyle->Attribute("minheight");
const char* maxwidth = xmlStyle->Attribute("maxwidth");
const char* maxheight = xmlStyle->Attribute("maxheight");
gfx::Size minSize = style->minSize();
gfx::Size maxSize = style->maxSize();
if (width) {
if (!minwidth) minwidth = width;
if (!maxwidth) maxwidth = width;
}
if (height) {
if (!minheight) minheight = height;
if (!maxheight) maxheight = height;
}
if (minwidth) minSize.w = scale*std::strtol(minwidth, nullptr, 10);
if (minheight) minSize.h = scale*std::strtol(minheight, nullptr, 10);
if (maxwidth) maxSize.w = scale*std::strtol(maxwidth, nullptr, 10);
if (maxheight) maxSize.h = scale*std::strtol(maxheight, nullptr, 10);
style->setMinSize(minSize);
style->setMaxSize(maxSize);
}
// Gap
{
const char* m = xmlStyle->Attribute("gap");
const char* r = xmlStyle->Attribute("gap-rows");
const char* c = xmlStyle->Attribute("gap-columns");
gfx::Size gap = style->gap();
if (m || c) gap.w = scale*std::strtol(c ? c: m, nullptr, 10);
if (m || r) gap.h = scale*std::strtol(r ? r: m, nullptr, 10);
style->setGap(gap);
}
// Font // Font
{ {
const char* fontId = xmlStyle->Attribute("font"); const char* fontId = xmlStyle->Attribute("font");
if (fontId) { if (fontId) {
os::FontRef font = m_themeFonts[fontId]; auto themeFont = m_themeFonts[fontId];
style->setFont(font); style->setFont(themeFont.font());
style->setMnemonics(themeFont.mnemonics());
}
// Override mnemonics value if it is defined for this style.
const char* mnemonicsStr = xmlStyle->Attribute("mnemonics");
if (mnemonicsStr) {
bool mnemonics = mnemonicsStr ? (std::string(mnemonicsStr) != "off") : true;
style->setMnemonics(mnemonics);
} }
} }
@ -666,6 +760,7 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
if (state.find("selected") != std::string::npos) flags |= ui::Style::Layer::kSelected; if (state.find("selected") != std::string::npos) flags |= ui::Style::Layer::kSelected;
if (state.find("focus") != std::string::npos) flags |= ui::Style::Layer::kFocus; if (state.find("focus") != std::string::npos) flags |= ui::Style::Layer::kFocus;
if (state.find("mouse") != std::string::npos) flags |= ui::Style::Layer::kMouse; if (state.find("mouse") != std::string::npos) flags |= ui::Style::Layer::kMouse;
if (state.find("capture") != std::string::npos) flags |= ui::Style::Layer::kCapture;
layer.setFlags(flags); layer.setFlags(flags);
} }
@ -749,9 +844,6 @@ void SkinTheme::loadXml(BackwardCompatibility* backward)
} }
} }
if (backward)
backward->createMissingStyles(this);
ThemeFile<SkinTheme>::updateInternals(); ThemeFile<SkinTheme>::updateInternals();
} }
@ -843,6 +935,7 @@ void SkinTheme::initWidget(Widget* widget)
widget->setStyle(styles.grid()); widget->setStyle(styles.grid());
BORDER(0); BORDER(0);
widget->setChildSpacing(4 * scale); widget->setChildSpacing(4 * scale);
static_cast<ui::Grid *>(widget)->setGap(styles.grid()->gap());
break; break;
case kLabelWidget: case kLabelWidget:

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020-2022 Igara Studio S.A. // Copyright (C) 2020-2023 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -34,6 +34,17 @@ namespace app {
class FontData; class FontData;
class ThemeFont {
public:
ThemeFont() {}
ThemeFont(os::FontRef font, bool mnemonics) : m_font(font), m_mnemonics(mnemonics) {}
os::FontRef font() { return m_font; }
bool mnemonics() { return m_mnemonics; }
private:
os::FontRef m_font;
bool m_mnemonics;
};
// This is the GUI theme used by Aseprite (which use images from // This is the GUI theme used by Aseprite (which use images from
// data/skins directory). // data/skins directory).
class SkinTheme : public ui::Theme class SkinTheme : public ui::Theme
@ -130,7 +141,7 @@ namespace app {
void onRegenerateTheme() override; void onRegenerateTheme() override;
private: private:
struct BackwardCompatibility; class BackwardCompatibility;
void loadFontData(); void loadFontData();
void loadAll(const std::string& themeId, void loadAll(const std::string& themeId,
@ -161,7 +172,7 @@ namespace app {
std::array<ui::Cursor*, ui::kCursorTypes> m_standardCursors; std::array<ui::Cursor*, ui::kCursorTypes> m_standardCursors;
std::map<std::string, ui::Style*> m_styles; std::map<std::string, ui::Style*> m_styles;
std::map<std::string, FontData*> m_fonts; std::map<std::string, FontData*> m_fonts;
std::map<std::string, os::FontRef> m_themeFonts; std::map<std::string, ThemeFont> m_themeFonts;
os::FontRef m_defaultFont; os::FontRef m_defaultFont;
os::FontRef m_miniFont; os::FontRef m_miniFont;
int m_preferredScreenScaling; int m_preferredScreenScaling;

View File

@ -44,11 +44,11 @@ AniControls::AniControls(TooltipManager* tooltipManager)
{ {
auto theme = SkinTheme::get(this); auto theme = SkinTheme::get(this);
addItem(theme->parts.aniFirst()); addItem(theme->parts.aniFirst(), "ani_button");
addItem(theme->parts.aniPrevious()); addItem(theme->parts.aniPrevious(), "ani_button");
addItem(theme->parts.aniPlay()); addItem(theme->parts.aniPlay(), "ani_button");
addItem(theme->parts.aniNext()); addItem(theme->parts.aniNext(), "ani_button");
addItem(theme->parts.aniLast()); addItem(theme->parts.aniLast(), "ani_button");
ItemChange.connect([this]{ onClickButton(); }); ItemChange.connect([this]{ onClickButton(); });
setTriggerOnMouseUp(true); setTriggerOnMouseUp(true);

View File

@ -1,5 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2018-2020 Igara Studio S.A. // Copyright (C) 2018-2023 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -40,6 +40,8 @@ Grid::Cell::Cell()
Grid::Grid(int columns, bool same_width_columns) Grid::Grid(int columns, bool same_width_columns)
: Widget(kGridWidget) : Widget(kGridWidget)
, m_rowgap(0)
, m_colgap(0)
, m_colstrip(columns) , m_colstrip(columns)
{ {
ASSERT(columns > 0); ASSERT(columns > 0);
@ -121,6 +123,18 @@ Grid::Info Grid::getChildInfo(Widget* child)
return info; return info;
} }
void Grid::setStyle(Style* style)
{
Widget::setStyle(style);
setGap(style->gap());
}
void Grid::setGap(const gfx::Size& gap)
{
m_colgap = gap.w;
m_rowgap = gap.h;
}
void Grid::onResize(ResizeEvent& ev) void Grid::onResize(ResizeEvent& ev)
{ {
gfx::Rect rect = ev.bounds(); gfx::Rect rect = ev.bounds();
@ -181,15 +195,20 @@ void Grid::onResize(ResizeEvent& ev)
if (y+h > rect.y+rect.h-border().bottom()) if (y+h > rect.y+rect.h-border().bottom())
h = rect.y+rect.h-border().bottom()-y; h = rect.y+rect.h-border().bottom()-y;
if (m_colgap < 0 && col+cell->hspan-1 < (int)m_colstrip.size()-1)
w += m_colgap;
if (m_rowgap < 0 && row+cell->vspan-1 < (int)m_rowstrip.size()-1)
h += m_rowgap;
cell->child->setBounds(Rect(x, y, w, h)); cell->child->setBounds(Rect(x, y, w, h));
} }
if (m_colstrip[col].size > 0) if (m_colstrip[col].size > 0)
pos_x += m_colstrip[col].size + childSpacing(); pos_x += m_colstrip[col].size + childSpacing() + m_colgap;
} }
if (m_rowstrip[row].size > 0) if (m_rowstrip[row].size > 0)
pos_y += m_rowstrip[row].size + childSpacing(); pos_y += m_rowstrip[row].size + childSpacing() + m_rowgap;
} }
} }
@ -211,13 +230,14 @@ void Grid::onSizeHint(SizeHintEvent& ev)
void Grid::sumStripSize(const std::vector<Strip>& strip, int& size) void Grid::sumStripSize(const std::vector<Strip>& strip, int& size)
{ {
int i, j; int i, j;
int gap = (&strip == &m_colstrip ? m_colgap: m_rowgap);
size = 0; size = 0;
for (i=j=0; i<(int)strip.size(); ++i) { for (i=j=0; i<(int)strip.size(); ++i) {
if (strip[i].size > 0) { if (strip[i].size > 0) {
size += strip[i].size; size += strip[i].size;
if (++j > 1) if (++j > 1)
size += this->childSpacing(); size += this->childSpacing()+gap;
} }
} }
} }
@ -225,6 +245,7 @@ void Grid::sumStripSize(const std::vector<Strip>& strip, int& size)
void Grid::calculateCellSize(int start, int span, const std::vector<Strip>& strip, int& size) void Grid::calculateCellSize(int start, int span, const std::vector<Strip>& strip, int& size)
{ {
int i, j; int i, j;
int gap = (&strip == &m_colstrip ? m_colgap: m_rowgap);
size = 0; size = 0;
@ -232,7 +253,7 @@ void Grid::calculateCellSize(int start, int span, const std::vector<Strip>& stri
if (strip[i].size > 0) { if (strip[i].size > 0) {
size += strip[i].size; size += strip[i].size;
if (++j > 1) if (++j > 1)
size += this->childSpacing(); size += this->childSpacing()+gap;
} }
} }
} }
@ -283,8 +304,8 @@ void Grid::calculateStripSize(std::vector<Strip>& colstrip,
// If the widget isn't hidden then we can request its size // If the widget isn't hidden then we can request its size
if (!(cell->child->hasFlags(HIDDEN))) { if (!(cell->child->hasFlags(HIDDEN))) {
Size reqSize = cell->child->sizeHint(); Size reqSize = cell->child->sizeHint();
cell->w = reqSize.w - (cell->hspan-1) * this->childSpacing(); cell->w = reqSize.w - (cell->hspan-1) * (this->childSpacing()+m_colgap);
cell->h = reqSize.h - (cell->vspan-1) * this->childSpacing(); cell->h = reqSize.h - (cell->vspan-1) * (this->childSpacing()+m_rowgap);
if ((cell->align & align) == align) if ((cell->align & align) == align)
++expand_count; ++expand_count;
@ -397,6 +418,7 @@ void Grid::distributeStripSize(std::vector<Strip>& colstrip,
int rect_size, int border_size, bool same_width) int rect_size, int border_size, bool same_width)
{ {
int i, j; int i, j;
int gap = (&colstrip == &m_colstrip ? m_colgap: m_rowgap);
int max_expand_count = 0; int max_expand_count = 0;
for (i=0; i<(int)colstrip.size(); ++i) for (i=0; i<(int)colstrip.size(); ++i)
@ -409,7 +431,7 @@ void Grid::distributeStripSize(std::vector<Strip>& colstrip,
if (colstrip[i].size > 0) { if (colstrip[i].size > 0) {
total_req += colstrip[i].size; total_req += colstrip[i].size;
if (++j > 1) if (++j > 1)
total_req += this->childSpacing(); total_req += this->childSpacing()+gap;
} }
if (colstrip[i].expand_count == max_expand_count || same_width) { if (colstrip[i].expand_count == max_expand_count || same_width) {
@ -430,7 +452,7 @@ void Grid::distributeStripSize(std::vector<Strip>& colstrip,
for (i=0; i<(int)colstrip.size(); ++i) { for (i=0; i<(int)colstrip.size(); ++i) {
if ((colstrip[i].size == 0) && if ((colstrip[i].size == 0) &&
(colstrip[i].expand_count == max_expand_count || same_width)) { (colstrip[i].expand_count == max_expand_count || same_width)) {
extra_total -= SGN(extra_total)*this->childSpacing(); extra_total -= SGN(extra_total)*(this->childSpacing()+gap);
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2023 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -31,12 +32,19 @@ namespace ui {
void addChildInCell(Widget* child, int hspan, int vspan, int align); void addChildInCell(Widget* child, int hspan, int vspan, int align);
Info getChildInfo(Widget* child); Info getChildInfo(Widget* child);
void setGap(const gfx::Size& gap);
void setStyle(Style* style) override;
protected: protected:
// Events // Events
void onResize(ResizeEvent& ev) override; void onResize(ResizeEvent& ev) override;
void onSizeHint(SizeHintEvent& ev) override; void onSizeHint(SizeHintEvent& ev) override;
// Separation between rows of grid cells. Negative values will overlap rows.
int m_rowgap;
// Separation between columns of grid cells. Negative values will overlap columns.
int m_colgap;
private: private:
struct Cell { struct Cell {
Cell* parent; Cell* parent;

View File

@ -21,17 +21,47 @@ gfx::Border Style::UndefinedBorder()
return gfx::Border(-1, -1, -1, -1); return gfx::Border(-1, -1, -1, -1);
} }
// static
gfx::Size Style::MinSize()
{
return gfx::Size(0, 0);
}
// static
gfx::Size Style::MaxSize()
{
return gfx::Size(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
}
Style::Style(const Style* base) Style::Style(const Style* base)
: m_insertionPoint(0) : m_insertionPoint(0)
, m_margin(base ? base->margin(): Style::UndefinedBorder()) , m_margin(base ? base->margin(): Style::UndefinedBorder())
, m_border(base ? base->border(): Style::UndefinedBorder()) , m_border(base ? base->border(): Style::UndefinedBorder())
, m_padding(base ? base->padding(): Style::UndefinedBorder()) , m_padding(base ? base->padding(): Style::UndefinedBorder())
, m_minSize(base ? base->minSize(): Style::MinSize())
, m_maxSize(base ? base->maxSize(): Style::MaxSize())
, m_gap(base ? base->gap(): gfx::Size(0, 0))
, m_font(nullptr) , m_font(nullptr)
, m_mnemonics(base ? base->mnemonics() : true)
{ {
if (base) if (base)
m_layers = base->layers(); m_layers = base->layers();
} }
void Style::setMinSize(const gfx::Size& sz)
{
ASSERT(sz.w <= m_maxSize.w);
ASSERT(sz.h <= m_maxSize.h);
m_minSize = sz;
}
void Style::setMaxSize(const gfx::Size& sz)
{
ASSERT(sz.w >= m_minSize.w);
ASSERT(sz.h >= m_minSize.h);
m_maxSize = sz;
}
void Style::setFont(const os::Ref<os::Font>& font) void Style::setFont(const os::Ref<os::Font>& font)
{ {
m_font = font; m_font = font;

View File

@ -48,6 +48,12 @@ namespace ui {
kFocus = 2, kFocus = 2,
kSelected = 4, kSelected = 4,
kDisabled = 8, kDisabled = 8,
kCapture = 16
};
class IconSurfaceProvider {
public:
virtual os::Surface* iconSurface() const = 0;
}; };
Layer() Layer()
@ -97,13 +103,20 @@ namespace ui {
static gfx::Border UndefinedBorder(); static gfx::Border UndefinedBorder();
static gfx::Size MinSize();
static gfx::Size MaxSize();
Style(const Style* base); Style(const Style* base);
const std::string& id() const { return m_id; } const std::string& id() const { return m_id; }
const gfx::Border& margin() const { return m_margin; } const gfx::Border& margin() const { return m_margin; }
const gfx::Border& border() const { return m_border; } const gfx::Border& border() const { return m_border; }
const gfx::Border& padding() const { return m_padding; } const gfx::Border& padding() const { return m_padding; }
const gfx::Size& minSize() const { return m_minSize; }
const gfx::Size& maxSize() const { return m_maxSize; }
const gfx::Size& gap() const { return m_gap; }
os::Font* font() const { return m_font.get(); } os::Font* font() const { return m_font.get(); }
const bool mnemonics() const { return m_mnemonics; }
const Layers& layers() const { return m_layers; } const Layers& layers() const { return m_layers; }
Layers& layers() { return m_layers; } Layers& layers() { return m_layers; }
@ -111,7 +124,11 @@ namespace ui {
void setMargin(const gfx::Border& value) { m_margin = value; } void setMargin(const gfx::Border& value) { m_margin = value; }
void setBorder(const gfx::Border& value) { m_border = value; } void setBorder(const gfx::Border& value) { m_border = value; }
void setPadding(const gfx::Border& value) { m_padding = value; } void setPadding(const gfx::Border& value) { m_padding = value; }
void setMinSize(const gfx::Size& sz);
void setMaxSize(const gfx::Size& sz);
void setGap(const gfx::Size& value) { m_gap = value; }
void setFont(const os::FontRef& font); void setFont(const os::FontRef& font);
void setMnemonics(const bool enabled) { m_mnemonics = enabled; }
void addLayer(const Layer& layer); void addLayer(const Layer& layer);
private: private:
@ -121,7 +138,14 @@ namespace ui {
gfx::Border m_margin; gfx::Border m_margin;
gfx::Border m_border; gfx::Border m_border;
gfx::Border m_padding; gfx::Border m_padding;
// Min width and height for the widget.
gfx::Size m_minSize;
// Max width and height for the widget.
gfx::Size m_maxSize;
// Grid's columns and rows separation in pixels.
gfx::Size m_gap;
os::FontRef m_font; os::FontRef m_font;
bool m_mnemonics;
}; };
} // namespace ui } // namespace ui

View File

@ -104,6 +104,7 @@ PaintWidgetPartInfo::PaintWidgetPartInfo()
styleFlags = 0; styleFlags = 0;
text = nullptr; text = nullptr;
mnemonic = 0; mnemonic = 0;
icon = nullptr;
} }
PaintWidgetPartInfo::PaintWidgetPartInfo(const Widget* widget) PaintWidgetPartInfo::PaintWidgetPartInfo(const Widget* widget)
@ -114,6 +115,10 @@ PaintWidgetPartInfo::PaintWidgetPartInfo(const Widget* widget)
styleFlags = PaintWidgetPartInfo::getStyleFlagsForWidget(widget); styleFlags = PaintWidgetPartInfo::getStyleFlagsForWidget(widget);
text = &widget->text(); text = &widget->text();
mnemonic = widget->mnemonic(); mnemonic = widget->mnemonic();
icon = nullptr;
if (const Style::Layer::IconSurfaceProvider* iconProvider = dynamic_cast<const Style::Layer::IconSurfaceProvider*>(widget)) {
icon = iconProvider->iconSurface();
}
} }
// static // static
@ -123,7 +128,8 @@ int PaintWidgetPartInfo::getStyleFlagsForWidget(const Widget* widget)
(widget->isEnabled() ? 0: Style::Layer::kDisabled) | (widget->isEnabled() ? 0: Style::Layer::kDisabled) |
(widget->isSelected() ? Style::Layer::kSelected: 0) | (widget->isSelected() ? Style::Layer::kSelected: 0) |
(widget->hasMouse() ? Style::Layer::kMouse: 0) | (widget->hasMouse() ? Style::Layer::kMouse: 0) |
(widget->hasFocus() ? Style::Layer::kFocus: 0); (widget->hasFocus() ? Style::Layer::kFocus: 0) |
(widget->hasCapture() ? Style::Layer::kCapture: 0);
} }
Theme::Theme() Theme::Theme()
@ -201,7 +207,7 @@ void Theme::paintWidgetPart(Graphics* g,
(const Style::Layer& layer) { (const Style::Layer& layer) {
paintLayer(g, style, layer, paintLayer(g, style, layer,
(info.text ? *info.text: std::string()), (info.text ? *info.text: std::string()),
info.mnemonic, rc, outBgColor); info.mnemonic, info.icon, rc, outBgColor);
}); });
} }
@ -318,6 +324,7 @@ void Theme::paintLayer(Graphics* g,
const Style::Layer& layer, const Style::Layer& layer,
const std::string& text, const std::string& text,
const int mnemonic, const int mnemonic,
os::Surface* providedIcon,
gfx::Rect& rc, gfx::Rect& rc,
gfx::Color& bgColor) gfx::Color& bgColor)
{ {
@ -443,27 +450,37 @@ void Theme::paintLayer(Graphics* g,
else { else {
gfx::Size textSize = g->measureUIText(text); gfx::Size textSize = g->measureUIText(text);
gfx::Point pt; gfx::Point pt;
gfx::Border undef = Style::UndefinedBorder();
gfx::Border padding = style->padding();
if (padding.left() == undef.left()) padding.left(0);
if (padding.right() == undef.right()) padding.right(0);
if (padding.top() == undef.top()) padding.top(0);
if (padding.bottom() == undef.bottom()) padding.bottom(0);
if (layer.align() & LEFT) if (layer.align() & LEFT)
pt.x = rc.x; pt.x = rc.x+padding.left();
else if (layer.align() & RIGHT) else if (layer.align() & RIGHT)
pt.x = rc.x+rc.w-textSize.w; pt.x = rc.x+rc.w-textSize.w-padding.right();
else else {
pt.x = rc.x+rc.w/2-textSize.w/2; pt.x = rc.x+padding.left()+(rc.w-padding.width())/2-textSize.w/2;
ADJUST_TO_GUISCALE(pt.x);
}
if (layer.align() & TOP) if (layer.align() & TOP)
pt.y = rc.y; pt.y = rc.y+padding.top();
else if (layer.align() & BOTTOM) else if (layer.align() & BOTTOM)
pt.y = rc.y+rc.h-textSize.h; pt.y = rc.y+rc.h-textSize.h-padding.bottom();
else else {
pt.y = rc.y+rc.h/2-textSize.h/2; pt.y = rc.y+padding.top()+(rc.h-padding.height())/2-textSize.h/2;
ADJUST_TO_GUISCALE(pt.y);
}
pt += layer.offset(); pt += layer.offset();
g->drawUIText(text, g->drawUIText(text,
layer.color(), layer.color(),
bgColor, bgColor,
pt, mnemonic); pt, style->mnemonics() ? mnemonic : 0);
} }
if (style->font()) if (style->font())
@ -472,24 +489,34 @@ void Theme::paintLayer(Graphics* g,
break; break;
case Style::Layer::Type::kIcon: { case Style::Layer::Type::kIcon: {
os::Surface* icon = layer.icon(); os::Surface* icon = providedIcon ? providedIcon : layer.icon();
if (icon) { if (icon) {
gfx::Size iconSize(icon->width(), icon->height()); gfx::Size iconSize(icon->width(), icon->height());
gfx::Point pt; gfx::Point pt;
gfx::Border undef = Style::UndefinedBorder();
gfx::Border padding = style->padding();
if (padding.left() == undef.left()) padding.left(0);
if (padding.right() == undef.right()) padding.right(0);
if (padding.top() == undef.top()) padding.top(0);
if (padding.bottom() == undef.bottom()) padding.bottom(0);
if (layer.align() & LEFT) if (layer.align() & LEFT)
pt.x = rc.x; pt.x = rc.x+padding.left();
else if (layer.align() & RIGHT) else if (layer.align() & RIGHT)
pt.x = rc.x+rc.w-iconSize.w; pt.x = rc.x+rc.w-iconSize.w-padding.right();
else else {
pt.x = rc.x+rc.w/2-iconSize.w/2; pt.x = rc.x+padding.left()+(rc.w-padding.width())/2-iconSize.w/2;
ADJUST_TO_GUISCALE(pt.x);
}
if (layer.align() & TOP) if (layer.align() & TOP)
pt.y = rc.y; pt.y = rc.y+padding.top();
else if (layer.align() & BOTTOM) else if (layer.align() & BOTTOM)
pt.y = rc.y+rc.h-iconSize.h; pt.y = rc.y+rc.h-iconSize.h-padding.bottom();
else else {
pt.y = rc.y+rc.h/2-iconSize.h/2; pt.y = rc.y+padding.top()+(rc.h-padding.height())/2-iconSize.h/2;
ADJUST_TO_GUISCALE(pt.y);
}
pt += layer.offset(); pt += layer.offset();
@ -578,7 +605,11 @@ void Theme::measureLayer(const Widget* widget,
break; break;
case Style::Layer::Type::kIcon: { case Style::Layer::Type::kIcon: {
os::Surface* icon = layer.icon(); const os::Surface* icon = layer.icon();
if (const Style::Layer::IconSurfaceProvider* iconProvider = dynamic_cast<const Style::Layer::IconSurfaceProvider*>(widget)) {
icon = iconProvider->iconSurface() ? iconProvider->iconSurface() : icon;
}
if (icon) { if (icon) {
iconHint.w = std::max(iconHint.w, icon->width()+ABS(layer.offset().x)); iconHint.w = std::max(iconHint.w, icon->width()+ABS(layer.offset().x));
iconHint.h = std::max(iconHint.h, icon->height()+ABS(layer.offset().y)); iconHint.h = std::max(iconHint.h, icon->height()+ABS(layer.offset().y));
@ -650,6 +681,34 @@ gfx::Color Theme::calcBgColor(const Widget* widget,
return bgColor; return bgColor;
} }
gfx::Size Theme::calcMinSize(const Widget* widget,
const Style* style)
{
ASSERT(widget);
ASSERT(style);
gfx::Size sz = widget->minSize();
if (sz.w == 0) sz.w = style->minSize().w;
if (sz.h == 0) sz.h = style->minSize().h;
return sz;
}
gfx::Size Theme::calcMaxSize(const Widget* widget,
const Style* style)
{
ASSERT(widget);
ASSERT(style);
gfx::Size sz = widget->maxSize();
if (sz.w == std::numeric_limits<int>::max()) sz.w = style->maxSize().w;
if (sz.h == std::numeric_limits<int>::max()) sz.h = style->maxSize().h;
return sz;
}
void Theme::calcWidgetMetrics(const Widget* widget, void Theme::calcWidgetMetrics(const Widget* widget,
const Style* style, const Style* style,
gfx::Size& sizeHint, gfx::Size& sizeHint,
@ -705,6 +764,9 @@ void Theme::calcWidgetMetrics(const Widget* widget,
sizeHint.h += std::max(textHint.h, iconHint.h); sizeHint.h += std::max(textHint.h, iconHint.h);
else else
sizeHint.h += textHint.h + iconHint.h; sizeHint.h += textHint.h + iconHint.h;
sizeHint.w = std::clamp(sizeHint.w, widget->minSize().w, widget->maxSize().w);
sizeHint.h = std::clamp(sizeHint.h, widget->minSize().h, widget->maxSize().h);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -16,6 +16,9 @@
#include "ui/base.h" #include "ui/base.h"
#include "ui/cursor_type.h" #include "ui/cursor_type.h"
#include "ui/style.h" #include "ui/style.h"
#include "ui/scale.h"
#define ADJUST_TO_GUISCALE(v) v -= (v % guiscale());
namespace gfx { namespace gfx {
class Region; class Region;
@ -43,6 +46,7 @@ namespace ui {
int styleFlags; // ui::Style::Layer flags int styleFlags; // ui::Style::Layer flags
const std::string* text; const std::string* text;
int mnemonic; int mnemonic;
os::Surface* icon;
PaintWidgetPartInfo(); PaintWidgetPartInfo();
PaintWidgetPartInfo(const Widget* widget); PaintWidgetPartInfo(const Widget* widget);
@ -119,6 +123,10 @@ namespace ui {
gfx::Rect& textBounds, int& textAlign); gfx::Rect& textBounds, int& textAlign);
virtual gfx::Color calcBgColor(const Widget* widget, virtual gfx::Color calcBgColor(const Widget* widget,
const Style* style); const Style* style);
virtual gfx::Size calcMinSize(const Widget* widget,
const Style* style);
virtual gfx::Size calcMaxSize(const Widget* widget,
const Style* style);
static void drawSlices(Graphics* g, static void drawSlices(Graphics* g,
os::Surface* sheet, os::Surface* sheet,
@ -141,6 +149,7 @@ namespace ui {
const Style::Layer& layer, const Style::Layer& layer,
const std::string& text, const std::string& text,
const int mnemonic, const int mnemonic,
os::Surface* icon,
gfx::Rect& rc, gfx::Rect& rc,
gfx::Color& bgColor); gfx::Color& bgColor);
void measureLayer(const Widget* widget, void measureLayer(const Widget* widget,

View File

@ -203,6 +203,8 @@ void Widget::setStyle(Style* style)
m_style = style; m_style = style;
m_border = m_theme->calcBorder(this, style); m_border = m_theme->calcBorder(this, style);
m_bgColor = m_theme->calcBgColor(this, style); m_bgColor = m_theme->calcBgColor(this, style);
m_minSize = m_theme->calcMinSize(this, style);
m_maxSize = m_theme->calcMaxSize(this, style);
if (style->font()) if (style->font())
m_font = AddRef(style->font()); m_font = AddRef(style->font());
} }
@ -966,15 +968,22 @@ void Widget::getTextIconInfo(
// Box position // Box position
if (align() & RIGHT) if (align() & RIGHT)
box_x = bounds.x2() - box_w - border().right(); box_x = bounds.x2() - box_w - border().right();
else if (align() & CENTER) else if (align() & CENTER) {
box_x = (bounds.x+bounds.x2())/2 - box_w/2; box_x = (bounds.x + bounds.x2() - box_w) / 2;
// Adjust position when it is not a multiple of guiscale. Without these adjustements
// it could happen that an icon or text is displayed a in a fraction of a scaled pixel.
ADJUST_TO_GUISCALE(box_x);
}
else else
box_x = bounds.x + border().left(); box_x = bounds.x + border().left();
if (align() & BOTTOM) if (align() & BOTTOM)
box_y = bounds.y2() - box_h - border().bottom(); box_y = bounds.y2() - box_h - border().bottom();
else if (align() & MIDDLE) else if (align() & MIDDLE) {
box_y = (bounds.y+bounds.y2())/2 - box_h/2; box_y = (bounds.y + bounds.y2() - box_h) / 2;
// Adjust position when it is not a multiple of guiscale
ADJUST_TO_GUISCALE(box_y);
}
else else
box_y = bounds.y + border().top(); box_y = bounds.y + border().top();
@ -986,8 +995,11 @@ void Widget::getTextIconInfo(
icon_x = box_x + box_w - icon_w; icon_x = box_x + box_w - icon_w;
} }
else if (icon_align & CENTER) { else if (icon_align & CENTER) {
text_x = box_x + box_w/2 - text_w/2; text_x = box_x + (box_w - text_w)/2;
icon_x = box_x + box_w/2 - icon_w/2; icon_x = box_x + (box_w - icon_w)/2;
// Adjust position when it is not a multiple of guiscale
ADJUST_TO_GUISCALE(text_x);
ADJUST_TO_GUISCALE(icon_x);
} }
else { else {
text_x = box_x + box_w - text_w; text_x = box_x + box_w - text_w;
@ -1000,8 +1012,11 @@ void Widget::getTextIconInfo(
icon_y = box_y + box_h - icon_h; icon_y = box_y + box_h - icon_h;
} }
else if (icon_align & MIDDLE) { else if (icon_align & MIDDLE) {
text_y = box_y + box_h/2 - text_h/2; text_y = box_y + (box_h - text_h)/2;
icon_y = box_y + box_h/2 - icon_h/2; icon_y = box_y + (box_h - icon_h)/2;
// Adjust position when it is not a multiple of guiscale
ADJUST_TO_GUISCALE(text_y);
ADJUST_TO_GUISCALE(icon_y);
} }
else { else {
text_y = box_y + box_h - text_h; text_y = box_y + box_h - text_h;

View File

@ -152,7 +152,7 @@ namespace ui {
Theme* theme() const { return m_theme; } Theme* theme() const { return m_theme; }
Style* style() const { return m_style; } Style* style() const { return m_style; }
void setTheme(Theme* theme); void setTheme(Theme* theme);
void setStyle(Style* style); virtual void setStyle(Style* style);
void initTheme(); void initTheme();
// =============================================================== // ===============================================================