Merge branch 'new-workspace'

Conflicts:
	src/app/commands/cmd_open_file.cpp

Fixes:
	src/app/ui/timeline.cpp
This commit is contained in:
David Capello 2015-03-04 22:41:34 -03:00
commit 361a3084fd
153 changed files with 3305 additions and 2106 deletions

View File

@ -89,9 +89,6 @@
<key command="InvertMask" shortcut="Ctrl+Shift+I" mac="Cmd+Shift+I" />
<!-- View -->
<key command="Refresh" shortcut="F5" />
<key command="MakeUniqueEditor" shortcut="Ctrl+1" mac="Cmd+1" />
<key command="SplitEditorVertically" shortcut="Ctrl+2" mac="Cmd+2" />
<key command="SplitEditorHorizontally" shortcut="Ctrl+3" mac="Cmd+3" />
<key command="TogglePreview" shortcut="F7" />
<key command="FullscreenPreview" shortcut="F8" />
<key command="ShowGrid" shortcut="Shift+G" />
@ -566,10 +563,6 @@
<item command="SaveMask" text="&amp;Save to MSK file" />
</menu>
<menu text="&amp;View">
<item command="MakeUniqueEditor" text="Make &amp;Unique" />
<item command="SplitEditorVertically" text="Split &amp;Vertically" />
<item command="SplitEditorHorizontally" text="Split &amp;Horizontally" />
<separator />
<item command="ShowPixelGrid" text="Show &amp;Pixel Grid" />
<item command="ShowGrid" text="Show &amp;Grid" />
<item command="SnapToGrid" text="&amp;Snap to Grid" />
@ -583,6 +576,7 @@
</item>
<item command="TogglePreview" text="Previe&amp;w" />
<item command="FullscreenPreview" text="&amp;Fullscreen Preview" />
<item command="Home" text="&amp;Home" />
<separator />
<item command="Refresh" text="&amp;Refresh &amp;&amp; Reload Skin" />
</menu>
@ -622,6 +616,10 @@
</menu>
</menu>
<menu id="tab_popup">
<item command="CloseFile" text="&amp;Close" />
</menu>
<menu id="document_tab_popup">
<item command="CloseFile" text="&amp;Close" />
<separator />

View File

@ -47,6 +47,7 @@
<global>
<section id="general">
<option id="visible_timeline" type="bool" default="false" />
<option id="autoshow_timeline" type="bool" default="true" migrate="Options.AutoShowTimeline" />
<option id="expand_menubar_on_mouseover" type="bool" default="false" migrate="Options.ExpandMenuBarOnMouseover" />
</section>
@ -71,6 +72,9 @@
<option id="use_native_file_dialog" type="bool" default="false" />
<option id="flash_layer" type="bool" default="false" migrate="Options.FlashLayer" />
</section>
<section id="news">
<option id="cache_file" type="std::string" />
</section>
</global>
<tool>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -3,6 +3,15 @@
author="Ilija Melentijevic &amp; David Capello"
url="http://ilkke.blogspot.com/">
<dimensions>
<dim id="tabs_width" value="80" />
<dim id="tabs_height" value="17" />
<dim id="tabs_empty_height" value="5" />
<dim id="tabs_close_icon_width" value="14" />
<dim id="tabs_close_icon_height" value="12" />
<dim id="tabs_icon_width" value="10" />
</dimensions>
<colors>
<color id="text" value="#000000" />
<color id="disabled" value="#968275" />
@ -15,7 +24,8 @@
<color id="textbox_text" value="#000000" />
<color id="textbox_face" value="#ffffff" />
<color id="entry_suffix" value="#c6c6c6" />
<color id="link_text" value="#0000ff" />
<color id="link_text" value="#2c4c91" />
<color id="link_hover" value="#ff5555" />
<color id="button_normal_text" value="#000000" />
<color id="button_normal_face" value="#c6c6c6" />
<color id="button_hot_text" value="#000000" />
@ -48,8 +58,8 @@
<color id="slider_full_face" value="#7d929e" />
<color id="tab_normal_text" value="#000000" />
<color id="tab_normal_face" value="#c6c6c6" />
<color id="tab_selected_text" value="#ffffff" />
<color id="tab_selected_face" value="#7d929e" />
<color id="tab_active_text" value="#ffffff" />
<color id="tab_active_face" value="#7d929e" />
<color id="splitter_normal_face" value="#7d929e" />
<color id="scrollbar_bg_face" value="#7d929e" />
<color id="scrollbar_thumb_face" value="#c6c6c6" />
@ -64,6 +74,9 @@
<color id="filelist_selected_row_face" value="#ff5555" />
<color id="filelist_disabled_row_text" value="#ffc8c8" />
<color id="workspace" value="#7d929e" />
<color id="workspace_text" value="#655561" />
<color id="workspace_link" value="#655561" />
<color id="workspace_link_hover" value="#ffff7d" />
<color id="timeline_normal" value="#c6c6c6" />
<color id="timeline_normal_text" value="#000000" />
<color id="timeline_hover" value="#d9d9d9" />
@ -214,12 +227,20 @@
<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="tab_normal" x="2" y="112" w1="4" w2="5" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_selected" x="16" y="112" w1="4" w2="7" w3="5" h1="4" h2="6" h3="2" />
<part id="tab_bottom_selected" x="16" y="124" w1="4" w2="7" w3="5" h1="2" h2="1" 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_normal" x="2" y="124" w="12" h="5" />
<part id="tab_filler" x="0" y="112" w="2" h="12" />
<part id="editor_normal" x="32" y="112" w1="3" w2="10" w3="3" h1="3" h2="10" h3="3" />
<part id="editor_selected" x="48" y="112" w1="3" w2="10" w3="3" h1="3" h2="10" h3="3" />
<part id="tab_modified_icon_normal" x="32" y="112" w="5" h="5" />
<part id="tab_modified_icon_active" x="32" y="117" w="5" h="5" />
<part id="tab_close_icon_normal" x="37" y="112" w="5" h="5" />
<part id="tab_close_icon_active" x="37" y="117" w="5" h="5" />
<part id="tab_icon_bg_clicked" x="42" y="112" w="14" h="12" />
<part id="tab_icon_bg_hover" x="56" y="112" w="14" h="12" />
<part id="tab_home_icon_normal" x="32" y="240" w="7" h="8" />
<part id="tab_home_icon_active" x="40" y="240" w="7" h="8" />
<part id="editor_normal" x="40" y="96" w1="3" w2="10" w3="3" h1="3" h2="10" h3="3" />
<part id="editor_selected" x="56" y="96" w1="3" w2="10" w3="3" h1="3" h2="10" h3="3" />
<part id="colorbar_0" x="0" y="192" w1="5" w2="6" w3="5" h1="5" h2="6" h3="5" />
<part id="colorbar_1" x="16" y="192" w1="5" w2="6" w3="5" h1="5" h2="6" h3="5" />
<part id="colorbar_2" x="0" y="208" w1="5" w2="6" w3="5" h1="5" h2="6" h3="5" />
@ -307,15 +328,15 @@
<part id="timeline_empty_frame_active" x="252" y="60" w="12" h="12" />
<part id="timeline_keyframe_normal" x="240" y="72" w="12" h="12" />
<part id="timeline_keyframe_active" x="252" y="72" w="12" h="12" />
<part id="timeline_fromleft_normal" x="240" y="84" w="12" h="12" />
<part id="timeline_fromleft_active" x="252" y="84" w="12" h="12" />
<part id="timeline_fromright_normal" x="240" y="96" w="12" h="12" />
<part id="timeline_fromright_active" x="252" y="96" w="12" h="12" />
<part id="timeline_fromboth_normal" x="240" y="108" w="12" h="12" />
<part id="timeline_fromboth_active" x="252" y="108" w="12" h="12" />
<part id="timeline_leftlink_active" x="264" y="84" w="12" h="12" />
<part id="timeline_bothlinks_active" x="264" y="96" w="12" h="12" />
<part id="timeline_rightlink_active" x="264" y="108" w="12" h="12" />
<part id="timeline_from_left_normal" x="240" y="84" w="12" h="12" />
<part id="timeline_from_left_active" x="252" y="84" w="12" h="12" />
<part id="timeline_from_right_normal" x="240" y="96" w="12" h="12" />
<part id="timeline_from_right_active" x="252" y="96" w="12" h="12" />
<part id="timeline_from_both_normal" x="240" y="108" w="12" h="12" />
<part id="timeline_from_both_active" x="252" y="108" w="12" h="12" />
<part id="timeline_left_link_active" x="264" y="84" w="12" h="12" />
<part id="timeline_both_links_active" x="264" y="96" w="12" h="12" />
<part id="timeline_right_link_active" x="264" y="108" w="12" h="12" />
<part id="timeline_gear" x="264" y="12" w="12" h="12" />
<part id="timeline_gear_active" x="264" y="24" w="12" h="12" />
<part id="timeline_onionskin" x="264" y="36" w="12" h="12" />
@ -355,6 +376,27 @@
<stylesheet>
<!-- label -->
<style id="label">
<text color="text" />
</style>
<!-- link -->
<style id="link">
<text color="link_text" />
</style>
<style id="link:hover">
<text color="link_hover" />
</style>
<!-- view -->
<style id="view">
<background part="sunken_normal" />
</style>
<style id="view:active">
<background part="sunken_focused" />
</style>
<!-- window -->
<style id="window">
<background color="window_face" part="window" />
@ -485,35 +527,35 @@
<icon part="timeline_keyframe_active" />
</style>
<style id="timeline_fromleft">
<icon part="timeline_fromleft_normal" />
<style id="timeline_from_left">
<icon part="timeline_from_left_normal" />
</style>
<style id="timeline_fromleft:active">
<icon part="timeline_fromleft_active" />
<style id="timeline_from_left:active">
<icon part="timeline_from_left_active" />
</style>
<style id="timeline_fromright">
<icon part="timeline_fromright_normal" />
<style id="timeline_from_right">
<icon part="timeline_from_right_normal" />
</style>
<style id="timeline_fromright:active">
<icon part="timeline_fromright_active" />
<style id="timeline_from_right:active">
<icon part="timeline_from_right_active" />
</style>
<style id="timeline_fromboth">
<icon part="timeline_fromboth_normal" />
<style id="timeline_from_both">
<icon part="timeline_from_both_normal" />
</style>
<style id="timeline_fromboth:active">
<icon part="timeline_fromboth_active" />
<style id="timeline_from_both:active">
<icon part="timeline_from_both_active" />
</style>
<style id="timeline_leftlink">
<icon part="timeline_leftlink_active" />
<style id="timeline_left_link">
<icon part="timeline_left_link_active" />
</style>
<style id="timeline_rightlink">
<icon part="timeline_rightlink_active" />
<style id="timeline_right_link">
<icon part="timeline_right_link_active" />
</style>
<style id="timeline_bothlinks">
<icon part="timeline_bothlinks_active" />
<style id="timeline_both_links">
<icon part="timeline_both_links_active" />
</style>
<!-- timeline_gear -->
@ -602,6 +644,156 @@
<background color="hot_face" />
</style>
<!-- tab -->
<style id="tab">
<background part="tab_normal" color="tab_normal_face" repeat="repeat-x" />
<text color="tab_normal_text" align="left" valign="middle" padding-left="4" padding-top="2" />
</style>
<style id="tab:active">
<background part="tab_active" color="tab_active_face" />
<text color="tab_active_text" />
</style>
<!-- tab_text -->
<style id="tab_text">
<text color="tab_normal_text" align="left" valign="middle" padding-left="4" padding-top="2" />
</style>
<style id="tab_text:active">
<text color="tab_active_text" />
</style>
<!-- tab_bottom -->
<style id="tab_bottom">
<background part="tab_bottom_normal" color="tab_normal_face" repeat="repeat-x" />
</style>
<style id="tab_bottom:active">
<background part="tab_bottom_active" color="tab_active_face" />
</style>
<!-- tab_filler -->
<style id="tab_filler">
<background part="tab_filler" color="window_face" repeat="repeat-x" />
</style>
<!-- tab_icon -->
<style id="tab_icon">
<icon align="left" valign="middle" x="3" />
</style>
<style id="tab_icon:hover">
<background part="tab_icon_bg_hover" />
</style>
<style id="tab_icon:clicked">
<background part="tab_icon_bg_clicked" />
</style>
<!-- tab_close_icon -->
<style id="tab_close_icon" base="tab_icon">
<icon part="tab_close_icon_normal" />
</style>
<style id="tab_close_icon:hover">
<icon part="tab_close_icon_normal" />
</style>
<style id="tab_close_icon:active">
<icon part="tab_close_icon_active" />
</style>
<style id="tab_close_icon:clicked">
<icon part="tab_close_icon_normal" />
</style>
<!-- tab_modified_icon -->
<style id="tab_modified_icon" base="tab_icon">
<icon part="tab_modified_icon_normal" />
</style>
<style id="tab_modified_icon:hover">
<icon part="tab_modified_icon_normal" />
</style>
<style id="tab_modified_icon:active">
<icon part="tab_modified_icon_active" />
</style>
<style id="tab_modified_icon:clicked">
<icon part="tab_modified_icon_normal" />
</style>
<!-- tab_home -->
<style id="tab_home">
<icon part="tab_home_icon_normal" align="left" valign="middle" x="4" y="1" />
</style>
<style id="tab_home:active">
<icon part="tab_home_icon_active" />
</style>
<!-- workspace_label -->
<style id="workspace_label">
<text color="workspace_text" />
</style>
<!-- workspace_link -->
<style id="workspace_link">
<text color="workspace_link" valign="middle" />
</style>
<style id="workspace_link:hover">
<text color="workspace_link_hover" />
</style>
<!-- workspace_link -->
<style id="workspace_update_link" base="workspace_link">
<background part="button_normal" color="button_normal_face" />
<icon part="warning_box" align="right" x="-4" y="4" />
<text padding-left="4" />
</style>
<style id="workspace_update_link:hover">
<background part="button_hot" color="button_hot_face" />
<text color="button_hot_text" />
</style>
<style id="workspace_update_link:clicked">
<background part="button_selected" color="button_selected_face" />
<text color="button_selected_text" />
</style>
<!-- workspace_view -->
<style id="workspace_view">
<background part="editor_normal" />
</style>
<style id="workspace_view:active">
<background part="editor_selected" />
</style>
<!-- recent_file -->
<style id="recent_file">
<background color="background" />
<text color="text" valign="middle" padding-left="2" padding-right="2" padding-top="3" padding-bottom="1" />
</style>
<style id="recent_file:hover">
<background color="menuitem_hot_face" />
</style>
<style id="recent_file:active">
<background color="listitem_selected_face" />
<text color="listitem_selected_text" />
</style>
<!-- recent_file_detail -->
<style id="recent_file_detail" base="recent_file">
<text color="disabled" valign="top" wordwrap="true" />
</style>
<!-- news_item -->
<style id="news_item">
<background color="background" />
<text color="text" valign="middle" padding-left="2" padding-right="2" padding-top="3" padding-bottom="3" />
</style>
<style id="news_item:hover">
<background color="menuitem_hot_face" />
</style>
<style id="news_item:active">
<background color="listitem_selected_face" />
<text color="listitem_selected_text" />
</style>
<!-- news_item_detail -->
<style id="news_item_detail" base="news_item">
<text color="disabled" valign="top" wordwrap="true" padding-top="0" padding-bottom="0" />
</style>
</stylesheet>
</skin>

View File

@ -0,0 +1,29 @@
<!-- Aseprite -->
<!-- Copyright (C) 2001-2015 by David Capello -->
<gui>
<vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true">
<hbox noborders="true">
<image file="icons/ase48.png" align="center" />
<vbox border="4" childspacing="4">
<link id="new_file" text="New File..." style="workspace_link" />
<link id="open_file" text="Open File..." style="workspace_link" />
</vbox>
<boxfiller />
<vbox border="4">
<link id="check_update" text="" style="workspace_link" />
</vbox>
</hbox>
<hbox noborders="true" expansive="true" homogeneous="true" childspacing="2">
<vbox noborders="true" childspacing="2">
<label text="Recent files:" style="workspace_label" />
<view id="files_view" expansive="true" style="workspace_view" />
<label text="Recent folders:" style="workspace_label" />
<view id="folders_view" expansive="true" style="workspace_view" />
</vbox>
<vbox noborders="true" childspacing="2">
<label text="News:" style="workspace_label" />
<view id="news_view" expansive="true" style="workspace_view" />
</vbox>
</hbox>
</vbox>
</gui>

View File

@ -1,26 +1,28 @@
<!-- Aseprite -->
<!-- Copyright (C) 2001-2014 by David Capello -->
<!-- Copyright (C) 2001-2015 by David Capello -->
<gui>
<vbox noborders="true" id="main_box">
<hbox noborders="true" id="menubar" />
<hbox noborders="true" id="tabsbar" />
<splitter id="colorbarsplitter"
horizontal="true" expansive="true"
by="pixel">
<vbox noborders="true" id="colorbar" />
<vbox noborders="true" expansive="true">
<vbox noborders="true" id="contextbar" />
<hbox noborders="true" expansive="true">
<splitter id="timelinesplitter"
vertical="true" expansive="true"
by="percetage" position="100">
<hbox noborders="true" id="workspace" expansive="true" />
<vbox noborders="true" id="timeline" expansive="true" />
</splitter>
<vbox noborders="true" id="toolbar" />
</hbox>
</vbox>
</splitter>
<hbox noborders="true" id="statusbar" />
</vbox>
<window id="main_window" noborders="true" desktop="true">
<vbox noborders="true" expansive="true">
<hbox noborders="true" id="menu_bar_placeholder" />
<hbox noborders="true" id="tabs_placeholder" />
<splitter id="color_bar_splitter"
horizontal="true" expansive="true"
by="pixel">
<vbox noborders="true" id="color_bar_placeholder" />
<vbox noborders="true" expansive="true">
<vbox noborders="true" id="context_bar_placeholder" />
<hbox noborders="true" expansive="true">
<splitter id="timeline_splitter"
vertical="true" expansive="true"
by="percetage" position="100">
<hbox noborders="true" id="workspace_placeholder" expansive="true" />
<vbox noborders="true" id="timeline_placeholder" expansive="true" />
</splitter>
<vbox noborders="true" id="tool_bar_placeholder" />
</hbox>
</vbox>
</splitter>
<hbox noborders="true" id="status_bar_placeholder" />
</vbox>
</window>
</gui>

View File

@ -47,7 +47,7 @@ AL_FUNC(void, register_trace_handler, (AL_METHOD(int, handler, (AL_CONST char *m
#ifndef TRACE
#define TRACE 1 ? (void) 0 : al_trace
#endif TRACE
#endif
#endif
#ifdef __cplusplus

View File

@ -1,9 +1,7 @@
# Aseprite
# Copyright (C) 2001-2015 David Capello
######################################################################
# Generate source files from widget XML files
# Generate a ui::Widget for each widget in a XML file
file(GLOB widget_files ${CMAKE_SOURCE_DIR}/data/widgets/*.xml)
foreach(widget_file ${widget_files})
get_filename_component(widget_name ${widget_file} NAME_WE)
@ -19,7 +17,7 @@ foreach(widget_file ${widget_files})
list(APPEND generated_files ${output_fn})
endforeach()
# pref.h and pref.cpp
# Generate preference types from data/pref.xml
set(pref_xml ${CMAKE_SOURCE_DIR}/data/pref.xml)
set(output_fn ${CMAKE_CURRENT_BINARY_DIR}/generated_pref_types.h)
@ -40,6 +38,17 @@ add_custom_command(
DEPENDS gen)
list(APPEND generated_files ${output_fn})
# Generate generated_skin.h from data/skins/default/skin.xml
set(skin_xml ${CMAKE_SOURCE_DIR}/data/skins/default/skin.xml)
set(output_fn ${CMAKE_CURRENT_BINARY_DIR}/generated_skin.h)
add_custom_command(
OUTPUT ${output_fn}
COMMAND ${CMAKE_BINARY_DIR}/bin/gen --input ${skin_xml} --skin > ${output_fn}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
MAIN_DEPENDENCY ${skin_xml}
DEPENDS gen)
list(APPEND generated_files ${output_fn})
# Directory where generated files by "gen" utility will stay.
include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -148,6 +157,7 @@ add_library(app-lib
commands/cmd_goto_layer.cpp
commands/cmd_goto_tab.cpp
commands/cmd_grid.cpp
commands/cmd_home.cpp
commands/cmd_import_sprite_sheet.cpp
commands/cmd_invert_mask.cpp
commands/cmd_keyboard_shortcuts.cpp
@ -190,7 +200,6 @@ add_library(app-lib
commands/cmd_scroll.cpp
commands/cmd_set_loop_section.cpp
commands/cmd_set_palette.cpp
commands/cmd_sprite_editor.cpp
commands/cmd_sprite_properties.cpp
commands/cmd_sprite_size.cpp
commands/cmd_switch_colors.cpp
@ -257,6 +266,7 @@ add_library(app-lib
pref/preferences.cpp
project.cpp
recent_files.cpp
res/http_loader.cpp
res/palettes_loader_delegate.cpp
res/resources_loader.cpp
resource_finder.cpp
@ -303,32 +313,34 @@ add_library(app-lib
ui/file_list.cpp
ui/file_selector.cpp
ui/hex_color_entry.cpp
ui/home_view.cpp
ui/keyboard_shortcuts.cpp
ui/main_menu_bar.cpp
ui/main_window.cpp
ui/news_listbox.cpp
ui/notifications.cpp
ui/palette_popup.cpp
ui/palette_view.cpp
ui/palettes_listbox.cpp
ui/popup_window_pin.cpp
ui/preview_editor.cpp
ui/recent_listbox.cpp
ui/resources_listbox.cpp
ui/select_accelerator.cpp
ui/skin/button_icon_impl.cpp
ui/skin/skin_part.cpp
ui/skin/skin_property.cpp
ui/skin/skin_slider_property.cpp
ui/skin/skin_style_property.cpp
ui/skin/skin_theme.cpp
ui/skin/style.cpp
ui/skin/style_sheet.cpp
ui/start_view.cpp
ui/status_bar.cpp
ui/styled_button.cpp
ui/tabs.cpp
ui/timeline.cpp
ui/toolbar.cpp
ui/workspace.cpp
ui/workspace_part.cpp
ui_context.cpp
util/autocrop.cpp
util/boundary.cpp

View File

@ -451,7 +451,8 @@ void App::run()
if (isGui()) {
#ifdef ENABLE_UPDATER
// Launch the thread to check for updates.
app::CheckUpdateThreadLauncher checkUpdate;
app::CheckUpdateThreadLauncher checkUpdate(
m_mainWindow->getCheckUpdateDelegate());
checkUpdate.launch();
#endif
@ -617,7 +618,7 @@ void app_refresh_screen()
void app_rebuild_documents_tabs()
{
if (App::instance()->isGui())
App::instance()->getMainWindow()->getTabsBar()->updateTabsText();
App::instance()->getMainWindow()->getTabsBar()->updateTabs();
}
PixelFormat app_get_current_pixel_format()

View File

@ -57,6 +57,9 @@ AppMenus* AppMenus::instance()
AppMenus::AppMenus()
: m_recentListMenuitem(NULL)
{
m_recentFilesConn =
App::instance()->getRecentFiles()->Changed.connect(
Bind(&AppMenus::rebuildRecentList, this));
}
void AppMenus::reload()
@ -78,6 +81,7 @@ void AppMenus::reload()
PRINTF("Main menu loaded.\n");
m_tabPopupMenu.reset(loadMenuById(handle, "tab_popup"));
m_documentTabPopupMenu.reset(loadMenuById(handle, "document_tab_popup"));
m_layerPopupMenu.reset(loadMenuById(handle, "layer_popup"));
m_framePopupMenu.reset(loadMenuById(handle, "frame_popup"));

View File

@ -39,6 +39,7 @@ namespace app {
Menu* getRootMenu() { return m_rootMenu; }
MenuItem* getRecentListMenuitem() { return m_recentListMenuitem; }
Menu* getTabPopupMenu() { return m_tabPopupMenu; }
Menu* getDocumentTabPopupMenu() { return m_documentTabPopupMenu; }
Menu* getLayerPopupMenu() { return m_layerPopupMenu; }
Menu* getFramePopupMenu() { return m_framePopupMenu; }
@ -56,11 +57,13 @@ namespace app {
base::UniquePtr<Menu> m_rootMenu;
MenuItem* m_recentListMenuitem;
base::UniquePtr<Menu> m_tabPopupMenu;
base::UniquePtr<Menu> m_documentTabPopupMenu;
base::UniquePtr<Menu> m_layerPopupMenu;
base::UniquePtr<Menu> m_framePopupMenu;
base::UniquePtr<Menu> m_celPopupMenu;
base::UniquePtr<Menu> m_celMovementPopupMenu;
ScopedConnection m_recentFilesConn;
};
} // namespace app

View File

@ -13,9 +13,10 @@
#include "app/check_update.h"
#include "app/app.h"
#include "app/check_update_delegate.h"
#include "app/ini_file.h"
#include "base/bind.h"
#include "base/convert_to.h"
#include "base/launcher.h"
#include <ctime>
@ -74,8 +75,9 @@ private:
updater::CheckUpdateResponse m_response;
};
CheckUpdateThreadLauncher::CheckUpdateThreadLauncher()
: m_doCheck(true)
CheckUpdateThreadLauncher::CheckUpdateThreadLauncher(CheckUpdateDelegate* delegate)
: m_delegate(delegate)
, m_doCheck(true)
, m_received(false)
, m_inits(get_config_int("Updater", "Inits", 0))
, m_exits(get_config_int("Updater", "Exits", 0))
@ -87,14 +89,14 @@ CheckUpdateThreadLauncher::CheckUpdateThreadLauncher()
, m_timer(kMonitoringPeriod, NULL)
{
// Get how many days we have to wait for the next "check for update"
int waitDays = get_config_int("Updater", "WaitDays", 0);
if (waitDays > 0) {
double waitDays = get_config_double("Updater", "WaitDays", 0.0);
if (waitDays > 0.0) {
// Get the date of the last "check for updates"
time_t lastCheck = (time_t)get_config_int("Updater", "LastCheck", 0);
time_t now = std::time(NULL);
// Verify if we are in the "WaitDays" period...
if (now < lastCheck+60*60*24*waitDays &&
if (now < lastCheck+int(double(60*60*24*waitDays)) &&
now > lastCheck) { // <- Avoid broken clocks
// So we do not check for updates.
m_doCheck = false;
@ -133,6 +135,8 @@ void CheckUpdateThreadLauncher::launch()
if (m_uuid.empty())
m_uuid = get_config_string("Updater", "Uuid", "");
m_delegate->onCheckingUpdates();
m_bgJob.reset(new CheckUpdateBackgroundJob);
m_thread.reset(new base::thread(Bind<void>(&CheckUpdateThreadLauncher::checkForUpdates, this)));
@ -158,12 +162,14 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
switch (m_response.getUpdateType()) {
case updater::CheckUpdateResponse::NoUpdate:
// Nothing to do, we are up-to-date
m_delegate->onUpToDate();
break;
case updater::CheckUpdateResponse::Critical:
case updater::CheckUpdateResponse::Major:
App::instance()->showNotification(this);
m_delegate->onNewUpdate(
m_response.getUrl(),
base::convert_to<std::string>(m_response.getLatestVersion()));
break;
}
@ -175,7 +181,7 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
// Set the date of the last "check for updates" and the "WaitDays" parameter.
set_config_int("Updater", "LastCheck", (int)std::time(NULL));
set_config_int("Updater", "WaitDays", m_response.getWaitDays());
set_config_double("Updater", "WaitDays", m_response.getWaitDays());
// Save the config file right now
flush_config_file();
@ -204,17 +210,6 @@ void CheckUpdateThreadLauncher::checkForUpdates()
}
}
std::string CheckUpdateThreadLauncher::notificationText()
{
return "New Version Available!";
}
void CheckUpdateThreadLauncher::notificationClick()
{
if (!m_response.getUrl().empty())
base::launcher::open_url(m_response.getUrl());
}
}
#endif // ENABLE_UPDATER

View File

@ -11,7 +11,6 @@
#ifdef ENABLE_UPDATER
#include "app/notification_delegate.h"
#include "base/thread.h"
#include "base/unique_ptr.h"
#include "ui/timer.h"
@ -19,11 +18,12 @@
namespace app {
class CheckUpdateDelegate;
class CheckUpdateBackgroundJob;
class CheckUpdateThreadLauncher : public INotificationDelegate {
class CheckUpdateThreadLauncher {
public:
CheckUpdateThreadLauncher();
CheckUpdateThreadLauncher(CheckUpdateDelegate* delegate);
~CheckUpdateThreadLauncher();
void launch();
@ -35,13 +35,11 @@ namespace app {
return m_response;
}
virtual std::string notificationText() override;
virtual void notificationClick() override;
private:
void onMonitoringTick();
void checkForUpdates();
CheckUpdateDelegate* m_delegate;
updater::Uuid m_uuid;
base::UniquePtr<base::thread> m_thread;
base::UniquePtr<CheckUpdateBackgroundJob> m_bgJob;

View File

@ -0,0 +1,30 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_CHECK_UPDATE_DELEGATE_H_INCLUDED
#define APP_CHECK_UPDATE_DELEGATE_H_INCLUDED
#pragma once
#ifdef ENABLE_UPDATER
#include <string>
namespace app {
class CheckUpdateDelegate {
public:
virtual ~CheckUpdateDelegate() { }
virtual void onCheckingUpdates() = 0;
virtual void onUpToDate() = 0;
virtual void onNewUpdate(const std::string& url, const std::string& version) = 0;
};
} // namespace app
#endif // ENABLE_UPDATER
#endif // APP_CHECK_UPDATE_DELEGATE_H_INCLUDED

View File

@ -29,53 +29,30 @@ namespace app {
using namespace ui;
static bool close_active_document(Context* context);
class CloseFileCommand : public Command {
public:
CloseFileCommand()
: Command("CloseFile",
"Close File",
CmdUIOnlyFlag)
{
CmdUIOnlyFlag) {
}
Command* clone() const override { return new CloseFileCommand(*this); }
protected:
bool onEnabled(Context* context)
{
const ContextReader reader(context);
const Sprite* sprite(reader.sprite());
return sprite != NULL;
}
void onExecute(Context* context)
{
bool onEnabled(Context* context) override {
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
if (workspace->activeView() == NULL)
return;
if (DocumentView* docView =
dynamic_cast<DocumentView*>(workspace->activeView())) {
Document* document = docView->getDocument();
if (static_cast<UIContext*>(context)->countViewsOf(document) == 1) {
// If we have only one view for this document, close the file.
close_active_document(context);
return;
}
}
// Close the active view.
WorkspaceView* view = workspace->activeView();
workspace->removeView(view);
delete view;
return (view != nullptr);
}
private:
static char* read_authors_txt(const char *filename);
void onExecute(Context* context) override {
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
WorkspaceView* view = workspace->activeView();
if (view)
workspace->closeView(view);
}
};
class CloseAllFilesCommand : public Command {
@ -83,96 +60,31 @@ public:
CloseAllFilesCommand()
: Command("CloseAllFiles",
"Close All Files",
CmdRecordableFlag)
{
CmdRecordableFlag) {
}
Command* clone() const override { return new CloseAllFilesCommand(*this); }
protected:
bool onEnabled(Context* context)
{
return !context->documents().empty();
}
void onExecute(Context* context) override {
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
void onExecute(Context* context)
{
while (true) {
if (context->activeDocument() != NULL) {
if (!close_active_document(context))
break;
}
else
std::vector<DocumentView*> docViews;
for (auto view : *workspace) {
DocumentView* docView = dynamic_cast<DocumentView*>(view);
if (docView)
docViews.push_back(docView);
}
for (auto docView : docViews) {
if (!workspace->closeView(docView))
break;
}
}
};
// Closes the active document, asking to the user to save it if it is
// modified.
static bool close_active_document(Context* context)
{
Document* closedDocument = NULL;
bool save_it;
bool try_again = true;
while (try_again) {
// This flag indicates if we have to sabe the sprite before to destroy it
save_it = false;
{
// The sprite is locked as reader temporaly
const ContextReader reader(context);
const Document* document = reader.document();
closedDocument = const_cast<Document*>(document);
// see if the sprite has changes
while (document->isModified()) {
// ask what want to do the user with the changes in the sprite
int ret = Alert::show("Warning<<Saving changes in:<<%s||&Save||Do&n't Save||&Cancel",
document->name().c_str());
if (ret == 1) {
// "save": save the changes
save_it = true;
break;
}
else if (ret != 2) {
// "cancel" or "ESC" */
return false; // we back doing nothing
}
else {
// "discard"
break;
}
}
}
// Does we need to save the sprite?
if (save_it) {
Command* save_command =
CommandsModule::instance()->getCommandByName(CommandId::SaveFile);
context->executeCommand(save_command);
try_again = true;
}
else
try_again = false;
}
// Destroy the sprite (locking it as writer)
{
DocumentDestroyer document(context, closedDocument);
StatusBar::instance()
->setStatusText(0, "Sprite '%s' closed.",
document->name().c_str());
document.destroyDocument();
}
return true;
}
Command* CommandFactory::createCloseFileCommand()
{
return new CloseFileCommand;

View File

@ -11,15 +11,7 @@
#include "app/app.h"
#include "app/commands/command.h"
#include "app/context.h"
#include "app/document.h"
#include "app/ui/devconsole_view.h"
#include "app/ui/main_window.h"
#include "app/ui/workspace.h"
#include "ui/box.h"
#include "ui/button.h"
#include "ui/combobox.h"
#include "ui/window.h"
namespace app {
@ -32,8 +24,6 @@ public:
protected:
void onExecute(Context* context);
DevConsoleView* m_devConsole;
};
DeveloperConsoleCommand::DeveloperConsoleCommand()
@ -41,24 +31,15 @@ DeveloperConsoleCommand::DeveloperConsoleCommand()
"Developer Console",
CmdUIOnlyFlag)
{
m_devConsole = NULL;
}
DeveloperConsoleCommand::~DeveloperConsoleCommand()
{
delete m_devConsole;
}
void DeveloperConsoleCommand::onExecute(Context* context)
{
if (!m_devConsole) {
m_devConsole = new DevConsoleView();
App::instance()->getMainWindow()->getWorkspace()->addView(m_devConsole);
}
App::instance()->getMainWindow()->getTabsBar()->selectTab(m_devConsole);
App::instance()->getMainWindow()->getWorkspace()->setActiveView(m_devConsole);
App::instance()->getMainWindow()->showDevConsole();
}
Command* CommandFactory::createDeveloperConsoleCommand()

View File

@ -63,7 +63,7 @@ namespace {
int nframes = sprite->totalFrames();
int framew = sprite->width();
int frameh = sprite->height();
Fit result(framew*nframes, frameh, nframes, INT_MAX);
Fit result(framew*nframes, frameh, nframes, std::numeric_limits<int>::max());
int w, h;
for (w=2; w < framew; w*=2)

View File

@ -31,6 +31,8 @@
#include "she/surface.h"
#include "she/system.h"
#include <cstring>
#define PREVIEW_TILED 1
#define PREVIEW_FIT_ON_SCREEN 2
@ -120,10 +122,10 @@ protected:
// Change frame
if (command != NULL &&
(strcmp(command->short_name(), CommandId::GotoFirstFrame) == 0 ||
strcmp(command->short_name(), CommandId::GotoPreviousFrame) == 0 ||
strcmp(command->short_name(), CommandId::GotoNextFrame) == 0 ||
strcmp(command->short_name(), CommandId::GotoLastFrame) == 0)) {
(std::strcmp(command->short_name(), CommandId::GotoFirstFrame) == 0 ||
std::strcmp(command->short_name(), CommandId::GotoPreviousFrame) == 0 ||
std::strcmp(command->short_name(), CommandId::GotoNextFrame) == 0 ||
std::strcmp(command->short_name(), CommandId::GotoLastFrame) == 0)) {
m_context->executeCommand(command);
invalidate();
m_render.reset(NULL); // Re-render
@ -131,7 +133,7 @@ protected:
#if 0
// Play the animation
else if (command != NULL &&
strcmp(command->short_name(), CommandId::PlayAnimation) == 0) {
std::strcmp(command->short_name(), CommandId::PlayAnimation) == 0) {
// TODO
}
#endif

View File

@ -0,0 +1,50 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/app.h"
#include "app/commands/command.h"
#include "app/ui/main_window.h"
namespace app {
using namespace ui;
class HomeCommand : public Command {
public:
HomeCommand();
~HomeCommand();
protected:
void onExecute(Context* context);
};
HomeCommand::HomeCommand()
: Command("Home",
"Home",
CmdUIOnlyFlag)
{
}
HomeCommand::~HomeCommand()
{
}
void HomeCommand::onExecute(Context* context)
{
App::instance()->getMainWindow()->showHome();
}
Command* CommandFactory::createHomeCommand()
{
return new HomeCommand;
}
} // namespace app

View File

@ -140,12 +140,12 @@ private:
gfx::Color fg, bg;
if (isSelected()) {
fg = theme->getColor(ThemeColor::ListItemSelectedText);
bg = theme->getColor(ThemeColor::ListItemSelectedFace);
fg = theme->colors.listitemSelectedText();
bg = theme->colors.listitemSelectedFace();
}
else {
fg = theme->getColor(ThemeColor::ListItemNormalText);
bg = theme->getColor(ThemeColor::ListItemNormalFace);
fg = theme->colors.listitemNormalText();
bg = theme->colors.listitemNormalFace();
}
g->fillRect(bg, bounds);

View File

@ -17,14 +17,15 @@
#include "app/find_widget.h"
#include "app/load_widget.h"
#include "app/modules/gui.h"
#include "app/transaction.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "app/transaction.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "ui/ui.h"
#include <cstdio>
#include <cstring>
namespace app {
@ -126,8 +127,8 @@ static int get_max_layer_num(Layer* layer)
{
int max = 0;
if (strncmp(layer->name().c_str(), "Layer ", 6) == 0)
max = strtol(layer->name().c_str()+6, NULL, 10);
if (std::strncmp(layer->name().c_str(), "Layer ", 6) == 0)
max = std::strtol(layer->name().c_str()+6, NULL, 10);
if (layer->isFolder()) {
LayerIterator it = static_cast<LayerFolder*>(layer)->getLayerBegin();

View File

@ -23,6 +23,7 @@
#include "app/ui/status_bar.h"
#include "app/ui_context.h"
#include "base/bind.h"
#include "base/path.h"
#include "base/thread.h"
#include "base/unique_ptr.h"
#include "doc/sprite.h"
@ -43,6 +44,7 @@ protected:
private:
std::string m_filename;
std::string m_folder;
};
class OpenFileJob : public Job, public IFileOpProgress
@ -93,12 +95,12 @@ OpenFileCommand::OpenFileCommand()
"Open Sprite",
CmdRecordableFlag)
{
m_filename = "";
}
void OpenFileCommand::onLoadParams(Params* params)
{
m_filename = params->get("filename");
m_folder = params->get("folder"); // Initial folder
}
void OpenFileCommand::onExecute(Context* context)
@ -109,7 +111,13 @@ void OpenFileCommand::onExecute(Context* context)
if (context->isUiAvailable() && m_filename.empty()) {
char exts[4096];
get_readable_extensions(exts, sizeof(exts));
m_filename = app::show_file_selector("Open", "", exts,
// Add backslash as show_file_selector() expected a filename as
// initial path (and the file part is removed from the path).
if (!m_folder.empty() && !base::is_path_separator(m_folder[m_folder.size()-1]))
m_folder.push_back(base::path_separator);
m_filename = app::show_file_selector("Open", m_folder, exts,
FileSelectorType::Open);
}

View File

@ -198,7 +198,7 @@ public:
private:
void onChangeSection() {
ListItem* item = sectionListbox()->getSelectedChild();
ListItem* item = static_cast<ListItem*>(sectionListbox()->getSelectedChild());
if (!item)
return;

View File

@ -1,104 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/app.h"
#include "app/commands/command.h"
#include "app/ui/main_window.h"
#include "app/ui/workspace.h"
#include "ui/base.h"
namespace app {
class MakeUniqueEditorCommand : public Command {
public:
MakeUniqueEditorCommand();
Command* clone() const override { return new MakeUniqueEditorCommand(*this); }
protected:
void onExecute(Context* context);
};
MakeUniqueEditorCommand::MakeUniqueEditorCommand()
: Command("MakeUniqueEditor",
"Make Unique Editor",
CmdUIOnlyFlag)
{
}
void MakeUniqueEditorCommand::onExecute(Context* context)
{
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
if (workspace->activeView() != NULL)
workspace->makeUnique(workspace->activeView());
}
class SplitEditorHorizontallyCommand : public Command {
public:
SplitEditorHorizontallyCommand();
Command* clone() const override { return new SplitEditorHorizontallyCommand(*this); }
protected:
void onExecute(Context* context);
};
SplitEditorHorizontallyCommand::SplitEditorHorizontallyCommand()
: Command("SplitEditorHorizontally",
"Split Editor Horizontally",
CmdUIOnlyFlag)
{
}
void SplitEditorHorizontallyCommand::onExecute(Context* context)
{
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
if (workspace->activeView() != NULL)
workspace->splitView(workspace->activeView(), JI_HORIZONTAL);
}
class SplitEditorVerticallyCommand : public Command {
public:
SplitEditorVerticallyCommand();
Command* clone() const override { return new SplitEditorVerticallyCommand(*this); }
protected:
void onExecute(Context* context);
};
SplitEditorVerticallyCommand::SplitEditorVerticallyCommand()
: Command("SplitEditorVertically",
"Split Editor Vertically",
CmdUIOnlyFlag)
{
}
void SplitEditorVerticallyCommand::onExecute(Context* context)
{
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
if (workspace->activeView() != NULL)
workspace->splitView(workspace->activeView(), JI_VERTICAL);
}
Command* CommandFactory::createMakeUniqueEditorCommand()
{
return new MakeUniqueEditorCommand;
}
Command* CommandFactory::createSplitEditorHorizontallyCommand()
{
return new SplitEditorHorizontallyCommand;
}
Command* CommandFactory::createSplitEditorVerticallyCommand()
{
return new SplitEditorVerticallyCommand;
}
} // namespace app

View File

@ -49,6 +49,7 @@ FOR_EACH_COMMAND(GotoPreviousFrame)
FOR_EACH_COMMAND(GotoPreviousLayer)
FOR_EACH_COMMAND(GotoPreviousTab)
FOR_EACH_COMMAND(GridSettings)
FOR_EACH_COMMAND(Home)
FOR_EACH_COMMAND(ImportSpriteSheet)
FOR_EACH_COMMAND(InvertColor)
FOR_EACH_COMMAND(InvertMask)
@ -59,7 +60,6 @@ FOR_EACH_COMMAND(LayerProperties)
FOR_EACH_COMMAND(LayerVisibility)
FOR_EACH_COMMAND(LoadMask)
FOR_EACH_COMMAND(LoadPalette)
FOR_EACH_COMMAND(MakeUniqueEditor)
FOR_EACH_COMMAND(MaskAll)
FOR_EACH_COMMAND(MaskByColor)
FOR_EACH_COMMAND(MaskContent)
@ -100,8 +100,6 @@ FOR_EACH_COMMAND(ShowGrid)
FOR_EACH_COMMAND(ShowOnionSkin)
FOR_EACH_COMMAND(ShowPixelGrid)
FOR_EACH_COMMAND(SnapToGrid)
FOR_EACH_COMMAND(SplitEditorHorizontally)
FOR_EACH_COMMAND(SplitEditorVertically)
FOR_EACH_COMMAND(SpriteProperties)
FOR_EACH_COMMAND(SpriteSize)
FOR_EACH_COMMAND(SwitchColors)

View File

@ -124,7 +124,7 @@ private:
void onMatrixChange()
{
ListItem* selected = m_stockListBox->getSelectedChild();
Widget* selected = m_stockListBox->getSelectedChild();
SharedPtr<ConvolutionMatrix> matrix = m_stock.getByName(selected->getText().c_str());
Target newTarget = matrix->getDefaultTarget();

View File

@ -11,7 +11,6 @@
#include "app/recent_files.h"
#include "app/app_menus.h"
#include "app/ini_file.h"
#include "base/fs.h"
#include "base/path.h"
@ -90,7 +89,7 @@ void RecentFiles::addRecentFile(const char* filename)
m_files.addItem(filename);
m_paths.addItem(base::get_file_path(filename));
AppMenus::instance()->rebuildRecentList();
Changed();
}
void RecentFiles::removeRecentFile(const char* filename)
@ -98,7 +97,7 @@ void RecentFiles::removeRecentFile(const char* filename)
m_files.removeItem(filename);
m_paths.removeItem(base::get_file_path(filename));
AppMenus::instance()->rebuildRecentList();
Changed();
}
} // namespace app

View File

@ -10,6 +10,7 @@
#pragma once
#include "base/recent_items.h"
#include "base/signal.h"
#include <string>
@ -35,6 +36,8 @@ namespace app {
void addRecentFile(const char* filename);
void removeRecentFile(const char* filename);
Signal0<void> Changed;
private:
List m_files;
List m_paths;

View File

@ -0,0 +1,79 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/res/http_loader.h"
#include "base/bind.h"
#include "base/replace_string.h"
#include "base/fs.h"
#include "base/path.h"
#include "base/scoped_value.h"
#include "net/http_request.h"
#include "net/http_response.h"
#include <fstream>
namespace app {
HttpLoader::HttpLoader(const std::string& url)
: m_url(url)
, m_done(false)
, m_cancel(false)
, m_thread(Bind<void>(&HttpLoader::threadHttpRequest, this))
{
}
HttpLoader::~HttpLoader()
{
m_thread.join();
}
void HttpLoader::cancel()
{
m_cancel = true;
}
void HttpLoader::threadHttpRequest()
{
try {
base::ScopedValue<bool> scoped(m_done, false, true);
PRINTF("Sending http request to %s...\n", m_url.c_str());
std::string dir = base::join_path(getenv("TEMP"), PACKAGE);
base::make_all_directories(dir);
std::string fn = m_url;
base::replace_string(fn, ":", "-");
base::replace_string(fn, "/", "-");
base::replace_string(fn, "?", "-");
base::replace_string(fn, "&", "-");
fn = base::join_path(dir, fn);
std::ofstream output(fn);
net::HttpRequest http(m_url);
net::HttpResponse response(&output);
http.send(response);
if (response.status() == 200)
m_filename = fn;
PRINTF("Response: %d\n", response.status());
}
catch (const std::exception& e) {
PRINTF("Unexpected exception sending http request: '%s'\n", e.what());
}
catch (...) {
PRINTF("Unexpected unknown exception sending http request\n");
}
}
} // namespace app

38
src/app/res/http_loader.h Normal file
View File

@ -0,0 +1,38 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_RES_HTTP_LOADER_H_INCLUDED
#define APP_RES_HTTP_LOADER_H_INCLUDED
#pragma once
#include "base/thread.h"
#include <string>
namespace app {
class HttpLoader {
public:
HttpLoader(const std::string& url);
~HttpLoader();
void cancel();
bool isDone() const { return m_done; }
std::string filename() const { return m_filename; }
private:
void threadHttpRequest();
std::string m_url;
bool m_done;
bool m_cancel;
base::thread m_thread;
std::string m_filename;
};
} // namespace app
#endif

View File

@ -43,11 +43,6 @@ void ResourcesLoader::cancel()
m_cancel = true;
}
bool ResourcesLoader::done()
{
return m_done;
}
bool ResourcesLoader::next(base::UniquePtr<Resource>& resource)
{
Resource* rawResource;

View File

@ -24,7 +24,6 @@ namespace app {
~ResourcesLoader();
void cancel();
bool done();
bool isDone() const { return m_done; }
bool next(base::UniquePtr<Resource>& resource);

View File

@ -71,11 +71,11 @@ void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
if (isSelected() || hasMouseOver()) {
nw = PART_TOOLBUTTON_HOT_NW;
face = theme->getColor(ThemeColor::ButtonHotFace);
face = theme->colors.buttonHotFace();
}
else {
nw = PART_TOOLBUTTON_LAST_NW;
face = theme->getColor(ThemeColor::ButtonNormalFace);
face = theme->colors.buttonNormalFace();
}
Grid::Info info = buttonSet()->getChildInfo(this);

View File

@ -112,8 +112,8 @@ ColorBar::ColorBar(int align)
setFgColor(get_config_color("ColorBar", "FG", getFgColor()));
// Change color-bar background color (not ColorBar::setBgColor)
Widget::setBgColor(((SkinTheme*)getTheme())->getColor(ThemeColor::TabSelectedFace));
m_paletteView.setBgColor(((SkinTheme*)getTheme())->getColor(ThemeColor::TabSelectedFace));
Widget::setBgColor(((SkinTheme*)getTheme())->colors.tabActiveFace());
m_paletteView.setBgColor(((SkinTheme*)getTheme())->colors.tabActiveFace());
// Change labels foreground color
setup_mini_font(m_paletteButton.mainButton());

View File

@ -168,7 +168,7 @@ void ColorButton::onPaint(PaintEvent& ev)
gfx::Color bg = getBgColor();
if (gfx::is_transparent(bg))
bg = theme->getColor(ThemeColor::Face);
bg = theme->colors.face();
g->fillRect(bg, rc);
app::Color color;

View File

@ -45,7 +45,8 @@ using namespace doc;
class ColorSelector::WarningIcon : public StyledButton {
public:
WarningIcon() : StyledButton("warning_box") {
WarningIcon()
: StyledButton(skin::SkinTheme::instance()->styles.warningBox()) {
}
};

View File

@ -734,7 +734,7 @@ ContextBar::ContextBar()
border_width.b = 2*guiscale();
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
setBgColor(theme->getColor(ThemeColor::Workspace));
setBgColor(theme->colors.workspace());
addChild(m_selectionOptionsBox = new HBox());
m_selectionOptionsBox->addChild(m_dropPixels = new DropPixelsField());

View File

@ -11,14 +11,20 @@
#include "app/ui/devconsole_view.h"
#include "app/app_menus.h"
#include "app/ui/skin/skin_style_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/workspace.h"
#include "ui/entry.h"
#include "ui/message.h"
#include "ui/system.h"
#include "ui/textbox.h"
#include "ui/view.h"
namespace app {
using namespace ui;
using namespace app::skin;
class DevConsoleView::CommmandEntry : public Entry {
public:
@ -59,16 +65,20 @@ DevConsoleView::DevConsoleView()
, m_label(">")
, m_entry(new CommmandEntry)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
addChild(&m_view);
addChild(&m_bottomBox);
m_bottomBox.addChild(&m_label);
m_bottomBox.addChild(m_entry);
m_view.setProperty(SkinStylePropertyPtr(
new SkinStyleProperty(theme->styles.workspaceView())));
m_view.attachToView(&m_textBox);
m_view.setExpansive(true);
m_entry->setExpansive(true);
m_entry->ExecuteCommand.connect(&DevConsoleView::onExecuteCommand, this);
}
@ -83,6 +93,11 @@ std::string DevConsoleView::getTabText()
return "Console";
}
TabIcon DevConsoleView::getTabIcon()
{
return TabIcon::NONE;
}
WorkspaceView* DevConsoleView::cloneWorkspaceView()
{
return new DevConsoleView();
@ -97,6 +112,21 @@ void DevConsoleView::onClonedFrom(WorkspaceView* from)
{
}
bool DevConsoleView::onCloseView(Workspace* workspace)
{
workspace->removeView(this);
return true;
}
void DevConsoleView::onTabPopup(Workspace* workspace)
{
Menu* menu = AppMenus::instance()->getTabPopupMenu();
if (!menu)
return;
menu->showPopup(ui::get_mouse_position());
}
bool DevConsoleView::onProcessMessage(Message* msg)
{
return Box::onProcessMessage(msg);

View File

@ -26,12 +26,15 @@ namespace app {
// TabView implementation
std::string getTabText() override;
TabIcon getTabIcon() override;
// WorkspaceView implementation
ui::Widget* getContentWidget() override { return this; }
WorkspaceView* cloneWorkspaceView() override;
void onWorkspaceViewSelected() override;
void onClonedFrom(WorkspaceView* from) override;
bool onCloseView(Workspace* workspace) override;
void onTabPopup(Workspace* workspace) override;
protected:
bool onProcessMessage(ui::Message* msg) override;

View File

@ -12,6 +12,9 @@
#include "app/ui/document_view.h"
#include "app/app.h"
#include "app/app_menus.h"
#include "app/commands/commands.h"
#include "app/document_access.h"
#include "app/modules/editors.h"
#include "app/modules/palettes.h"
#include "app/ui/editor/editor.h"
@ -20,12 +23,16 @@
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/preview_editor.h"
#include "app/ui/status_bar.h"
#include "app/ui/workspace.h"
#include "app/ui_context.h"
#include "base/path.h"
#include "doc/document_event.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "ui/accelerator.h"
#include "ui/alert.h"
#include "ui/menu.h"
#include "ui/message.h"
#include "ui/system.h"
#include "ui/view.h"
@ -191,13 +198,12 @@ void DocumentView::getDocumentLocation(DocumentLocation* location) const
std::string DocumentView::getTabText()
{
std::string str = m_document->name();
return m_document->name();
}
// Add an asterisk if the document is modified.
if (m_document->isModified())
str += "*";
return str;
TabIcon DocumentView::getTabIcon()
{
return TabIcon::NONE;
}
WorkspaceView* DocumentView::cloneWorkspaceView()
@ -223,6 +229,81 @@ void DocumentView::onClonedFrom(WorkspaceView* from)
->setViewScroll(View::getView(srcEditor)->getViewScroll());
}
bool DocumentView::onCloseView(Workspace* workspace)
{
UIContext* ctx = UIContext::instance();
bool save_it;
bool try_again = true;
while (try_again) {
// This flag indicates if we have to sabe the sprite before to destroy it
save_it = false;
{
// see if the sprite has changes
while (m_document->isModified()) {
// ask what want to do the user with the changes in the sprite
int ret = Alert::show("Warning<<Saving changes in:<<%s||&Save||Do&n't Save||&Cancel",
m_document->name().c_str());
if (ret == 1) {
// "save": save the changes
save_it = true;
break;
}
else if (ret != 2) {
// "cancel" or "ESC" */
return false; // we back doing nothing
}
else {
// "discard"
break;
}
}
}
// Does we need to save the sprite?
if (save_it) {
ctx->setActiveView(this);
ctx->updateFlags();
Command* save_command =
CommandsModule::instance()->getCommandByName(CommandId::SaveFile);
ctx->executeCommand(save_command);
try_again = true;
}
else
try_again = false;
}
// Destroy the sprite (locking it as writer)
DocumentDestroyer destroyer(
static_cast<app::Context*>(m_document->context()), m_document);
StatusBar::instance()
->setStatusText(0, "Sprite '%s' closed.",
m_document->name().c_str());
destroyer.destroyDocument();
// At this point the view is already destroyed
return true;
}
void DocumentView::onTabPopup(Workspace* workspace)
{
Menu* menu = AppMenus::instance()->getDocumentTabPopupMenu();
if (!menu)
return;
UIContext* ctx = UIContext::instance();
ctx->setActiveView(this);
ctx->updateFlags();
menu->showPopup(ui::get_mouse_position());
}
bool DocumentView::onProcessMessage(Message* msg)
{
switch (msg->type()) {

View File

@ -42,12 +42,15 @@ namespace app {
// TabView implementation
std::string getTabText() override;
TabIcon getTabIcon() override;
// WorkspaceView implementation
ui::Widget* getContentWidget() override { return this; }
WorkspaceView* cloneWorkspaceView() override;
void onWorkspaceViewSelected() override;
void onClonedFrom(WorkspaceView* from) override;
bool onCloseView(Workspace* workspace) override;
void onTabPopup(Workspace* workspace) override;
// DocumentObserver implementation
void onGeneralUpdate(doc::DocumentEvent& ev) override;

View File

@ -508,7 +508,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
// sprite).
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
if (m_flags & kShowOutside) {
g->fillRegion(theme->getColor(ThemeColor::EditorFace), outside);
g->fillRegion(theme->colors.editorFace(), outside);
}
// Grids
@ -556,9 +556,9 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
if (m_flags & kShowOutside) {
// Draw the borders that enclose the sprite.
enclosingRect.enlarge(1);
g->drawRect(theme->getColor(ThemeColor::EditorSpriteBorder), enclosingRect);
g->drawRect(theme->colors.editorSpriteBorder(), enclosingRect);
g->drawHLine(
theme->getColor(ThemeColor::EditorSpriteBottomBorder),
theme->colors.editorSpriteBottomBorder(),
enclosingRect.x, enclosingRect.y+enclosingRect.h, enclosingRect.w);
}
@ -1310,7 +1310,7 @@ void Editor::onPaint(ui::PaintEvent& ev)
// Editor without sprite
if (!m_sprite) {
g->fillRect(theme->getColor(ThemeColor::EditorFace), rc);
g->fillRect(theme->colors.editorFace(), rc);
}
// Editor with sprite
else {
@ -1338,7 +1338,7 @@ void Editor::onPaint(ui::PaintEvent& ev)
catch (const LockedDocumentException&) {
// The sprite is locked to be read, so we can draw an opaque
// background only.
g->fillRect(theme->getColor(ThemeColor::EditorFace), rc);
g->fillRect(theme->colors.editorFace(), rc);
}
}
}

View File

@ -41,6 +41,8 @@
#include "ui/system.h"
#include "ui/view.h"
#include <cstring>
namespace app {
using namespace ui;
@ -343,14 +345,14 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
if (KeyboardShortcuts::instance()
->getCommandFromKeyMessage(msg, &command, &params)) {
// We accept zoom commands.
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
if (std::strcmp(command->short_name(), CommandId::Zoom) == 0) {
UIContext::instance()->executeCommand(command, params);
return true;
}
// Intercept the "Cut" or "Copy" command to handle them locally
// with the current m_pixelsMovement data.
else if (strcmp(command->short_name(), CommandId::Cut) == 0 ||
strcmp(command->short_name(), CommandId::Copy) == 0) {
else if (std::strcmp(command->short_name(), CommandId::Cut) == 0 ||
std::strcmp(command->short_name(), CommandId::Copy) == 0) {
// Copy the floating image to the clipboard.
{
Document* document = editor->document();
@ -362,7 +364,7 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
}
// In case of "Cut" command.
if (strcmp(command->short_name(), CommandId::Cut) == 0) {
if (std::strcmp(command->short_name(), CommandId::Cut) == 0) {
// Discard the dragged image.
m_pixelsMovement->discardImage();
m_discarded = true;
@ -376,7 +378,7 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
}
// Flip Horizontally/Vertically commands are handled manually to
// avoid dropping the floating region of pixels.
else if (strcmp(command->short_name(), CommandId::Flip) == 0) {
else if (std::strcmp(command->short_name(), CommandId::Flip) == 0) {
if (FlipCommand* flipCommand = dynamic_cast<FlipCommand*>(command)) {
flipCommand->loadParams(params);
m_pixelsMovement->flipImage(flipCommand->getFlipType());
@ -443,8 +445,8 @@ void MovingPixelsState::onBeforeCommandExecution(Command* command)
if (moveMaskCmd->getTarget() == MoveMaskCommand::Content)
return;
}
else if ((strcmp(command->short_name(), CommandId::Zoom) == 0) ||
(strcmp(command->short_name(), CommandId::Scroll) == 0)) {
else if ((std::strcmp(command->short_name(), CommandId::Zoom) == 0) ||
(std::strcmp(command->short_name(), CommandId::Scroll) == 0)) {
return;
}

View File

@ -312,7 +312,7 @@ void FileList::onPaint(ui::PaintEvent& ev)
she::Surface* thumbnail = NULL;
int thumbnail_y = 0;
g->fillRect(theme->getColor(ThemeColor::Background), bounds);
g->fillRect(theme->colors.background(), bounds);
// rows
for (FileItemList::iterator
@ -321,18 +321,18 @@ void FileList::onPaint(ui::PaintEvent& ev)
gfx::Size itemSize = getFileItemSize(fi);
if (fi == m_selected) {
fgcolor = theme->getColor(ThemeColor::FileListSelectedRowText);
bgcolor = theme->getColor(ThemeColor::FileListSelectedRowFace);
fgcolor = theme->colors.filelistSelectedRowText();
bgcolor = theme->colors.filelistSelectedRowFace();
}
else {
bgcolor = evenRow ? theme->getColor(ThemeColor::FileListEvenRowFace):
theme->getColor(ThemeColor::FileListOddRowFace);
bgcolor = evenRow ? theme->colors.filelistEvenRowFace():
theme->colors.filelistOddRowFace();
if (fi->isFolder() && !fi->isBrowsable())
fgcolor = theme->getColor(ThemeColor::FileListDisabledRowText);
fgcolor = theme->colors.filelistDisabledRowText();
else
fgcolor = evenRow ? theme->getColor(ThemeColor::FileListEvenRowText):
theme->getColor(ThemeColor::FileListOddRowText);
fgcolor = evenRow ? theme->colors.filelistEvenRowText():
theme->colors.filelistOddRowText();
}
x = bounds.x+2*guiscale();

148
src/app/ui/home_view.cpp Normal file
View File

@ -0,0 +1,148 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/home_view.h"
#include "app/app_menus.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/ui/news_listbox.h"
#include "app/ui/recent_listbox.h"
#include "app/ui/skin/skin_style_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/workspace.h"
#include "app/ui_context.h"
#include "base/bind.h"
#include "base/exception.h"
#include "ui/label.h"
#include "ui/system.h"
#include "ui/textbox.h"
#include "ui/view.h"
namespace app {
using namespace ui;
using namespace app::skin;
HomeView::HomeView()
: m_files(new RecentFilesListBox)
, m_folders(new RecentFoldersListBox)
, m_news(new NewsListBox)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
setBgColor(theme->colors.workspace());
child_spacing = 8 * guiscale();
newFile()->Click.connect(Bind(&HomeView::onNewFile, this));
openFile()->Click.connect(Bind(&HomeView::onOpenFile, this));
filesView()->attachToView(m_files);
foldersView()->attachToView(m_folders);
newsView()->attachToView(m_news);
checkUpdate()->setVisible(false);
}
HomeView::~HomeView()
{
}
std::string HomeView::getTabText()
{
return "Home";
}
TabIcon HomeView::getTabIcon()
{
return TabIcon::HOME;
}
WorkspaceView* HomeView::cloneWorkspaceView()
{
return NULL; // This view cannot be cloned
}
void HomeView::onClonedFrom(WorkspaceView* from)
{
ASSERT(false); // Never called
}
bool HomeView::onCloseView(Workspace* workspace)
{
workspace->removeView(this);
return true;
}
void HomeView::onTabPopup(Workspace* workspace)
{
Menu* menu = AppMenus::instance()->getTabPopupMenu();
if (!menu)
return;
menu->showPopup(ui::get_mouse_position());
}
void HomeView::onWorkspaceViewSelected()
{
}
void HomeView::onNewFile()
{
Command* command = CommandsModule::instance()->getCommandByName(CommandId::NewFile);
Params params;
UIContext::instance()->executeCommand(command, &params);
}
void HomeView::onOpenFile()
{
Command* command = CommandsModule::instance()->getCommandByName(CommandId::OpenFile);
Params params;
UIContext::instance()->executeCommand(command, &params);
}
void HomeView::onCheckingUpdates()
{
checkUpdate()->setText("Checking Updates...");
checkUpdate()->setVisible(true);
layout();
}
void HomeView::onUpToDate()
{
checkUpdate()->setText(PACKAGE " is up to date");
checkUpdate()->setVisible(true);
layout();
}
void HomeView::onNewUpdate(const std::string& url, const std::string& version)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
checkUpdate()->setText("New " PACKAGE " v" + version + " available!");
checkUpdate()->setUrl(url);
checkUpdate()->setProperty(
SkinStylePropertyPtr(new SkinStyleProperty(theme->styles.workspaceUpdateLink())));
// TODO this should be in a skin.xml's <style>
gfx::Size iconSize = theme->styles.workspaceUpdateLink()->preferredSize(
nullptr, Style::State());
checkUpdate()->setBorder(gfx::Border(6*guiscale())+gfx::Border(
0, 0, iconSize.w, 0));
checkUpdate()->setVisible(true);
layout();
}
} // namespace app

71
src/app/ui/home_view.h Normal file
View File

@ -0,0 +1,71 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_HOME_VIEW_H_INCLUDED
#define APP_UI_HOME_VIEW_H_INCLUDED
#pragma once
#include "app/check_update_delegate.h"
#include "app/ui/tabs.h"
#include "app/ui/workspace_view.h"
#include "ui/box.h"
#include "generated_home_view.h"
namespace ui {
class View;
}
namespace app {
class NewsListBox;
class RecentFilesListBox;
class RecentFoldersListBox;
class HomeView : public app::gen::HomeView
, public TabView
, public WorkspaceView
#ifdef ENABLE_UPDATER
, public CheckUpdateDelegate
#endif
{
public:
HomeView();
~HomeView();
// TabView implementation
std::string getTabText() override;
TabIcon getTabIcon() override;
// WorkspaceView implementation
ui::Widget* getContentWidget() override { return this; }
WorkspaceView* cloneWorkspaceView() override;
void onClonedFrom(WorkspaceView* from) override;
bool onCloseView(Workspace* workspace) override;
void onTabPopup(Workspace* workspace) override;
void onWorkspaceViewSelected() override;
protected:
#ifdef ENABLE_UPDATER
// CheckUpdateDelegate impl
void onCheckingUpdates() override;
void onUpToDate() override;
void onNewUpdate(const std::string& url, const std::string& version) override;
#endif
private:
void onNewFile();
void onOpenFile();
RecentFilesListBox* m_files;
RecentFoldersListBox* m_folders;
NewsListBox* m_news;
};
} // namespace app
#endif

View File

@ -21,15 +21,16 @@
#include "app/settings/settings.h"
#include "app/ui/color_bar.h"
#include "app/ui/context_bar.h"
#include "app/ui/devconsole_view.h"
#include "app/ui/document_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/editor_view.h"
#include "app/ui/home_view.h"
#include "app/ui/main_menu_bar.h"
#include "app/ui/notifications.h"
#include "app/ui/preview_editor.h"
#include "app/ui/skin/skin_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/start_view.h"
#include "app/ui/status_bar.h"
#include "app/ui/tabs.h"
#include "app/ui/timeline.h"
@ -46,42 +47,24 @@ namespace app {
using namespace ui;
MainWindow::MainWindow()
: Window(DesktopWindow)
, m_lastSplitterPos(0.0)
, m_lastTimelineSplitterPos(75.0)
, m_mode(NormalMode)
, m_startView(NULL)
: m_mode(NormalMode)
, m_homeView(nullptr)
, m_devConsoleView(nullptr)
{
setId("main_window");
// Load all menus by first time.
AppMenus::instance()->reload();
Widget* mainBox = app::load_widget<Widget>("main_window.xml", "main_box");
addChild(mainBox);
Widget* box_menubar = findChild("menubar");
Widget* box_contextbar = findChild("contextbar");
Widget* box_colorbar = findChild("colorbar");
Widget* box_toolbar = findChild("toolbar");
Widget* box_statusbar = findChild("statusbar");
Widget* box_tabsbar = findChild("tabsbar");
Widget* box_workspace = findChild("workspace");
Widget* box_timeline = findChild("timeline");
m_menuBar = new MainMenuBar();
m_notifications = new Notifications();
m_contextBar = new ContextBar();
m_statusBar = new StatusBar();
m_colorBar = new ColorBar(box_colorbar->getAlign());
m_colorBar = new ColorBar(colorBarPlaceholder()->getAlign());
m_toolBar = new ToolBar();
m_tabsBar = new Tabs(this);
m_workspace = new Workspace();
m_workspace->ActiveViewChanged.connect(&MainWindow::onActiveViewChange, this);
m_previewEditor = new PreviewEditorWindow();
m_timeline = new Timeline();
m_colorBarSplitter = findChildT<Splitter>("colorbarsplitter");
m_timelineSplitter = findChildT<Splitter>("timelinesplitter");
// configure all widgets to expansives
m_menuBar->setExpansive(true);
@ -99,20 +82,19 @@ MainWindow::MainWindow()
m_menuBar->setMenu(AppMenus::instance()->getRootMenu());
// Add the widgets in the boxes
if (box_menubar) {
box_menubar->addChild(m_menuBar);
box_menubar->addChild(m_notifications);
}
if (box_contextbar) box_contextbar->addChild(m_contextBar);
if (box_colorbar) box_colorbar->addChild(m_colorBar);
if (box_toolbar) box_toolbar->addChild(m_toolBar);
if (box_statusbar) box_statusbar->addChild(m_statusBar);
if (box_tabsbar) box_tabsbar->addChild(m_tabsBar);
if (box_workspace) box_workspace->addChild(m_workspace);
if (box_timeline) box_timeline->addChild(m_timeline);
menuBarPlaceholder()->addChild(m_menuBar);
menuBarPlaceholder()->addChild(m_notifications);
contextBarPlaceholder()->addChild(m_contextBar);
colorBarPlaceholder()->addChild(m_colorBar);
toolBarPlaceholder()->addChild(m_toolBar);
statusBarPlaceholder()->addChild(m_statusBar);
tabsPlaceholder()->addChild(m_tabsBar);
workspacePlaceholder()->addChild(m_workspace);
timelinePlaceholder()->addChild(m_timeline);
// Default layout of widgets
m_colorBarSplitter->setPosition(m_colorBar->getPreferredSize().w);
// Default splitter positions
colorBarSplitter()->setPosition(m_colorBar->getPreferredSize().w);
timelineSplitter()->setPosition(75);
// Prepare the window
remapWindow();
@ -122,9 +104,15 @@ MainWindow::MainWindow()
MainWindow::~MainWindow()
{
if (m_startView) {
m_workspace->removeView(m_startView);
delete m_startView;
if (m_devConsoleView) {
if (m_devConsoleView->getParent())
m_workspace->removeView(m_devConsoleView);
delete m_devConsoleView;
}
if (m_homeView) {
if (m_homeView->getParent())
m_workspace->removeView(m_homeView);
delete m_homeView;
}
delete m_contextBar;
delete m_previewEditor;
@ -139,6 +127,25 @@ MainWindow::~MainWindow()
m_menuBar->setMenu(NULL);
}
DocumentView* MainWindow::getDocView()
{
return dynamic_cast<DocumentView*>(m_workspace->activeView());
}
HomeView* MainWindow::getHomeView()
{
if (!m_homeView)
m_homeView = new HomeView;
return m_homeView;
}
#ifdef ENABLE_UPDATER
CheckUpdateDelegate* MainWindow::getCheckUpdateDelegate()
{
return getHomeView();
}
#endif
void MainWindow::reloadMenus()
{
m_menuBar->reload();
@ -154,56 +161,45 @@ void MainWindow::showNotification(INotificationDelegate* del)
m_notifications->getParent()->layout();
}
void MainWindow::showHome()
{
if (!getHomeView()->getParent()) {
m_workspace->addView(m_homeView);
m_tabsBar->selectTab(m_homeView);
}
}
void MainWindow::showDevConsole()
{
if (!m_devConsoleView)
m_devConsoleView = new DevConsoleView;
if (!m_devConsoleView->getParent()) {
m_workspace->addView(m_devConsoleView);
m_tabsBar->selectTab(m_devConsoleView);
}
}
void MainWindow::setMode(Mode mode)
{
// Check if we already are in the given mode.
if (m_mode == mode)
return;
if (mode == NormalMode) {
if (m_colorBarSplitter->getPosition() == 0.0)
m_colorBarSplitter->setPosition(m_lastSplitterPos);
}
// If current mode is "normal", we save the splitter position of the
// color bar in "m_lastSplitterPos" before we hide it.
else if (m_mode == NormalMode) {
m_lastSplitterPos = m_colorBarSplitter->getPosition();
m_colorBarSplitter->setPosition(0.0);
}
m_menuBar->setVisible(mode == NormalMode);
m_tabsBar->setVisible(mode == NormalMode);
m_toolBar->setVisible(mode == NormalMode);
m_statusBar->setVisible(mode == NormalMode);
m_contextBar->setVisible(
mode == NormalMode ||
mode == ContextBarAndTimelineMode);
setTimelineVisibility(
mode == NormalMode ||
mode == ContextBarAndTimelineMode);
m_mode = mode;
layout();
configureWorkspaceLayout();
}
bool MainWindow::getTimelineVisibility() const
{
return m_timelineSplitter->getPosition() < 100.0;
return App::instance()->preferences().general.visibleTimeline();
}
void MainWindow::setTimelineVisibility(bool visible)
{
if (visible) {
if (m_timelineSplitter->getPosition() >= 100.0)
m_timelineSplitter->setPosition(m_lastTimelineSplitterPos);
}
else {
if (m_timelineSplitter->getPosition() < 100.0) {
m_lastTimelineSplitterPos = m_timelineSplitter->getPosition();
m_timelineSplitter->setPosition(100.0);
}
}
layout();
App::instance()->preferences().general.visibleTimeline(visible);
configureWorkspaceLayout();
}
void MainWindow::popTimeline()
@ -219,13 +215,8 @@ void MainWindow::popTimeline()
bool MainWindow::onProcessMessage(ui::Message* msg)
{
#if 0 // TODO Enable start view
if (msg->type() == kOpenMessage) {
m_startView = new StartView;
m_workspace->addView(m_startView);
m_tabsBar->selectTab(m_startView);
}
#endif
if (msg->type() == kOpenMessage)
showHome();
return Window::onProcessMessage(msg);
}
@ -233,11 +224,6 @@ bool MainWindow::onProcessMessage(ui::Message* msg)
void MainWindow::onSaveLayout(SaveLayoutEvent& ev)
{
Window::onSaveLayout(ev);
// Restore splitter position if we are in advanced mode, so we save
// the original splitter position in the layout.
if (m_colorBarSplitter->getPosition() == 0.0)
m_colorBarSplitter->setPosition(m_lastSplitterPos);
}
// When the active view is changed from methods like
@ -245,58 +231,41 @@ void MainWindow::onSaveLayout(SaveLayoutEvent& ev)
// inform to the UIContext that the current view has changed.
void MainWindow::onActiveViewChange()
{
if (DocumentView* docView = dynamic_cast<DocumentView*>(m_workspace->activeView())) {
if (DocumentView* docView = getDocView())
UIContext::instance()->setActiveView(docView);
else
UIContext::instance()->setActiveView(nullptr);
m_contextBar->updateFromTool(UIContext::instance()
->settings()->getCurrentTool());
if (m_mode != EditorOnlyMode)
m_contextBar->setVisible(true);
}
else {
UIContext::instance()->setActiveView(NULL);
if (m_mode != EditorOnlyMode)
m_contextBar->setVisible(false);
}
layout();
configureWorkspaceLayout();
}
void MainWindow::clickTab(Tabs* tabs, TabView* tabView, ui::MouseButtons buttons)
void MainWindow::onSelectTab(Tabs* tabs, TabView* tabView)
{
if (!tabView)
return;
WorkspaceView* workspaceView = dynamic_cast<WorkspaceView*>(tabView);
if (m_workspace->activeView() != workspaceView)
m_workspace->setActiveView(workspaceView);
DocumentView* docView = dynamic_cast<DocumentView*>(workspaceView);
if (!docView)
return;
UIContext* context = UIContext::instance();
context->setActiveView(docView);
context->updateFlags();
// Right-button: popup-menu
if (buttons & kButtonRight) {
Menu* popup_menu = AppMenus::instance()->getDocumentTabPopupMenu();
if (popup_menu != NULL) {
popup_menu->showPopup(ui::get_mouse_position());
}
}
// Middle-button: close the sprite
else if (buttons & kButtonMiddle) {
Command* close_file_cmd =
CommandsModule::instance()->getCommandByName(CommandId::CloseFile);
context->executeCommand(close_file_cmd, NULL);
}
WorkspaceView* view = dynamic_cast<WorkspaceView*>(tabView);
if (m_workspace->activeView() != view)
m_workspace->setActiveView(view);
}
void MainWindow::mouseOverTab(Tabs* tabs, TabView* tabView)
void MainWindow::onCloseTab(Tabs* tabs, TabView* tabView)
{
WorkspaceView* view = dynamic_cast<WorkspaceView*>(tabView);
ASSERT(view);
if (view)
m_workspace->closeView(view);
}
void MainWindow::onContextMenuTab(Tabs* tabs, TabView* tabView)
{
WorkspaceView* view = dynamic_cast<WorkspaceView*>(tabView);
ASSERT(view);
if (view)
view->onTabPopup(m_workspace);
}
void MainWindow::onMouseOverTab(Tabs* tabs, TabView* tabView)
{
// Note: tabView can be NULL
if (DocumentView* docView = dynamic_cast<DocumentView*>(tabView)) {
@ -309,4 +278,43 @@ void MainWindow::mouseOverTab(Tabs* tabs, TabView* tabView)
}
}
bool MainWindow::onIsModified(Tabs* tabs, TabView* tabView)
{
if (DocumentView* docView = dynamic_cast<DocumentView*>(tabView)) {
Document* document = docView->getDocument();
return document->isModified();
}
else {
return false;
}
}
void MainWindow::configureWorkspaceLayout()
{
bool normal = (m_mode == NormalMode);
bool isDoc = (getDocView() != nullptr);
m_menuBar->setVisible(normal);
m_tabsBar->setVisible(normal);
colorBarPlaceholder()->setVisible(normal && isDoc);
m_toolBar->setVisible(normal && isDoc);
m_statusBar->setVisible(normal);
m_contextBar->setVisible(
isDoc &&
(m_mode == NormalMode ||
m_mode == ContextBarAndTimelineMode));
timelinePlaceholder()->setVisible(
isDoc &&
(m_mode == NormalMode ||
m_mode == ContextBarAndTimelineMode) &&
App::instance()->preferences().general.visibleTimeline());
if (m_contextBar->isVisible()) {
m_contextBar->updateFromTool(
UIContext::instance()->settings()->getCurrentTool());
}
layout();
}
} // namespace app

View File

@ -12,25 +12,33 @@
#include "app/ui/tabs.h"
#include "ui/window.h"
#include "generated_main_window.h"
namespace ui {
class Splitter;
}
namespace app {
#ifdef ENABLE_UPDATER
class CheckUpdateDelegate;
#endif
class ColorBar;
class ContextBar;
class DevConsoleView;
class DocumentView;
class HomeView;
class INotificationDelegate;
class MainMenuBar;
class PreviewEditorWindow;
class Notifications;
class StartView;
class PreviewEditorWindow;
class StatusBar;
class Tabs;
class Timeline;
class Workspace;
class MainWindow : public ui::Window
class MainWindow : public app::gen::MainWindow
, public TabsDelegate {
public:
enum Mode {
@ -48,10 +56,15 @@ namespace app {
Timeline* getTimeline() { return m_timeline; }
Workspace* getWorkspace() { return m_workspace; }
PreviewEditorWindow* getPreviewEditor() { return m_previewEditor; }
#ifdef ENABLE_UPDATER
CheckUpdateDelegate* getCheckUpdateDelegate();
#endif
void start();
void reloadMenus();
void showNotification(INotificationDelegate* del);
void showHome();
void showDevConsole();
Mode getMode() const { return m_mode; }
void setMode(Mode mode);
@ -61,8 +74,11 @@ namespace app {
void popTimeline();
// TabsDelegate implementation.
void clickTab(Tabs* tabs, TabView* tabView, ui::MouseButtons buttons);
void mouseOverTab(Tabs* tabs, TabView* tabView);
void onSelectTab(Tabs* tabs, TabView* tabView) override;
void onCloseTab(Tabs* tabs, TabView* tabView) override;
void onContextMenuTab(Tabs* tabs, TabView* tabView) override;
void onMouseOverTab(Tabs* tabs, TabView* tabView) override;
bool onIsModified(Tabs* tabs, TabView* tabView) override;
protected:
bool onProcessMessage(ui::Message* msg) override;
@ -70,21 +86,22 @@ namespace app {
void onActiveViewChange();
private:
DocumentView* getDocView();
HomeView* getHomeView();
void configureWorkspaceLayout();
MainMenuBar* m_menuBar;
ContextBar* m_contextBar;
StatusBar* m_statusBar;
ColorBar* m_colorBar;
ui::Splitter* m_colorBarSplitter;
ui::Splitter* m_timelineSplitter;
ui::Widget* m_toolBar;
Tabs* m_tabsBar;
double m_lastSplitterPos;
double m_lastTimelineSplitterPos;
Mode m_mode;
Timeline* m_timeline;
Workspace* m_workspace;
PreviewEditorWindow* m_previewEditor;
StartView* m_startView;
HomeView* m_homeView;
DevConsoleView* m_devConsoleView;
Notifications* m_notifications;
};

309
src/app/ui/news_listbox.cpp Normal file
View File

@ -0,0 +1,309 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/news_listbox.h"
#include "app/app.h"
#include "app/pref/preferences.h"
#include "app/res/http_loader.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/xml_document.h"
#include "base/fs.h"
#include "base/string.h"
#include "base/time.h"
#include "ui/link_label.h"
#include "ui/paint_event.h"
#include "ui/preferred_size_event.h"
#include "ui/view.h"
#include "tinyxml.h"
#include <cctype>
#include <sstream>
namespace app {
using namespace ui;
using namespace app::skin;
namespace {
std::string convert_html_entity(const std::string& e)
{
if (e.size() >= 3 && e[0] == '#' && std::isdigit(e[1])) {
long unicodeChar;
if (e[2] == 'x')
unicodeChar = std::strtol(e.c_str()+1, nullptr, 16);
else
unicodeChar = std::strtol(e.c_str()+1, nullptr, 10);
if (unicodeChar == 0x2018) return "\x60";
if (unicodeChar == 0x2019) return "'";
else {
std::wstring wstr(1, (wchar_t)unicodeChar);
return base::to_utf8(wstr);
}
}
else if (e == "lt") return "<";
else if (e == "gt") return ">";
else if (e == "amp") return "&";
return "";
}
std::string parse_html(const std::string& str)
{
bool paraOpen = true;
std::string result;
size_t i = 0;
while (i < str.size()) {
// Ignore content between <...> symbols
if (str[i] == '<') {
size_t j = ++i;
while (i < str.size() && str[i] != '>')
++i;
if (i < str.size()) {
ASSERT(str[i] == '>');
std::string tag = str.substr(j, i - j);
if (tag == "li") {
if (!paraOpen)
result.push_back('\n');
result.push_back((char)0xc2);
result.push_back((char)0xb7); // middle dot
result.push_back(' ');
paraOpen = false;
}
else if (tag == "p" || tag == "ul") {
if (!paraOpen)
result.push_back('\n');
paraOpen = true;
}
++i;
}
}
else if (str[i] == '&') {
size_t j = ++i;
while (i < str.size() && str[i] != ';')
++i;
if (i < str.size()) {
ASSERT(str[i] == ';');
std::string entity = str.substr(j, i - j);
result += convert_html_entity(entity);
++i;
}
paraOpen = false;
}
else {
result.push_back(str[i++]);
paraOpen = false;
}
}
return result;
}
}
class NewsItem : public LinkLabel {
public:
NewsItem(const std::string& link,
const std::string& title,
const std::string& desc)
: LinkLabel(link, title)
, m_desc(desc) {
}
protected:
void onPreferredSize(PreferredSizeEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
Style* style = theme->styles.newsItem();
Style* styleDetail = theme->styles.newsItemDetail();
Style::State state;
gfx::Size sz1 = style->preferredSize(getText().c_str(), state);
gfx::Size sz2, sz2fourlines;
if (!m_desc.empty()) {
View* view = View::getView(getParent());
sz2 = styleDetail->preferredSize(m_desc.c_str(), state,
(view ? view->getViewportBounds().w: 0));
sz2fourlines = styleDetail->preferredSize("\n\n\n", state);
}
ev.setPreferredSize(gfx::Size(0, MIN(sz1.h+sz2fourlines.h, sz1.h+sz2.h)));
}
void onPaint(PaintEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
Graphics* g = ev.getGraphics();
gfx::Rect bounds = getClientBounds();
Style* style = theme->styles.newsItem();
Style* styleDetail = theme->styles.newsItemDetail();
Style::State state;
if (hasMouse() && !getManager()->getCapture()) state += Style::hover();
if (isSelected()) state += Style::active();
if (getParent()->hasCapture()) state += Style::clicked();
gfx::Size textSize = style->preferredSize(getText().c_str(), state);
gfx::Rect textBounds(bounds.x, bounds.y, bounds.w, textSize.h);
gfx::Rect detailsBounds(
bounds.x, bounds.y+textSize.h,
bounds.w, bounds.h-textSize.h);
style->paint(g, textBounds, getText().c_str(), state);
styleDetail->paint(g, detailsBounds, m_desc.c_str(), state);
}
private:
std::string m_desc;
};
class ProblemsItem : public NewsItem {
public:
ProblemsItem() : NewsItem("", "Problems loading news. Retry.", "") {
}
protected:
void onClick() override {
static_cast<NewsListBox*>(getParent())->reload();
}
};
NewsListBox::NewsListBox()
: m_loader(nullptr)
, m_timer(250, this)
{
m_timer.Tick.connect(&NewsListBox::onTick, this);
std::string cache = App::instance()->preferences().news.cacheFile();
if (!cache.empty() && base::is_file(cache) && validCache(cache))
parseFile(cache);
else
reload();
}
NewsListBox::~NewsListBox()
{
if (m_timer.isRunning())
m_timer.stop();
delete m_loader;
m_loader = nullptr;
}
void NewsListBox::reload()
{
if (m_loader || m_timer.isRunning())
return;
while (getLastChild())
removeChild(getLastChild());
View* view = View::getView(this);
if (view)
view->updateView();
m_loader = new HttpLoader(WEBSITE_NEWS_RSS);
m_timer.start();
}
void NewsListBox::onTick()
{
if (!m_loader || !m_loader->isDone())
return;
std::string fn = m_loader->filename();
delete m_loader;
m_loader = nullptr;
m_timer.stop();
if (fn.empty()) {
addChild(new ProblemsItem());
View::getView(this)->updateView();
return;
}
parseFile(fn);
}
void NewsListBox::parseFile(const std::string& filename)
{
View* view = View::getView(this);
XmlDocumentRef doc;
try {
doc = open_xml(filename);
}
catch (...) {
addChild(new ProblemsItem());
if (view)
view->updateView();
return;
}
TiXmlHandle handle(doc);
TiXmlElement* itemXml = handle
.FirstChild("rss")
.FirstChild("channel")
.FirstChild("item").ToElement();
int count = 0;
while (itemXml) {
TiXmlElement* titleXml = itemXml->FirstChildElement("title");
TiXmlElement* descXml = itemXml->FirstChildElement("description");
TiXmlElement* linkXml = itemXml->FirstChildElement("link");
TiXmlElement* guidXml = itemXml->FirstChildElement("guid");
TiXmlElement* pubDateXml = itemXml->FirstChildElement("pubDate");
std::string link = linkXml->GetText();
std::string title = titleXml->GetText();
std::string desc = parse_html(descXml->GetText());
addChild(new NewsItem(link, title, desc));
itemXml = itemXml->NextSiblingElement();
if (++count == 4)
break;
}
TiXmlElement* linkXml = handle
.FirstChild("rss")
.FirstChild("channel")
.FirstChild("link").ToElement();
if (linkXml)
addChild(new NewsItem(linkXml->GetText(), "More...", ""));
if (view)
view->updateView();
// Save as cached news
App::instance()->preferences().news.cacheFile(filename);
}
bool NewsListBox::validCache(const std::string& filename)
{
base::Time
now = base::current_time(),
time = base::get_modification_time(filename);
now.dateOnly();
time.dateOnly();
return (now == time);
}
} // namespace app

39
src/app/ui/news_listbox.h Normal file
View File

@ -0,0 +1,39 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_NEWS_LISTBOX_H_INCLUDED
#define APP_UI_NEWS_LISTBOX_H_INCLUDED
#pragma once
#include "ui/listbox.h"
#include "ui/timer.h"
#include <string>
namespace app {
class HttpLoader;
class NewsListBox : public ui::ListBox {
public:
NewsListBox();
~NewsListBox();
void reload();
private:
void onTick();
void parseFile(const std::string& filename);
bool validCache(const std::string& filename);
ui::Timer m_timer;
HttpLoader* m_loader;
};
} // namespace app
#endif

View File

@ -23,8 +23,6 @@ namespace app {
using namespace ui;
static const char* kFlag = "flag";
class NotificationItem : public MenuItem {
public:
NotificationItem(INotificationDelegate* del)
@ -44,7 +42,7 @@ private:
Notifications::Notifications()
: Button("")
, m_flagStyle(skin::get_style(kFlag))
, m_flagStyle(skin::SkinTheme::instance()->styles.flag())
, m_withNotifications(false)
{
}

View File

@ -0,0 +1,157 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/recent_listbox.h"
#include "app/app.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/recent_files.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui_context.h"
#include "base/bind.h"
#include "base/path.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/link_label.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/preferred_size_event.h"
#include "ui/system.h"
namespace app {
using namespace ui;
using namespace skin;
//////////////////////////////////////////////////////////////////////
// RecentFileItem
class RecentFileItem : public LinkLabel {
public:
RecentFileItem(const std::string& file)
: LinkLabel(file) {
}
protected:
void onPreferredSize(PreferredSizeEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
Style* style = theme->styles.recentFile();
Style* styleDetail = theme->styles.recentFileDetail();
Style::State state;
gfx::Size sz1 = style->preferredSize(name().c_str(), state);
gfx::Size sz2 = styleDetail->preferredSize(path().c_str(), state);
ev.setPreferredSize(gfx::Size(sz1.w+sz2.w, MAX(sz1.h, sz2.h)));
}
void onPaint(PaintEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
Graphics* g = ev.getGraphics();
gfx::Rect bounds = getClientBounds();
Style* style = theme->styles.recentFile();
Style* styleDetail = theme->styles.recentFileDetail();
Style::State state;
if (hasMouse() && !getManager()->getCapture()) state += Style::hover();
if (isSelected()) state += Style::active();
if (getParent()->hasCapture()) state += Style::clicked();
std::string name = this->name();
style->paint(g, bounds, name.c_str(), state);
gfx::Size textSize = style->preferredSize(name.c_str(), state);
gfx::Rect detailsBounds(
bounds.x+textSize.w, bounds.y,
bounds.w-textSize.w, bounds.h);
styleDetail->paint(g, detailsBounds, path().c_str(), state);
}
void onClick() override {
static_cast<RecentListBox*>(getParent())->onClick(getText());
}
private:
std::string name() const { return base::get_file_name(getText()); }
std::string path() const { return base::get_file_path(getText()); }
};
//////////////////////////////////////////////////////////////////////
// RecentListBox
RecentListBox::RecentListBox()
{
m_recentFilesConn =
App::instance()->getRecentFiles()->Changed.connect(
Bind(&RecentListBox::rebuildList, this));
}
void RecentListBox::rebuildList()
{
while (getLastChild())
removeChild(getLastChild());
onRebuildList();
}
//////////////////////////////////////////////////////////////////////
// RecentFilesListBox
RecentFilesListBox::RecentFilesListBox()
{
onRebuildList();
}
void RecentFilesListBox::onRebuildList()
{
RecentFiles* recent = App::instance()->getRecentFiles();
auto it = recent->files_begin();
auto end = recent->files_end();
for (; it != end; ++it)
addChild(new RecentFileItem(it->c_str()));
}
void RecentFilesListBox::onClick(const std::string& path)
{
Command* command = CommandsModule::instance()->getCommandByName(CommandId::OpenFile);
Params params;
params.set("filename", path.c_str());
UIContext::instance()->executeCommand(command, &params);
}
//////////////////////////////////////////////////////////////////////
// RecentFoldersListBox
RecentFoldersListBox::RecentFoldersListBox()
{
onRebuildList();
}
void RecentFoldersListBox::onRebuildList()
{
RecentFiles* recent = App::instance()->getRecentFiles();
auto it = recent->paths_begin();
auto end = recent->paths_end();
for (; it != end; ++it)
addChild(new RecentFileItem(it->c_str()));
}
void RecentFoldersListBox::onClick(const std::string& path)
{
Command* command = CommandsModule::instance()->getCommandByName(CommandId::OpenFile);
Params params;
params.set("folder", path.c_str());
UIContext::instance()->executeCommand(command, &params);
}
} // namespace app

View File

@ -0,0 +1,53 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_RECENT_LISTBOX_H_INCLUDED
#define APP_UI_RECENT_LISTBOX_H_INCLUDED
#pragma once
#include "ui/listbox.h"
namespace app {
class RecentFileItem;
class RecentListBox : public ui::ListBox {
friend class RecentFileItem;
public:
RecentListBox();
protected:
virtual void onRebuildList() = 0;
virtual void onClick(const std::string& path) = 0;
private:
void rebuildList();
ScopedConnection m_recentFilesConn;
};
class RecentFilesListBox : public RecentListBox {
public:
RecentFilesListBox();
protected:
void onRebuildList() override;
void onClick(const std::string& path) override;
};
class RecentFoldersListBox : public RecentListBox {
public:
RecentFoldersListBox();
protected:
void onRebuildList() override;
void onClick(const std::string& path) override;
};
} // namespace app
#endif

View File

@ -55,12 +55,12 @@ protected:
gfx::Color bgcolor, fgcolor;
if (isSelected()) {
bgcolor = theme->getColor(ThemeColor::ListItemSelectedFace);
fgcolor = theme->getColor(ThemeColor::ListItemSelectedText);
bgcolor = theme->colors.listitemSelectedFace();
fgcolor = theme->colors.listitemSelectedText();
}
else {
bgcolor = theme->getColor(ThemeColor::ListItemNormalFace);
fgcolor = theme->getColor(ThemeColor::ListItemNormalText);
bgcolor = theme->colors.listitemNormalFace();
fgcolor = theme->colors.listitemNormalText();
}
g->fillRect(bgcolor, bounds);

View File

@ -0,0 +1,25 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_SKIN_BACKGROUND_REPEAT_H_INCLUDED
#define APP_UI_SKIN_BACKGROUND_REPEAT_H_INCLUDED
#pragma once
namespace app {
namespace skin {
enum class BackgroundRepeat {
REPEAT,
REPEAT_X,
REPEAT_Y,
NO_REPEAT
};
} // namespace skin
} // namespace app
#endif // APP_UI_SKIN_BACKGROUND_REPEAT_H_INCLUDED

View File

@ -9,9 +9,10 @@
#define APP_UI_SKIN_SKIN_PART_H_INCLUDED
#pragma once
#include <vector>
#include "base/shared_ptr.h"
#include <vector>
namespace she {
class Surface;
}
@ -26,14 +27,14 @@ namespace app {
SkinPart();
~SkinPart();
size_t size() const { return m_bitmaps.size(); }
std::size_t size() const { return m_bitmaps.size(); }
void clear();
// It doesn't destroy the previous bitmap in the given "index".
void setBitmap(size_t index, she::Surface* bitmap);
void setBitmap(std::size_t index, she::Surface* bitmap);
she::Surface* getBitmap(size_t index) const {
she::Surface* getBitmap(std::size_t index) const {
return (index < m_bitmaps.size() ? m_bitmaps[index]: NULL);
}

View File

@ -100,14 +100,6 @@ namespace app {
SKIN_PART_NESW(PART_TOOLBUTTON_LAST),
SKIN_PART_NESW(PART_TOOLBUTTON_PUSHED),
SKIN_PART_NESW(PART_TAB_NORMAL),
SKIN_PART_NESW(PART_TAB_SELECTED),
SKIN_PART_NESW(PART_TAB_BOTTOM_SELECTED),
PART_TAB_BOTTOM_NORMAL,
PART_TAB_FILLER,
SKIN_PART_NESW(PART_EDITOR_NORMAL),
SKIN_PART_NESW(PART_EDITOR_SELECTED),

View File

@ -0,0 +1,31 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/skin/skin_style_property.h"
namespace app {
namespace skin {
const char* SkinStyleProperty::Name = "SkinStyleProperty";
SkinStyleProperty::SkinStyleProperty(Style* style)
: Property(Name)
, m_style(style)
{
}
Style* SkinStyleProperty::getStyle() const
{
return m_style;
}
} // namespace skin
} // namespace app

View File

@ -0,0 +1,37 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_SKIN_SKIN_STYLE_PROPERTY_H_INCLUDED
#define APP_UI_SKIN_SKIN_STYLE_PROPERTY_H_INCLUDED
#pragma once
#include "app/ui/skin/skin_property.h"
#include "app/ui/skin/style.h"
#include "base/shared_ptr.h"
namespace app {
namespace skin {
class Style;
class SkinStyleProperty : public ui::Property {
public:
static const char* Name;
SkinStyleProperty(Style* style);
skin::Style* getStyle() const;
private:
skin::Style* m_style;
};
typedef SharedPtr<SkinStyleProperty> SkinStylePropertyPtr;
} // namespace skin
} // namespace app
#endif

View File

@ -17,6 +17,7 @@
#include "app/ui/skin/button_icon_impl.h"
#include "app/ui/skin/skin_property.h"
#include "app/ui/skin/skin_slider_property.h"
#include "app/ui/skin/skin_style_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui/skin/style_sheet.h"
@ -49,13 +50,9 @@ using namespace gfx;
using namespace ui;
static std::map<std::string, int> sheet_mapping;
static std::map<std::string, ThemeColor::Type> color_mapping;
const char* SkinTheme::kThemeCloseButtonId = "theme_close_button";
const char* kWindowFaceColorId = "window_face";
const char* kSeparatorLabelColorId = "separator_label";
// Controls the "X" button in a window to close it.
class WindowCloseButton : public Button {
public:
@ -138,9 +135,14 @@ static const char* cursor_names[kCursorTypes] = {
"magnifier" // kMagnifierCursor
};
// static
SkinTheme* SkinTheme::instance()
{
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme());
}
SkinTheme::SkinTheme()
: m_cursors(ui::kCursorTypes, NULL)
, m_colors(ThemeColor::MaxColors)
{
this->name = "Skin Theme";
m_selected_skin = get_config_string("Skin", "Selected", "default");
@ -210,11 +212,6 @@ SkinTheme::SkinTheme()
sheet_mapping["toolbutton_hot"] = PART_TOOLBUTTON_HOT_NW;
sheet_mapping["toolbutton_last"] = PART_TOOLBUTTON_LAST_NW;
sheet_mapping["toolbutton_pushed"] = PART_TOOLBUTTON_PUSHED_NW;
sheet_mapping["tab_normal"] = PART_TAB_NORMAL_NW;
sheet_mapping["tab_selected"] = PART_TAB_SELECTED_NW;
sheet_mapping["tab_bottom_selected"] = PART_TAB_BOTTOM_SELECTED_NW;
sheet_mapping["tab_bottom_normal"] = PART_TAB_BOTTOM_NORMAL;
sheet_mapping["tab_filler"] = PART_TAB_FILLER;
sheet_mapping["editor_normal"] = PART_EDITOR_NORMAL_NW;
sheet_mapping["editor_selected"] = PART_EDITOR_SELECTED_NW;
sheet_mapping["colorbar_0"] = PART_COLORBAR_0_NW;
@ -290,62 +287,6 @@ SkinTheme::SkinTheme()
sheet_mapping["freehand_algo_dots"] = PART_FREEHAND_ALGO_DOTS;
sheet_mapping["freehand_algo_dots_selected"] = PART_FREEHAND_ALGO_DOTS_SELECTED;
color_mapping["text"] = ThemeColor::Text;
color_mapping["disabled"] = ThemeColor::Disabled;
color_mapping["face"] = ThemeColor::Face;
color_mapping["hot_face"] = ThemeColor::HotFace;
color_mapping["selected"] = ThemeColor::Selected;
color_mapping["background"] = ThemeColor::Background;
color_mapping["textbox_text"] = ThemeColor::TextBoxText;
color_mapping["textbox_face"] = ThemeColor::TextBoxFace;
color_mapping["entry_suffix"] = ThemeColor::EntrySuffix;
color_mapping["link_text"] = ThemeColor::LinkText;
color_mapping["button_normal_text"] = ThemeColor::ButtonNormalText;
color_mapping["button_normal_face"] = ThemeColor::ButtonNormalFace;
color_mapping["button_hot_text"] = ThemeColor::ButtonHotText;
color_mapping["button_hot_face"] = ThemeColor::ButtonHotFace;
color_mapping["button_selected_text"] = ThemeColor::ButtonSelectedText;
color_mapping["button_selected_face"] = ThemeColor::ButtonSelectedFace;
color_mapping["check_hot_face"] = ThemeColor::CheckHotFace;
color_mapping["check_focus_face"] = ThemeColor::CheckFocusFace;
color_mapping["radio_hot_face"] = ThemeColor::RadioHotFace;
color_mapping["radio_focus_face"] = ThemeColor::RadioFocusFace;
color_mapping["menuitem_normal_text"] = ThemeColor::MenuItemNormalText;
color_mapping["menuitem_normal_face"] = ThemeColor::MenuItemNormalFace;
color_mapping["menuitem_hot_text"] = ThemeColor::MenuItemHotText;
color_mapping["menuitem_hot_face"] = ThemeColor::MenuItemHotFace;
color_mapping["menuitem_highlight_text"] = ThemeColor::MenuItemHighlightText;
color_mapping["menuitem_highlight_face"] = ThemeColor::MenuItemHighlightFace;
color_mapping["editor_face"] = ThemeColor::EditorFace;
color_mapping["editor_sprite_border"] = ThemeColor::EditorSpriteBorder;
color_mapping["editor_sprite_bottom_border"] = ThemeColor::EditorSpriteBottomBorder;
color_mapping["listitem_normal_text"] = ThemeColor::ListItemNormalText;
color_mapping["listitem_normal_face"] = ThemeColor::ListItemNormalFace;
color_mapping["listitem_selected_text"] = ThemeColor::ListItemSelectedText;
color_mapping["listitem_selected_face"] = ThemeColor::ListItemSelectedFace;
color_mapping["slider_empty_text"] = ThemeColor::SliderEmptyText;
color_mapping["slider_empty_face"] = ThemeColor::SliderEmptyFace;
color_mapping["slider_full_text"] = ThemeColor::SliderFullText;
color_mapping["slider_full_face"] = ThemeColor::SliderFullFace;
color_mapping["tab_normal_text"] = ThemeColor::TabNormalText;
color_mapping["tab_normal_face"] = ThemeColor::TabNormalFace;
color_mapping["tab_selected_text"] = ThemeColor::TabSelectedText;
color_mapping["tab_selected_face"] = ThemeColor::TabSelectedFace;
color_mapping["splitter_normal_face"] = ThemeColor::SplitterNormalFace;
color_mapping["scrollbar_bg_face"] = ThemeColor::ScrollBarBgFace;
color_mapping["scrollbar_thumb_face"] = ThemeColor::ScrollBarThumbFace;
color_mapping["popup_window_border"] = ThemeColor::PopupWindowBorder;
color_mapping["tooltip_text"] = ThemeColor::TooltipText;
color_mapping["tooltip_face"] = ThemeColor::TooltipFace;
color_mapping["filelist_even_row_text"] = ThemeColor::FileListEvenRowText;
color_mapping["filelist_even_row_face"] = ThemeColor::FileListEvenRowFace;
color_mapping["filelist_odd_row_text"] = ThemeColor::FileListOddRowText;
color_mapping["filelist_odd_row_face"] = ThemeColor::FileListOddRowFace;
color_mapping["filelist_selected_row_text"] = ThemeColor::FileListSelectedRowText;
color_mapping["filelist_selected_row_face"] = ThemeColor::FileListSelectedRowFace;
color_mapping["filelist_disabled_row_text"] = ThemeColor::FileListDisabledRowText;
color_mapping["workspace"] = ThemeColor::Workspace;
reload_skin();
}
@ -366,7 +307,6 @@ SkinTheme::~SkinTheme()
m_part.clear();
m_parts_by_id.clear();
sheet_mapping.clear();
color_mapping.clear();
// Destroy the minifont
if (m_minifont)
@ -433,6 +373,23 @@ void SkinTheme::onRegenerate()
XmlDocumentRef doc = open_xml(rf.filename());
TiXmlHandle handle(doc);
// Load dimension
{
TiXmlElement* xmlDim = handle
.FirstChild("skin")
.FirstChild("dimensions")
.FirstChild("dim").ToElement();
while (xmlDim) {
std::string id = xmlDim->Attribute("id");
uint32_t value = strtol(xmlDim->Attribute("value"), NULL, 10);
PRINTF("Loading dimension '%s'...\n", id.c_str());
m_dimensions_by_id[id] = value;
xmlDim = xmlDim->NextSiblingElement();
}
}
// Load colors
{
TiXmlElement* xmlColor = handle
@ -450,12 +407,6 @@ void SkinTheme::onRegenerate()
PRINTF("Loading color '%s'...\n", id.c_str());
m_colors_by_id[id] = color;
std::map<std::string, ThemeColor::Type>::iterator it = color_mapping.find(id);
if (it != color_mapping.end()) {
m_colors[it->second] = color;
}
xmlColor = xmlColor->NextSiblingElement();
}
}
@ -612,6 +563,7 @@ void SkinTheme::onRegenerate()
int align = 0;
const char* halign = xmlRule->Attribute("align");
const char* valign = xmlRule->Attribute("valign");
const char* wordwrap = xmlRule->Attribute("wordwrap");
if (halign) {
if (strcmp(halign, "left") == 0) align |= JI_LEFT;
else if (strcmp(halign, "right") == 0) align |= JI_RIGHT;
@ -622,28 +574,39 @@ void SkinTheme::onRegenerate()
else if (strcmp(valign, "bottom") == 0) align |= JI_BOTTOM;
else if (strcmp(valign, "middle") == 0) align |= JI_MIDDLE;
}
if (wordwrap && strcmp(wordwrap, "true") == 0)
align |= JI_WORDWRAP;
if (ruleName == "background") {
const char* repeat_id = xmlRule->Attribute("repeat");
if (color_id) (*style)[StyleSheet::backgroundColorRule()] = css::Value(color_id);
if (part_id) (*style)[StyleSheet::backgroundPartRule()] = css::Value(part_id);
if (repeat_id) (*style)[StyleSheet::backgroundRepeatRule()] = css::Value(repeat_id);
}
else if (ruleName == "icon") {
if (align) (*style)[StyleSheet::iconAlignRule()] = css::Value(align);
if (part_id) (*style)[StyleSheet::iconPartRule()] = css::Value(part_id);
const char* x = xmlRule->Attribute("x");
const char* y = xmlRule->Attribute("y");
if (x) (*style)[StyleSheet::iconXRule()] = css::Value(strtol(x, NULL, 10));
if (y) (*style)[StyleSheet::iconYRule()] = css::Value(strtol(y, NULL, 10));
}
else if (ruleName == "text") {
if (color_id) (*style)[StyleSheet::textColorRule()] = css::Value(color_id);
if (align) (*style)[StyleSheet::textAlignRule()] = css::Value(align);
const char* padding_left = xmlRule->Attribute("padding-left");
const char* padding_top = xmlRule->Attribute("padding-top");
const char* padding_right = xmlRule->Attribute("padding-right");
const char* padding_bottom = xmlRule->Attribute("padding-bottom");
const char* l = xmlRule->Attribute("padding-left");
const char* t = xmlRule->Attribute("padding-top");
const char* r = xmlRule->Attribute("padding-right");
const char* b = xmlRule->Attribute("padding-bottom");
if (padding_left) (*style)[StyleSheet::paddingLeftRule()] = css::Value(strtol(padding_left, NULL, 10));
if (padding_top) (*style)[StyleSheet::paddingTopRule()] = css::Value(strtol(padding_top, NULL, 10));
if (padding_right) (*style)[StyleSheet::paddingRightRule()] = css::Value(strtol(padding_right, NULL, 10));
if (padding_bottom) (*style)[StyleSheet::paddingBottomRule()] = css::Value(strtol(padding_bottom, NULL, 10));
if (l) (*style)[StyleSheet::paddingLeftRule()] = css::Value(strtol(l, NULL, 10));
if (t) (*style)[StyleSheet::paddingTopRule()] = css::Value(strtol(t, NULL, 10));
if (r) (*style)[StyleSheet::paddingRightRule()] = css::Value(strtol(r, NULL, 10));
if (b) (*style)[StyleSheet::paddingBottomRule()] = css::Value(strtol(b, NULL, 10));
}
xmlRule = xmlRule->NextSiblingElement();
@ -652,6 +615,8 @@ void SkinTheme::onRegenerate()
xmlStyle = xmlStyle->NextSiblingElement();
}
}
SkinFile<SkinTheme>::updateInternals();
}
she::Surface* SkinTheme::sliceSheet(she::Surface* sur, const gfx::Rect& bounds)
@ -745,7 +710,6 @@ void SkinTheme::initWidget(Widget* widget)
case kLabelWidget:
BORDER(1 * scale);
static_cast<Label*>(widget)->setTextColor(getColor(ThemeColor::Text));
break;
case kListBoxWidget:
@ -855,7 +819,7 @@ void SkinTheme::initWidget(Widget* widget)
m_part[PART_SUNKEN_NORMAL_E]->width()-1*scale,
m_part[PART_SUNKEN_NORMAL_S]->height()-1*scale);
widget->child_spacing = 0;
widget->setBgColor(getColorById(kWindowFaceColorId));
widget->setBgColor(colors.windowFace());
break;
case kViewScrollbarWidget:
@ -887,7 +851,7 @@ void SkinTheme::initWidget(Widget* widget)
BORDER(0);
}
widget->child_spacing = 4 * scale; // TODO this hard-coded 4 should be configurable in skin.xml
widget->setBgColor(getColorById(kWindowFaceColorId));
widget->setBgColor(colors.windowFace());
break;
default:
@ -920,7 +884,7 @@ void SkinTheme::paintDesktop(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
g->fillRect(getColor(ThemeColor::Disabled), g->getClipBounds());
g->fillRect(colors.disabled(), g->getClipBounds());
}
void SkinTheme::paintBox(PaintEvent& ev)
@ -954,8 +918,8 @@ void SkinTheme::paintButton(PaintEvent& ev)
// Selected
if (widget->isSelected()) {
fg = getColor(ThemeColor::ButtonSelectedText);
bg = getColor(ThemeColor::ButtonSelectedFace);
fg = colors.buttonSelectedText();
bg = colors.buttonSelectedFace();
part_nw = (look == MiniLook ? PART_TOOLBUTTON_NORMAL_NW:
look == LeftButtonLook ? PART_DROP_DOWN_BUTTON_LEFT_SELECTED_NW:
look == RightButtonLook ? PART_DROP_DOWN_BUTTON_RIGHT_SELECTED_NW:
@ -963,8 +927,8 @@ void SkinTheme::paintButton(PaintEvent& ev)
}
// With mouse
else if (widget->isEnabled() && widget->hasMouseOver()) {
fg = getColor(ThemeColor::ButtonHotText);
bg = getColor(ThemeColor::ButtonHotFace);
fg = colors.buttonHotText();
bg = colors.buttonHotFace();
part_nw = (look == MiniLook ? PART_TOOLBUTTON_HOT_NW:
look == LeftButtonLook ? PART_DROP_DOWN_BUTTON_LEFT_HOT_NW:
look == RightButtonLook ? PART_DROP_DOWN_BUTTON_RIGHT_HOT_NW:
@ -972,8 +936,8 @@ void SkinTheme::paintButton(PaintEvent& ev)
}
// Without mouse
else {
fg = getColor(ThemeColor::ButtonNormalText);
bg = getColor(ThemeColor::ButtonNormalFace);
fg = colors.buttonNormalText();
bg = colors.buttonNormalFace();
if (widget->hasFocus())
part_nw = (look == MiniLook ? PART_TOOLBUTTON_HOT_NW:
@ -1033,9 +997,9 @@ void SkinTheme::paintCheckBox(PaintEvent& ev)
// Mouse
if (widget->isEnabled()) {
if (widget->hasMouseOver())
g->fillRect(bg = getColor(ThemeColor::CheckHotFace), bounds);
g->fillRect(bg = colors.checkHotFace(), bounds);
else if (widget->hasFocus())
g->fillRect(bg = getColor(ThemeColor::CheckFocusFace), bounds);
g->fillRect(bg = colors.checkFocusFace(), bounds);
}
// Text
@ -1081,7 +1045,7 @@ void SkinTheme::paintEntry(PaintEvent& ev)
if (skinPropery != NULL)
isMiniLook = (skinPropery->getLook() == MiniLook);
gfx::Color bg = getColor(ThemeColor::Background);
gfx::Color bg = colors.background();
draw_bounds_nw(g, bounds,
(widget->hasFocus() ?
(isMiniLook ? PART_SUNKEN_MINI_FOCUSED_NW: PART_SUNKEN_FOCUSED_NW):
@ -1100,21 +1064,21 @@ void SkinTheme::paintEntry(PaintEvent& ev)
// Normal text
bg = ColorNone;
gfx::Color fg = getColor(ThemeColor::Text);
gfx::Color fg = colors.text();
// Selected
if ((c >= selbeg) && (c <= selend)) {
if (widget->hasFocus())
bg = getColor(ThemeColor::Selected);
bg = colors.selected();
else
bg = getColor(ThemeColor::Disabled);
fg = getColor(ThemeColor::Background);
bg = colors.disabled();
fg = colors.background();
}
// Disabled
if (!widget->isEnabled()) {
bg = ColorNone;
fg = getColor(ThemeColor::Disabled);
fg = colors.disabled();
}
// Suffix
@ -1123,7 +1087,7 @@ void SkinTheme::paintEntry(PaintEvent& ev)
break;
bg = ColorNone;
fg = getColor(ThemeColor::EntrySuffix);
fg = colors.entrySuffix();
}
w = g->measureChar(ch).w;
@ -1151,43 +1115,48 @@ void SkinTheme::paintLabel(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
Label* widget = static_cast<Label*>(ev.getSource());
Style* style = styles.label();
gfx::Color bg = BGCOLOR;
gfx::Color fg = widget->getTextColor();
Rect text, rc = widget->getClientBounds();
SkinStylePropertyPtr styleProp = widget->getProperty(SkinStyleProperty::Name);
if (styleProp)
style = styleProp->getStyle();
if (!is_transparent(bg))
g->fillRect(bg, rc);
rc.shrink(widget->getBorder());
widget->getTextIconInfo(NULL, &text);
g->drawUIString(widget->getText(), fg, ColorNone, text.getOrigin());
style->paint(g, text, widget->getText().c_str(), Style::State());
}
void SkinTheme::paintLinkLabel(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
Widget* widget = static_cast<Widget*>(ev.getSource());
Style* style = styles.link();
gfx::Rect bounds = widget->getClientBounds();
gfx::Color fg = getColor(ThemeColor::LinkText);
gfx::Color bg = BGCOLOR;
g->fillRect(bg, bounds);
drawTextString(g, NULL, fg, ColorNone, widget, bounds, 0);
SkinStylePropertyPtr styleProp = widget->getProperty(SkinStyleProperty::Name);
if (styleProp)
style = styleProp->getStyle();
// Underline style
if (widget->hasMouseOver()) {
int w = widget->getTextWidth();
for (int v=0; v<guiscale(); ++v)
g->drawHLine(fg, bounds.x, bounds.y2()-1-v, w);
}
Style::State state;
if (widget->hasMouseOver()) state += Style::hover();
if (widget->isSelected()) state += Style::clicked();
g->fillRect(bg, bounds);
style->paint(g, bounds, widget->getText().c_str(), state);
}
void SkinTheme::paintListBox(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
g->fillRect(getColor(ThemeColor::Background), g->getClipBounds());
g->fillRect(colors.background(), g->getClipBounds());
}
void SkinTheme::paintListItem(ui::PaintEvent& ev)
@ -1198,16 +1167,16 @@ void SkinTheme::paintListItem(ui::PaintEvent& ev)
gfx::Color fg, bg;
if (!widget->isEnabled()) {
bg = getColor(ThemeColor::Face);
fg = getColor(ThemeColor::Disabled);
bg = colors.face();
fg = colors.disabled();
}
else if (widget->isSelected()) {
fg = getColor(ThemeColor::ListItemSelectedText);
bg = getColor(ThemeColor::ListItemSelectedFace);
fg = colors.listitemSelectedText();
bg = colors.listitemSelectedFace();
}
else {
fg = getColor(ThemeColor::ListItemNormalText);
bg = getColor(ThemeColor::ListItemNormalFace);
fg = colors.listitemNormalText();
bg = colors.listitemNormalFace();
}
g->fillRect(bg, bounds);
@ -1244,20 +1213,20 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
// Colors
if (!widget->isEnabled()) {
fg = ColorNone;
bg = getColor(ThemeColor::MenuItemNormalFace);
bg = colors.menuitemNormalFace();
}
else {
if (widget->isHighlighted()) {
fg = getColor(ThemeColor::MenuItemHighlightText);
bg = getColor(ThemeColor::MenuItemHighlightFace);
fg = colors.menuitemHighlightText();
bg = colors.menuitemHighlightFace();
}
else if (widget->hasMouse()) {
fg = getColor(ThemeColor::MenuItemHotText);
bg = getColor(ThemeColor::MenuItemHotFace);
fg = colors.menuitemHotText();
bg = colors.menuitemHotFace();
}
else {
fg = getColor(ThemeColor::MenuItemNormalText);
bg = getColor(ThemeColor::MenuItemNormalFace);
fg = colors.menuitemNormalText();
bg = colors.menuitemNormalFace();
}
}
@ -1301,12 +1270,12 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
// Disabled
else {
for (c=0; c<3*scale; c++)
g->drawVLine(getColor(ThemeColor::Background),
g->drawVLine(colors.background(),
bounds.x2()-3*scale-c+1,
bounds.y+bounds.h/2-c+1, 2*c+1);
for (c=0; c<3*scale; c++)
g->drawVLine(getColor(ThemeColor::Disabled),
g->drawVLine(colors.disabled(),
bounds.x2()-3*scale-c,
bounds.y+bounds.h/2-c, 2*c+1);
}
@ -1333,7 +1302,7 @@ void SkinTheme::paintSplitter(PaintEvent& ev)
{
Graphics* g = ev.getGraphics();
g->fillRect(getColor(ThemeColor::SplitterNormalFace), g->getClipBounds());
g->fillRect(colors.splitterNormalFace(), g->getClipBounds());
}
void SkinTheme::paintRadioButton(PaintEvent& ev)
@ -1356,9 +1325,9 @@ void SkinTheme::paintRadioButton(PaintEvent& ev)
// Mouse
if (widget->isEnabled()) {
if (widget->hasMouseOver())
g->fillRect(bg = getColor(ThemeColor::RadioHotFace), bounds);
g->fillRect(bg = colors.radioHotFace(), bounds);
else if (widget->hasFocus())
g->fillRect(bg = getColor(ThemeColor::RadioFocusFace), bounds);
g->fillRect(bg = colors.radioFocusFace(), bounds);
}
// Text
@ -1400,7 +1369,7 @@ void SkinTheme::paintSeparator(ui::PaintEvent& ev)
bounds.y2() - widget->border_width.b/2 + h));
drawTextString(g, NULL,
getColorById(kSeparatorLabelColorId), BGCOLOR,
colors.separatorLabel(), BGCOLOR,
widget, r, 0);
}
}
@ -1489,14 +1458,14 @@ void SkinTheme::paintSlider(PaintEvent& ev)
}
if (value == min)
draw_bounds_nw(g, rc, empty_part_nw, getColor(ThemeColor::SliderEmptyFace));
draw_bounds_nw(g, rc, empty_part_nw, colors.sliderEmptyFace());
else if (value == max)
draw_bounds_nw(g, rc, full_part_nw, getColor(ThemeColor::SliderFullFace));
draw_bounds_nw(g, rc, full_part_nw, colors.sliderFullFace());
else
draw_bounds_nw2(g, rc, x,
full_part_nw, empty_part_nw,
getColor(ThemeColor::SliderFullFace),
getColor(ThemeColor::SliderEmptyFace));
full_part_nw, empty_part_nw,
colors.sliderFullFace(),
colors.sliderEmptyFace());
// Draw text
std::string old_text = widget->getText();
@ -1511,7 +1480,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
IntersectClip clip(g, Rect(rc.x, rc.y, x-rc.x, rc.h));
if (clip) {
drawTextString(g, NULL,
getColor(ThemeColor::SliderFullText), ColorNone,
colors.sliderFullText(), ColorNone,
widget, rc, 0);
}
}
@ -1520,7 +1489,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
IntersectClip clip(g, Rect(x+1, rc.y, rc.w-(x-rc.x+1), rc.h));
if (clip) {
drawTextString(g, NULL,
getColor(ThemeColor::SliderEmptyText),
colors.sliderEmptyText(),
ColorNone, widget, rc, 0);
}
}
@ -1545,7 +1514,7 @@ void SkinTheme::paintComboBoxEntry(ui::PaintEvent& ev)
// Outside borders
g->fillRect(BGCOLOR, bounds);
gfx::Color fg, bg = getColor(ThemeColor::Background);
gfx::Color fg, bg = colors.background();
draw_bounds_nw(g, bounds,
widget->hasFocus() ?
@ -1564,21 +1533,21 @@ void SkinTheme::paintComboBoxEntry(ui::PaintEvent& ev)
// Normal text
bg = ColorNone;
fg = getColor(ThemeColor::Text);
fg = colors.text();
// Selected
if ((c >= selbeg) && (c <= selend)) {
if (widget->hasFocus())
bg = getColor(ThemeColor::Selected);
bg = colors.selected();
else
bg = getColor(ThemeColor::Disabled);
fg = getColor(ThemeColor::Background);
bg = colors.disabled();
fg = colors.background();
}
// Disabled
if (!widget->isEnabled()) {
bg = ColorNone;
fg = getColor(ThemeColor::Disabled);
fg = colors.disabled();
}
w = g->measureChar(ch).w;
@ -1611,17 +1580,17 @@ void SkinTheme::paintComboBoxButton(PaintEvent& ev)
gfx::Color bg;
if (widget->isSelected()) {
bg = getColor(ThemeColor::ButtonSelectedFace);
bg = colors.buttonSelectedFace();
part_nw = PART_TOOLBUTTON_PUSHED_NW;
}
// With mouse
else if (widget->isEnabled() && widget->hasMouseOver()) {
bg = getColor(ThemeColor::ButtonHotFace);
bg = colors.buttonHotFace();
part_nw = PART_TOOLBUTTON_HOT_NW;
}
// Without mouse
else {
bg = getColor(ThemeColor::ButtonNormalFace);
bg = colors.buttonNormalFace();
part_nw = PART_TOOLBUTTON_LAST_NW;
}
@ -1649,8 +1618,8 @@ void SkinTheme::paintTextBox(ui::PaintEvent& ev)
Widget* widget = static_cast<Widget*>(ev.getSource());
drawTextBox(g, widget, NULL, NULL,
getColor(ThemeColor::TextBoxFace),
getColor(ThemeColor::TextBoxText));
colors.textboxFace(),
colors.textboxText());
}
void SkinTheme::paintView(PaintEvent& ev)
@ -1659,15 +1628,19 @@ void SkinTheme::paintView(PaintEvent& ev)
View* widget = static_cast<View*>(ev.getSource());
gfx::Rect bounds = widget->getClientBounds();
gfx::Color bg = BGCOLOR;
Style* style = styles.view();
SkinStylePropertyPtr styleProp = widget->getProperty(SkinStyleProperty::Name);
if (styleProp)
style = styleProp->getStyle();
Style::State state;
if (widget->hasMouseOver()) state += Style::hover();
if (!is_transparent(bg))
g->fillRect(bg, bounds);
draw_bounds_nw(g, bounds,
(widget->hasFocus() ?
PART_SUNKEN_FOCUSED_NW:
PART_SUNKEN_NORMAL_NW),
BGCOLOR);
style->paint(g, bounds, nullptr, state);
}
void SkinTheme::paintViewScrollbar(PaintEvent& ev)
@ -1681,8 +1654,13 @@ void SkinTheme::paintViewScrollbar(PaintEvent& ev)
if (skinPropery != NULL)
isMiniLook = (skinPropery->getLook() == MiniLook);
skin::Style* bgStyle = get_style(isMiniLook ? "mini_scrollbar": "scrollbar");
skin::Style* thumbStyle = get_style(isMiniLook ? "mini_scrollbar_thumb": "scrollbar_thumb");
skin::Style* bgStyle = (isMiniLook ?
styles.miniScrollbar():
styles.scrollbar());
skin::Style* thumbStyle = (isMiniLook ?
styles.miniScrollbarThumb():
styles.scrollbarThumb());
widget->getScrollBarThemeInfo(&pos, &len);
@ -1724,20 +1702,20 @@ void SkinTheme::paintWindow(PaintEvent& ev)
if (!window->isDesktop()) {
// window frame
if (window->hasText()) {
get_style("window")->paint(g, pos, NULL, Style::State());
get_style("window_title")->paint(g,
styles.window()->paint(g, pos, NULL, Style::State());
styles.windowTitle()->paint(g,
gfx::Rect(cpos.x, pos.y+5*guiscale(), cpos.w, // TODO this hard-coded 5 should be configurable in skin.xml
window->getTextHeight()),
window->getText().c_str(), Style::State());
}
// menubox
else {
get_style("menubox")->paint(g, pos, NULL, Style::State());
styles.menubox()->paint(g, pos, NULL, Style::State());
}
}
// desktop
else {
get_style("desktop")->paint(g, pos, NULL, Style::State());
styles.desktop()->paint(g, pos, NULL, Style::State());
}
}
@ -1749,12 +1727,12 @@ void SkinTheme::paintPopupWindow(PaintEvent& ev)
gfx::Rect pos = window->getClientBounds();
if (!is_transparent(BGCOLOR))
get_style("menubox")->paint(g, pos, NULL, Style::State());
styles.menubox()->paint(g, pos, NULL, Style::State());
pos.shrink(window->getBorder());
g->drawAlignedUIString(window->getText(),
getColor(ThemeColor::Text),
colors.text(),
window->getBgColor(), pos,
window->getAlign());
}
@ -1781,8 +1759,8 @@ void SkinTheme::paintTooltip(PaintEvent& ev)
ui::TipWindow* widget = static_cast<ui::TipWindow*>(ev.getSource());
Graphics* g = ev.getGraphics();
Rect rc = widget->getClientBounds();
gfx::Color fg = getColor(ThemeColor::TooltipText);
gfx::Color bg = getColor(ThemeColor::TooltipFace);
gfx::Color fg = colors.tooltipText();
gfx::Color bg = colors.tooltipFace();
int nw = PART_TOOLTIP_NW;
int n = PART_TOOLTIP_N;
@ -1853,9 +1831,9 @@ gfx::Color SkinTheme::getWidgetBgColor(Widget* widget)
if (!is_transparent(c) || widget->getType() == kWindowWidget)
return c;
else if (decorative)
return getColor(ThemeColor::Selected);
return colors.selected();
else
return getColor(ThemeColor::Face);
return colors.face();
}
void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
@ -1914,16 +1892,16 @@ void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color,
if (!widget->isEnabled()) {
// Draw white part
g->drawUIString(t,
getColor(ThemeColor::Background),
colors.background(),
gfx::ColorNone,
textrc.getOrigin() + Point(guiscale(), guiscale()));
}
g->drawUIString(t,
(!widget->isEnabled() ?
getColor(ThemeColor::Disabled):
colors.disabled():
(gfx::geta(fg_color) > 0 ? fg_color :
getColor(ThemeColor::Text))),
colors.text())),
bg_color, textrc.getOrigin());
}
}
@ -1931,7 +1909,7 @@ void SkinTheme::drawTextString(Graphics* g, const char *t, gfx::Color fg_color,
void SkinTheme::drawEntryCaret(ui::Graphics* g, Entry* widget, int x, int y)
{
gfx::Color color = getColor(ThemeColor::Text);
gfx::Color color = colors.text();
int h = widget->getTextHeight();
for (int u=x; u<x+2*guiscale(); ++u)
@ -2142,7 +2120,7 @@ void SkinTheme::draw_part_as_vline(ui::Graphics* g, const gfx::Rect& rc, int par
void SkinTheme::paintProgressBar(ui::Graphics* g, const gfx::Rect& rc0, double progress)
{
g->drawRect(getColor(ThemeColor::Text), rc0);
g->drawRect(colors.text(), rc0);
gfx::Rect rc = rc0;
rc.shrink(1);
@ -2151,10 +2129,10 @@ void SkinTheme::paintProgressBar(ui::Graphics* g, const gfx::Rect& rc0, double p
u = MID(0, u, rc.w);
if (u > 0)
g->fillRect(getColor(ThemeColor::Selected), gfx::Rect(rc.x, rc.y, u, rc.h));
g->fillRect(colors.selected(), gfx::Rect(rc.x, rc.y, u, rc.h));
if (1+u < rc.w)
g->fillRect(getColor(ThemeColor::Background), gfx::Rect(rc.x+u, rc.y, rc.w-u, rc.h));
g->fillRect(colors.background(), gfx::Rect(rc.x+u, rc.y, rc.w-u, rc.h));
}
void SkinTheme::paintIcon(Widget* widget, Graphics* g, IButtonIcon* iconInterface, int x, int y)

View File

@ -17,6 +17,8 @@
#include "ui/manager.h"
#include "ui/theme.h"
#include "generated_skin.h"
#include <map>
#include <string>
@ -33,82 +35,18 @@ namespace she {
namespace app {
namespace skin {
namespace ThemeColor {
enum Type {
Text,
Disabled,
Face,
HotFace,
Selected,
Background,
TextBoxText,
TextBoxFace,
EntrySuffix,
LinkText,
ButtonNormalText,
ButtonNormalFace,
ButtonHotText,
ButtonHotFace,
ButtonSelectedText,
ButtonSelectedFace,
CheckHotFace,
CheckFocusFace,
RadioHotFace,
RadioFocusFace,
MenuItemNormalText,
MenuItemNormalFace,
MenuItemHotText,
MenuItemHotFace,
MenuItemHighlightText,
MenuItemHighlightFace,
EditorFace,
EditorSpriteBorder,
EditorSpriteBottomBorder,
ListItemNormalText,
ListItemNormalFace,
ListItemSelectedText,
ListItemSelectedFace,
SliderEmptyText,
SliderEmptyFace,
SliderFullText,
SliderFullFace,
TabNormalText,
TabNormalFace,
TabSelectedText,
TabSelectedFace,
SplitterNormalFace,
ScrollBarBgFace,
ScrollBarThumbFace,
PopupWindowBorder,
TooltipText,
TooltipFace,
FileListEvenRowText,
FileListEvenRowFace,
FileListOddRowText,
FileListOddRowFace,
FileListSelectedRowText,
FileListSelectedRowFace,
FileListDisabledRowText,
Workspace,
MaxColors
};
}
extern const char* kWindowFaceColorId;
// This is the GUI theme used by Aseprite (which use images from
// data/skins directory).
class SkinTheme : public ui::Theme {
class SkinTheme : public ui::Theme
, public app::gen::SkinFile<SkinTheme> {
public:
static const char* kThemeCloseButtonId;
static SkinTheme* instance();
SkinTheme();
~SkinTheme();
gfx::Color getColor(ThemeColor::Type k) const {
return m_colors[k];
}
she::Font* getMiniFont() const { return m_minifont; }
void reload_skin();
@ -170,7 +108,12 @@ namespace app {
return m_parts_by_id[id];
}
int getDimensionById(const std::string& id) {
return m_dimensions_by_id[id] * ui::guiscale();
}
gfx::Color getColorById(const std::string& id) {
ASSERT(m_colors_by_id.find(id) != m_colors_by_id.end());
return m_colors_by_id[id];
}
@ -203,16 +146,12 @@ namespace app {
std::map<std::string, SkinPartPtr> m_parts_by_id;
std::map<std::string, she::Surface*> m_toolicon;
std::map<std::string, gfx::Color> m_colors_by_id;
std::map<std::string, int> m_dimensions_by_id;
std::vector<ui::Cursor*> m_cursors;
std::vector<gfx::Color> m_colors;
StyleSheet m_stylesheet;
she::Font* m_minifont;
};
inline Style* get_style(const std::string& id) {
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme())->getStyle(id);
}
inline SkinPartPtr get_part_by_id(const std::string& id) {
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme())->getPartById(id);
}

View File

@ -44,7 +44,26 @@ void BackgroundRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const cha
if (!gfx::is_transparent(m_color))
g->fillRect(m_color, bounds);
g->drawRgbaSurface(m_part->getBitmap(0), bounds.x, bounds.y);
she::Surface* bmp = m_part->getBitmap(0);
if (m_repeat == BackgroundRepeat::NO_REPEAT) {
g->drawRgbaSurface(bmp, bounds.x, bounds.y);
}
else {
ui::IntersectClip clip(g, bounds);
if (!clip)
return;
for (int y=bounds.y; y<bounds.y2(); y+=bmp->height()) {
for (int x=bounds.x; x<bounds.x2(); x+=bmp->width()) {
g->drawRgbaSurface(bmp, x, y);
if (m_repeat == BackgroundRepeat::REPEAT_Y)
break;
}
if (m_repeat == BackgroundRepeat::REPEAT_X)
break;
}
}
}
else if (m_part->size() == 8) {
theme->draw_bounds_nw(g, bounds, m_part, m_color);
@ -62,7 +81,7 @@ void TextRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* tex
if (text) {
g->drawAlignedUIString(text,
(gfx::is_transparent(m_color) ?
theme->getColor(ThemeColor::Text):
theme->colors.text():
m_color),
gfx::ColorNone,
gfx::Rect(bounds).shrink(m_padding), m_align);
@ -88,6 +107,9 @@ void IconRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* tex
else
y = bounds.y;
x += m_x;
y += m_y;
g->drawRgbaSurface(bmp, x, y);
}
@ -98,8 +120,11 @@ Rules::Rules(const css::Query& query) :
{
css::Value backgroundColor = query[StyleSheet::backgroundColorRule()];
css::Value backgroundPart = query[StyleSheet::backgroundPartRule()];
css::Value backgroundRepeat = query[StyleSheet::backgroundRepeatRule()];
css::Value iconAlign = query[StyleSheet::iconAlignRule()];
css::Value iconPart = query[StyleSheet::iconPartRule()];
css::Value iconX = query[StyleSheet::iconXRule()];
css::Value iconY = query[StyleSheet::iconYRule()];
css::Value textAlign = query[StyleSheet::textAlignRule()];
css::Value textColor = query[StyleSheet::textColorRule()];
css::Value paddingLeft = query[StyleSheet::paddingLeftRule()];
@ -109,17 +134,23 @@ Rules::Rules(const css::Query& query) :
css::Value none;
if (backgroundColor != none
|| backgroundPart != none) {
|| backgroundPart != none
|| backgroundRepeat != none) {
m_background = new BackgroundRule();
m_background->setColor(StyleSheet::convertColor(backgroundColor));
m_background->setPart(StyleSheet::convertPart(backgroundPart));
m_background->setRepeat(StyleSheet::convertRepeat(backgroundRepeat));
}
if (iconAlign != none
|| iconPart != none) {
|| iconPart != none
|| iconX != none
|| iconY != none) {
m_icon = new IconRule();
m_icon->setAlign((int)iconAlign.number());
m_icon->setPart(StyleSheet::convertPart(iconPart));
m_icon->setX((int)iconX.number()*ui::guiscale());
m_icon->setY((int)iconY.number()*ui::guiscale());
}
if (textAlign != none
@ -155,7 +186,7 @@ void Rules::paint(ui::Graphics* g,
if (m_text) m_text->paint(g, bounds, text);
}
gfx::Size Rules::preferredSize(const char* text)
gfx::Size Rules::preferredSize(const char* text, int maxWidth)
{
gfx::Size sz(0, 0);
if (m_icon) {
@ -164,10 +195,13 @@ gfx::Size Rules::preferredSize(const char* text)
}
if (m_text && text) {
ui::ScreenGraphics g;
gfx::Size textSize = g.measureUIString(text);
//if (sz.w > 0) sz.w += 2; // TODO text separation
gfx::Size textSize = g.fitString(text, maxWidth, m_text->align());
if (sz.w > 0) sz.w += 2*ui::guiscale(); // TODO text separation
sz.w += textSize.w;
sz.h = MAX(sz.h, textSize.h);
sz.w += m_text->padding().left() + m_text->padding().right();
sz.h += m_text->padding().top() + m_text->padding().bottom();
}
return sz;
}
@ -212,9 +246,10 @@ void Style::paint(ui::Graphics* g,
gfx::Size Style::preferredSize(
const char* text,
const State& state)
const State& state,
int maxWidth)
{
return getRulesFromState(state)->preferredSize(text);
return getRulesFromState(state)->preferredSize(text, maxWidth);
}
} // namespace skin

View File

@ -9,6 +9,7 @@
#define APP_UI_SKIN_STYLE_H_INCLUDED
#pragma once
#include "app/ui/skin/background_repeat.h"
#include "app/ui/skin/skin_part.h"
#include "base/disable_copying.h"
#include "css/compound_style.h"
@ -44,10 +45,12 @@ namespace app {
class BackgroundRule : public Rule {
public:
BackgroundRule() : m_color(gfx::ColorNone) { }
BackgroundRule() : m_color(gfx::ColorNone)
, m_repeat(BackgroundRepeat::NO_REPEAT) { }
void setColor(gfx::Color color) { m_color = color; }
void setPart(const SkinPartPtr& part) { m_part = part; }
void setRepeat(BackgroundRepeat repeat) { m_repeat = repeat; }
protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) override;
@ -55,6 +58,7 @@ namespace app {
private:
gfx::Color m_color;
SkinPartPtr m_part;
BackgroundRepeat m_repeat;
};
class TextRule : public Rule {
@ -66,6 +70,9 @@ namespace app {
void setColor(gfx::Color color) { m_color = color; }
void setPadding(const gfx::Border& padding) { m_padding = padding; }
int align() const { return m_align; }
gfx::Border padding() const { return m_padding; }
protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) override;
@ -81,6 +88,8 @@ namespace app {
void setAlign(int align) { m_align = align; }
void setPart(const SkinPartPtr& part) { m_part = part; }
void setX(int x) { m_x = x; }
void setY(int y) { m_y = y; }
SkinPartPtr getPart() { return m_part; }
@ -90,6 +99,7 @@ namespace app {
private:
int m_align;
SkinPartPtr m_part;
int m_x, m_y;
};
class Rules {
@ -101,7 +111,7 @@ namespace app {
const gfx::Rect& bounds,
const char* text);
gfx::Size preferredSize(const char* text);
gfx::Size preferredSize(const char* text, int maxWidth);
private:
BackgroundRule* m_background;
@ -129,7 +139,8 @@ namespace app {
gfx::Size preferredSize(
const char* text,
const State& state);
const State& state,
int maxWidth = 0);
const std::string& id() const { return m_id; }

View File

@ -23,8 +23,11 @@ namespace skin {
css::Rule StyleSheet::m_backgroundColorRule("background-color");
css::Rule StyleSheet::m_backgroundPartRule("background-part");
css::Rule StyleSheet::m_backgroundRepeatRule("background-repeat");
css::Rule StyleSheet::m_iconAlignRule("icon-align");
css::Rule StyleSheet::m_iconPartRule("icon-part");
css::Rule StyleSheet::m_iconXRule("icon-x");
css::Rule StyleSheet::m_iconYRule("icon-y");
css::Rule StyleSheet::m_textAlignRule("text-align");
css::Rule StyleSheet::m_textColorRule("text-color");
css::Rule StyleSheet::m_paddingLeftRule("padding-left");
@ -37,8 +40,11 @@ StyleSheet::StyleSheet()
m_sheet = new css::Sheet;
m_sheet->addRule(&m_backgroundColorRule);
m_sheet->addRule(&m_backgroundPartRule);
m_sheet->addRule(&m_backgroundRepeatRule);
m_sheet->addRule(&m_iconAlignRule);
m_sheet->addRule(&m_iconPartRule);
m_sheet->addRule(&m_iconXRule);
m_sheet->addRule(&m_iconYRule);
m_sheet->addRule(&m_textAlignRule);
m_sheet->addRule(&m_textColorRule);
m_sheet->addRule(&m_paddingLeftRule);
@ -114,5 +120,25 @@ gfx::Color StyleSheet::convertColor(const css::Value& value)
return color;
}
// static
BackgroundRepeat StyleSheet::convertRepeat(const css::Value& value)
{
BackgroundRepeat repeat = BackgroundRepeat::NO_REPEAT;
if (value.type() == css::Value::String) {
const std::string& id = value.string();
if (id == "repeat")
repeat = BackgroundRepeat::REPEAT;
else if (id == "repeat-x")
repeat = BackgroundRepeat::REPEAT_X;
else if (id == "repeat-y")
repeat = BackgroundRepeat::REPEAT_Y;
else if (id == "no_repeat")
repeat = BackgroundRepeat::NO_REPEAT;
else
throw base::Exception("Unknown repeat value '%s'\n", id.c_str());
}
return repeat;
}
} // namespace skin
} // namespace app

View File

@ -9,6 +9,7 @@
#define APP_UI_SKIN_STYLE_SHEET_H_INCLUDED
#pragma once
#include "app/ui/skin/background_repeat.h"
#include "app/ui/skin/skin_part.h"
#include "css/rule.h"
#include "css/state.h"
@ -37,8 +38,11 @@ namespace app {
static css::Rule& backgroundColorRule() { return m_backgroundColorRule; }
static css::Rule& backgroundPartRule() { return m_backgroundPartRule; }
static css::Rule& backgroundRepeatRule() { return m_backgroundRepeatRule; }
static css::Rule& iconAlignRule() { return m_iconAlignRule; }
static css::Rule& iconPartRule() { return m_iconPartRule; }
static css::Rule& iconXRule() { return m_iconXRule; }
static css::Rule& iconYRule() { return m_iconYRule; }
static css::Rule& textAlignRule() { return m_textAlignRule; }
static css::Rule& textColorRule() { return m_textColorRule; }
static css::Rule& paddingLeftRule() { return m_paddingLeftRule; }
@ -53,14 +57,18 @@ namespace app {
static SkinPartPtr convertPart(const css::Value& value);
static gfx::Color convertColor(const css::Value& value);
static BackgroundRepeat convertRepeat(const css::Value& value);
private:
typedef std::map<std::string, Style*> StyleMap;
static css::Rule m_backgroundColorRule;
static css::Rule m_backgroundPartRule;
static css::Rule m_backgroundRepeatRule;
static css::Rule m_iconAlignRule;
static css::Rule m_iconPartRule;
static css::Rule m_iconXRule;
static css::Rule m_iconYRule;
static css::Rule m_textAlignRule;
static css::Rule m_textColorRule;
static css::Rule m_paddingLeftRule;

View File

@ -1,54 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/start_view.h"
#include "app/ui/skin/skin_theme.h"
#include "ui/label.h"
#include "ui/textbox.h"
#include "ui/view.h"
namespace app {
using namespace ui;
using namespace skin;
StartView::StartView()
: Box(JI_VERTICAL)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
setBgColor(theme->getColor(ThemeColor::Workspace));
child_spacing = 8 * guiscale();
addChild(new Label("Welcome to " PACKAGE " v" VERSION));
}
StartView::~StartView()
{
}
std::string StartView::getTabText()
{
return "Start";
}
WorkspaceView* StartView::cloneWorkspaceView()
{
return NULL; // This view cannot be cloned
}
void StartView::onClonedFrom(WorkspaceView* from)
{
ASSERT(false); // Never called
}
} // namespace app

View File

@ -1,39 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_START_VIEW_H_INCLUDED
#define APP_UI_START_VIEW_H_INCLUDED
#pragma once
#include "app/ui/tabs.h"
#include "app/ui/workspace_view.h"
#include "ui/box.h"
namespace ui {
class View;
}
namespace app {
class StartView : public ui::Box
, public TabView
, public WorkspaceView {
public:
StartView();
~StartView();
// TabView implementation
std::string getTabText() override;
// WorkspaceView implementation
ui::Widget* getContentWidget() override { return this; }
WorkspaceView* cloneWorkspaceView() override;
void onClonedFrom(WorkspaceView* from) override;
};
} // namespace app
#endif

View File

@ -224,24 +224,6 @@ StatusBar::StatusBar()
m_commandsBox = box1;
}
// Create the box to show notifications.
{
Box* box1 = new Box(JI_HORIZONTAL);
Box* box2 = new Box(JI_VERTICAL);
box1->setBorder(gfx::Border(2, 1, 2, 2)*guiscale());
box2->noBorderNoChildSpacing();
box2->setExpansive(true);
m_linkLabel = new LinkLabel((std::string(WEBSITE) + "donate/").c_str(), "Support This Project");
box1->addChild(box2);
box1->addChild(m_linkLabel);
m_notificationsBox = box1;
}
addChild(m_notificationsBox);
App::instance()->CurrentToolChange.connect(&StatusBar::onCurrentToolChange, this);
}
@ -252,7 +234,6 @@ StatusBar::~StatusBar()
delete m_tipwindow; // widget
delete m_commandsBox;
delete m_notificationsBox;
}
void StatusBar::onCurrentToolChange()
@ -455,11 +436,6 @@ void StatusBar::onResize(ResizeEvent& ev)
setBoundsQuietly(ev.getBounds());
Rect rc = ev.getBounds();
rc.x = rc.x2() - m_notificationsBox->getPreferredSize().w;
rc.w = m_notificationsBox->getPreferredSize().w;
m_notificationsBox->setBounds(rc);
rc = ev.getBounds();
rc.w -= rc.w/4 + 4*guiscale();
m_commandsBox->setBounds(rc);
}
@ -650,7 +626,6 @@ void StatusBar::updateSubwidgetsVisibility()
{
const Document* document = UIContext::instance()->activeDocument();
bool commandsVisible = (document != NULL && hasMouse());
bool notificationsVisible = (document == NULL);
if (commandsVisible) {
if (!hasChild(m_commandsBox)) {
@ -664,19 +639,6 @@ void StatusBar::updateSubwidgetsVisibility()
invalidate();
}
}
if (notificationsVisible) {
if (!hasChild(m_notificationsBox)) {
addChild(m_notificationsBox);
invalidate();
}
}
else {
if (hasChild(m_notificationsBox)) {
removeChild(m_notificationsBox);
invalidate();
}
}
}
} // namespace app

View File

@ -109,10 +109,6 @@ namespace app {
ui::Button* m_b_next; // Go to next frame
ui::Button* m_b_last; // Go to last frame
// Box of notifications.
ui::Widget* m_notificationsBox;
ui::LinkLabel* m_linkLabel;
// Tip window
class CustomizedTipWindow;
CustomizedTipWindow* m_tipwindow;

View File

@ -22,8 +22,10 @@ namespace app {
using namespace ui;
StyledButton::StyledButton(const std::string& styleName) : Button("") {
m_style = skin::get_style(styleName);
StyledButton::StyledButton(skin::Style* style)
: Button("")
, m_style(style)
{
}
bool StyledButton::onProcessMessage(Message* msg) {

View File

@ -19,7 +19,7 @@ namespace app {
class StyledButton : public ui::Button {
public:
StyledButton(const std::string& styleName);
StyledButton(skin::Style* style);
protected:
bool onProcessMessage(ui::Message* msg) override;

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,11 @@ namespace ui {
namespace app {
class Tabs;
enum class TabIcon {
NONE,
HOME,
};
// Required interface to be implemented by each new tab that is added
// in the Tabs widget.
class TabView {
@ -30,6 +35,9 @@ namespace app {
// Returns the text to be shown in the tab.
virtual std::string getTabText() = 0;
// Returns the icon to be shown in the tab
virtual TabIcon getTabIcon() = 0;
};
// Interface used to control notifications from the Tabs widget.
@ -37,12 +45,20 @@ namespace app {
public:
virtual ~TabsDelegate() { }
// Called when the user presses a mouse button over a tab.
virtual void clickTab(Tabs* tabs, TabView* tabView, ui::MouseButtons buttons) = 0;
// Called when the user selected the tab with the left mouse button.
virtual void onSelectTab(Tabs* tabs, TabView* tabView) = 0;
// When the tab close button is pressed (or middle mouse button is used to close it).
virtual void onCloseTab(Tabs* tabs, TabView* tabView) = 0;
// When the right-click is pressed in the tab.
virtual void onContextMenuTab(Tabs* tabs, TabView* tabView) = 0;
// Called when the mouse is over a tab (the data can be null if the
// mouse just leave all tabs)
virtual void mouseOverTab(Tabs* tabs, TabView* tabView) = 0;
virtual void onMouseOverTab(Tabs* tabs, TabView* tabView) = 0;
virtual bool onIsModified(Tabs* tabs, TabView* tabView) = 0;
};
// Tabs control. Used to show opened documents.
@ -50,9 +66,12 @@ namespace app {
struct Tab {
TabView* view;
std::string text;
int width;
TabIcon icon;
int x, width;
int oldX, oldWidth;
bool modified;
Tab(TabView* view) : view(view), width(0) {
Tab(TabView* view) : view(view) {
}
};
@ -62,8 +81,7 @@ namespace app {
enum Ani { ANI_NONE,
ANI_ADDING_TAB,
ANI_REMOVING_TAB,
ANI_SCROLL,
ANI_SMOOTH_SCROLL };
ANI_REORDER_TABS };
public:
Tabs(TabsDelegate* delegate);
@ -71,59 +89,59 @@ namespace app {
void addTab(TabView* tabView);
void removeTab(TabView* tabView);
void updateTabsText();
void updateTabs();
void selectTab(TabView* tabView);
void selectNextTab();
void selectPreviousTab();
TabView* getSelectedTab();
void startScrolling();
void stopScrolling();
protected:
bool onProcessMessage(ui::Message* msg) override;
void onPaint(ui::PaintEvent& ev) override;
void onResize(ui::ResizeEvent& ev) override;
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
void onInitTheme(ui::InitThemeEvent& ev) override;
void onSetText() override;
private:
void startAni(Ani ani);
void resetOldPositions();
void resetOldPositions(double t);
void startAni(Ani ani, int T);
void stopAni();
void selectTabInternal(Tab* tab);
void drawTab(ui::Graphics* g, const gfx::Rect& box, Tab* tab, int y_delta, bool selected);
void drawTab(ui::Graphics* g, const gfx::Rect& box, Tab* tab, int dy, bool hover, bool selected);
void drawFiller(ui::Graphics* g, const gfx::Rect& box);
TabsListIterator getTabIteratorByView(TabView* tabView);
Tab* getTabByView(TabView* tabView);
int getMaxScrollX();
void makeTabVisible(Tab* tab);
void setScrollX(int scroll_x);
void calculateHot();
void calcTabWidth(Tab* tab);
gfx::Rect getTabCloseButtonBounds(Tab* tab, const gfx::Rect& box);
void startDrag();
void stopDrag();
TabsList m_list_of_tabs;
int m_border;
TabsList m_list;
Tab* m_hot;
bool m_hotCloseButton;
bool m_clickedCloseButton;
Tab* m_selected;
int m_scrollX;
// Delegate of notifications
TabsDelegate* m_delegate;
// Variables for animation purposes
ui::Timer m_timer;
int m_begScrollX; // Initial X position of scroll in the animation when you scroll with mouse wheel
int m_endScrollX; // Final X position of scroll in the animation when you scroll with mouse wheel
Ani m_ani; // Current animation
int m_ani_t; // Number of ticks from the beginning of the animation
int m_ani_t; // Number of ticks from the beginning of the transition/animation
int m_ani_T; // Number of ticks in total for the current transition/animation
Tab* m_removedTab;
Tab* m_nextTabOfTheRemovedOne;
// Buttons to scroll tabs (useful when there are more tabs than visible area)
class ScrollButton;
ScrollButton* m_button_left;
ScrollButton* m_button_right;
// Drag-and-drop
bool m_isDragging;
int m_dragTabX;
gfx::Point m_dragMousePos;
int m_dragTabIndex;
};
} // namespace app

View File

@ -30,6 +30,7 @@
#include "app/ui/document_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui/status_bar.h"
#include "app/ui_context.h"
#include "app/util/clipboard.h"
@ -73,38 +74,6 @@ using namespace gfx;
using namespace doc;
using namespace ui;
static const char* kTimeline = "timeline";
static const char* kTimelineBox = "timeline_box";
static const char* kTimelineOpenEye = "timeline_open_eye";
static const char* kTimelineClosedEye = "timeline_closed_eye";
static const char* kTimelineOpenPadlock = "timeline_open_padlock";
static const char* kTimelineClosedPadlock = "timeline_closed_padlock";
static const char* kTimelineContinuous = "timeline_continuous";
static const char* kTimelineDiscontinuous = "timeline_discontinuous";
static const char* kTimelineLayer = "timeline_layer";
static const char* kTimelineEmptyFrame = "timeline_empty_frame";
static const char* kTimelineKeyframe = "timeline_keyframe";
static const char* kTimelineFromLeft = "timeline_fromleft";
static const char* kTimelineFromRight = "timeline_fromright";
static const char* kTimelineFromBoth = "timeline_fromboth";
static const char* kTimelineLeftLink = "timeline_leftlink";
static const char* kTimelineRightLink = "timeline_rightlink";
static const char* kTimelineBothLinks = "timeline_bothlinks";
static const char* kTimelineGear = "timeline_gear";
static const char* kTimelineOnionskin = "timeline_onionskin";
static const char* kTimelineOnionskinRange = "timeline_onionskin_range";
static const char* kTimelinePadding = "timeline_padding";
static const char* kTimelinePaddingTr = "timeline_padding_tr";
static const char* kTimelinePaddingBl = "timeline_padding_bl";
static const char* kTimelinePaddingBr = "timeline_padding_br";
static const char* kTimelineSelectedCelStyle = "timeline_selected_cel";
static const char* kTimelineRangeOutlineStyle = "timeline_range_outline";
static const char* kTimelineDropLayerDecoStyle = "timeline_drop_layer_deco";
static const char* kTimelineDropFrameDecoStyle = "timeline_drop_frame_deco";
static const char* kTimelineLoopRangeStyle = "timeline_loop_range";
static const char* kTimelineActiveColor = "timeline_active";
enum {
A_PART_NOTHING,
A_PART_SEPARATOR,
@ -128,35 +97,6 @@ enum {
Timeline::Timeline()
: Widget(kGenericWidget)
, m_timelineStyle(get_style(kTimeline))
, m_timelineBoxStyle(get_style(kTimelineBox))
, m_timelineOpenEyeStyle(get_style(kTimelineOpenEye))
, m_timelineClosedEyeStyle(get_style(kTimelineClosedEye))
, m_timelineOpenPadlockStyle(get_style(kTimelineOpenPadlock))
, m_timelineClosedPadlockStyle(get_style(kTimelineClosedPadlock))
, m_timelineContinuousStyle(get_style(kTimelineContinuous))
, m_timelineDiscontinuousStyle(get_style(kTimelineDiscontinuous))
, m_timelineLayerStyle(get_style(kTimelineLayer))
, m_timelineEmptyFrameStyle(get_style(kTimelineEmptyFrame))
, m_timelineKeyframeStyle(get_style(kTimelineKeyframe))
, m_timelineFromLeftStyle(get_style(kTimelineFromLeft))
, m_timelineFromRightStyle(get_style(kTimelineFromRight))
, m_timelineFromBothStyle(get_style(kTimelineFromBoth))
, m_timelineLeftLinkStyle(get_style(kTimelineLeftLink))
, m_timelineRightLinkStyle(get_style(kTimelineRightLink))
, m_timelineBothLinksStyle(get_style(kTimelineBothLinks))
, m_timelineGearStyle(get_style(kTimelineGear))
, m_timelineOnionskinStyle(get_style(kTimelineOnionskin))
, m_timelineOnionskinRangeStyle(get_style(kTimelineOnionskinRange))
, m_timelinePaddingStyle(get_style(kTimelinePadding))
, m_timelinePaddingTrStyle(get_style(kTimelinePaddingTr))
, m_timelinePaddingBlStyle(get_style(kTimelinePaddingBl))
, m_timelinePaddingBrStyle(get_style(kTimelinePaddingBr))
, m_timelineSelectedCelStyle(get_style(kTimelineSelectedCelStyle))
, m_timelineRangeOutlineStyle(get_style(kTimelineRangeOutlineStyle))
, m_timelineDropLayerDecoStyle(get_style(kTimelineDropLayerDecoStyle))
, m_timelineDropFrameDecoStyle(get_style(kTimelineDropFrameDecoStyle))
, m_timelineLoopRangeStyle(get_style(kTimelineLoopRangeStyle))
, m_context(UIContext::instance())
, m_editor(NULL)
, m_document(NULL)
@ -832,7 +772,7 @@ void Timeline::onPaint(ui::PaintEvent& ev)
gfx::Rect bounds = getOnionskinFramesBounds();
if (!bounds.isEmpty()) {
drawPart(g, bounds,
NULL, m_timelineOnionskinRangeStyle,
NULL, skinTheme()->styles.timelineOnionskinRange(),
false, false, false);
}
}
@ -889,7 +829,8 @@ void Timeline::onPaint(ui::PaintEvent& ev)
paintNoDoc:;
if (noDoc)
drawPart(g, getClientBounds(), NULL, m_timelinePaddingStyle);
drawPart(g, getClientBounds(), NULL,
skinTheme()->styles.timelinePadding());
}
void Timeline::onAfterCommandExecution(Command* command)
@ -1098,46 +1039,47 @@ void Timeline::drawClipboardRange(ui::Graphics* g)
void Timeline::drawHeader(ui::Graphics* g)
{
SkinTheme::Styles& styles = skinTheme()->styles;
bool allInvisible = allLayersInvisible();
bool allLocked = allLayersLocked();
bool allContinuous = allLayersContinuous();
drawPart(g, getPartBounds(A_PART_HEADER_EYE),
NULL,
allInvisible ? m_timelineClosedEyeStyle: m_timelineOpenEyeStyle,
allInvisible ? styles.timelineClosedEye(): styles.timelineOpenEye(),
m_clk_part == A_PART_HEADER_EYE,
m_hot_part == A_PART_HEADER_EYE,
m_clk_part == A_PART_HEADER_EYE);
drawPart(g, getPartBounds(A_PART_HEADER_PADLOCK),
NULL,
allLocked ? m_timelineClosedPadlockStyle: m_timelineOpenPadlockStyle,
allLocked ? styles.timelineClosedPadlock(): styles.timelineOpenPadlock(),
m_clk_part == A_PART_HEADER_PADLOCK,
m_hot_part == A_PART_HEADER_PADLOCK,
m_clk_part == A_PART_HEADER_PADLOCK);
drawPart(g, getPartBounds(A_PART_HEADER_CONTINUOUS),
NULL,
allContinuous ? m_timelineContinuousStyle: m_timelineDiscontinuousStyle,
allContinuous ? styles.timelineContinuous(): styles.timelineDiscontinuous(),
m_clk_part == A_PART_HEADER_CONTINUOUS,
m_hot_part == A_PART_HEADER_CONTINUOUS,
m_clk_part == A_PART_HEADER_CONTINUOUS);
drawPart(g, getPartBounds(A_PART_HEADER_GEAR),
NULL, m_timelineGearStyle,
NULL, styles.timelineGear(),
false,
m_hot_part == A_PART_HEADER_GEAR,
m_clk_part == A_PART_HEADER_GEAR);
drawPart(g, getPartBounds(A_PART_HEADER_ONIONSKIN),
NULL, m_timelineOnionskinStyle,
NULL, styles.timelineOnionskin(),
docPref().onionskin.active(),
m_hot_part == A_PART_HEADER_ONIONSKIN,
m_clk_part == A_PART_HEADER_ONIONSKIN);
// Empty header space.
drawPart(g, getPartBounds(A_PART_HEADER_LAYER),
NULL, m_timelineBoxStyle, false, false, false);
NULL, styles.timelineBox(), false, false, false);
}
void Timeline::drawHeaderFrame(ui::Graphics* g, frame_t frame)
@ -1155,13 +1097,14 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, frame_t frame)
std::sprintf(buf, "%d", (frame+1)%100); // Draw only the first two digits.
she::Font* oldFont = g->getFont();
g->setFont(((SkinTheme*)getTheme())->getMiniFont());
drawPart(g, bounds, buf, m_timelineBoxStyle, is_active, is_hover, is_clicked);
g->setFont(skinTheme()->getMiniFont());
drawPart(g, bounds, buf, skinTheme()->styles.timelineBox(), is_active, is_hover, is_clicked);
g->setFont(oldFont);
}
void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
{
SkinTheme::Styles& styles = skinTheme()->styles;
Layer* layer = m_layers[layerIdx];
bool is_active = isLayerActive(layerIdx);
bool hotlayer = (m_hot_layer == layerIdx);
@ -1174,7 +1117,7 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
// Draw the eye (visible flag).
bounds = getPartBounds(A_PART_LAYER_EYE_ICON, layerIdx);
drawPart(g, bounds, NULL,
layer->isVisible() ? m_timelineOpenEyeStyle: m_timelineClosedEyeStyle,
layer->isVisible() ? styles.timelineOpenEye(): styles.timelineClosedEye(),
is_active,
(hotlayer && m_hot_part == A_PART_LAYER_EYE_ICON),
(clklayer && m_clk_part == A_PART_LAYER_EYE_ICON));
@ -1182,7 +1125,7 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
// Draw the padlock (editable flag).
bounds = getPartBounds(A_PART_LAYER_PADLOCK_ICON, layerIdx);
drawPart(g, bounds, NULL,
layer->isEditable() ? m_timelineOpenPadlockStyle: m_timelineClosedPadlockStyle,
layer->isEditable() ? styles.timelineOpenPadlock(): styles.timelineClosedPadlock(),
is_active,
(hotlayer && m_hot_part == A_PART_LAYER_PADLOCK_ICON),
(clklayer && m_clk_part == A_PART_LAYER_PADLOCK_ICON));
@ -1190,14 +1133,14 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
// Draw the continuous flag.
bounds = getPartBounds(A_PART_LAYER_CONTINUOUS_ICON, layerIdx);
drawPart(g, bounds, NULL,
layer->isContinuous() ? m_timelineContinuousStyle: m_timelineDiscontinuousStyle,
layer->isContinuous() ? styles.timelineContinuous(): styles.timelineDiscontinuous(),
is_active,
(hotlayer && m_hot_part == A_PART_LAYER_CONTINUOUS_ICON),
(clklayer && m_clk_part == A_PART_LAYER_CONTINUOUS_ICON));
// Draw the layer's name.
bounds = getPartBounds(A_PART_LAYER_TEXT, layerIdx);
drawPart(g, bounds, layer->name().c_str(), m_timelineLayerStyle,
drawPart(g, bounds, layer->name().c_str(), styles.timelineLayer(),
is_active,
(hotlayer && m_hot_part == A_PART_LAYER_TEXT),
(clklayer && m_clk_part == A_PART_LAYER_TEXT));
@ -1207,13 +1150,15 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
// layers.
if (hotlayer && !is_active && m_clk_part == A_PART_LAYER_TEXT) {
// TODO this should be skinneable
g->fillRect(get_color_by_id(kTimelineActiveColor),
gfx::Rect(bounds.x, bounds.y, bounds.w, 2));
g->fillRect(
skinTheme()->colors.timelineActive(),
gfx::Rect(bounds.x, bounds.y, bounds.w, 2));
}
}
void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Cel* cel)
{
SkinTheme::Styles& styles = skinTheme()->styles;
Layer* layer = m_layers[layerIndex];
Image* image = (cel ? cel->image(): NULL);
bool is_hover = (m_hot_part == A_PART_CEL &&
@ -1227,15 +1172,15 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
return;
if (layer == m_layer && frame == m_frame)
drawPart(g, bounds, NULL, m_timelineSelectedCelStyle, false, false, true);
drawPart(g, bounds, NULL, styles.timelineSelectedCel(), false, false, true);
else
drawPart(g, bounds, NULL, m_timelineBoxStyle, is_active, is_hover);
drawPart(g, bounds, NULL, styles.timelineBox(), is_active, is_hover);
skin::Style* style;
bool fromLeft = false;
bool fromRight = false;
if (is_empty) {
style = m_timelineEmptyFrameStyle;
style = styles.timelineEmptyFrame();
}
else {
Cel* left = (layer->isImage() ? layer->cel(frame-1): NULL);
@ -1246,13 +1191,13 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
fromRight = (rightImg == cel->image()->id());
if (fromLeft && fromRight)
style = m_timelineFromBothStyle;
style = styles.timelineFromBoth();
else if (fromLeft)
style = m_timelineFromLeftStyle;
style = styles.timelineFromLeft();
else if (fromRight)
style = m_timelineFromRightStyle;
style = styles.timelineFromRight();
else
style = m_timelineKeyframeStyle;
style = styles.timelineKeyframe();
}
drawPart(g, bounds, NULL, style, is_active, is_hover);
@ -1267,6 +1212,7 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
Cel* cel, Cel* activeCel, frame_t frame, bool is_active, bool is_hover)
{
SkinTheme::Styles& styles = skinTheme()->styles;
ObjectId imageId = activeCel->image()->id();
// Link in some cel at the left side
@ -1291,18 +1237,18 @@ void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
if (!cel || cel->image()->id() != imageId) {
if (left && right)
drawPart(g, bounds, NULL, m_timelineBothLinksStyle, is_active, is_hover);
drawPart(g, bounds, NULL, styles.timelineBothLinks(), is_active, is_hover);
}
else {
if (left) {
Cel* prevCel = m_layer->cel(cel->frame()-1);
if (!prevCel || prevCel->image()->id() != imageId)
drawPart(g, bounds, NULL, m_timelineLeftLinkStyle, is_active, is_hover);
drawPart(g, bounds, NULL, styles.timelineLeftLink(), is_active, is_hover);
}
if (right) {
Cel* nextCel = m_layer->cel(cel->frame()+1);
if (!nextCel || nextCel->image()->id() != imageId)
drawPart(g, bounds, NULL, m_timelineRightLinkStyle, is_active, is_hover);
drawPart(g, bounds, NULL, styles.timelineRightLink(), is_active, is_hover);
}
}
}
@ -1326,11 +1272,14 @@ void Timeline::drawLoopRange(ui::Graphics* g)
if (!clip)
return;
drawPart(g, bounds, NULL, m_timelineLoopRangeStyle);
drawPart(g, bounds, NULL,
skinTheme()->styles.timelineLoopRange());
}
void Timeline::drawFrameTags(ui::Graphics* g)
{
SkinTheme::Styles& styles = skinTheme()->styles;
for (FrameTag* frameTag : m_sprite->frameTags()) {
gfx::Rect bounds1 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), frameTag->fromFrame());
gfx::Rect bounds2 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), frameTag->toFrame());
@ -1338,13 +1287,15 @@ void Timeline::drawFrameTags(ui::Graphics* g)
IntersectClip clip(g, bounds);
if (clip) {
drawPart(g, bounds, NULL, m_timelineLoopRangeStyle);
drawPart(g, bounds, NULL, styles.timelineLoopRange());
}
}
}
void Timeline::drawRangeOutline(ui::Graphics* g)
{
SkinTheme::Styles& styles = skinTheme()->styles;
gfx::Rect clipBounds;
switch (m_range.type()) {
case Range::kCels: clipBounds = getCelsBounds(); break;
@ -1360,7 +1311,7 @@ void Timeline::drawRangeOutline(ui::Graphics* g)
if (m_hot_part == A_PART_RANGE_OUTLINE) state += Style::hover();
gfx::Rect bounds = getPartBounds(A_PART_RANGE_OUTLINE);
m_timelineRangeOutlineStyle->paint(g, bounds, NULL, state);
styles.timelineRangeOutline()->paint(g, bounds, NULL, state);
Range drop = m_dropRange;
gfx::Rect dropBounds = getRangeBounds(drop);
@ -1369,7 +1320,7 @@ void Timeline::drawRangeOutline(ui::Graphics* g)
case Range::kCels: {
dropBounds = dropBounds.enlarge(OUTLINE_WIDTH);
m_timelineRangeOutlineStyle->paint(g, dropBounds, NULL, Style::active());
styles.timelineRangeOutline()->paint(g, dropBounds, NULL, Style::active());
break;
}
@ -1385,7 +1336,7 @@ void Timeline::drawRangeOutline(ui::Graphics* g)
dropBounds.w = w;
m_timelineDropFrameDecoStyle->paint(g, dropBounds, NULL, Style::State());
styles.timelineDropFrameDeco()->paint(g, dropBounds, NULL, Style::State());
break;
}
@ -1401,7 +1352,7 @@ void Timeline::drawRangeOutline(ui::Graphics* g)
dropBounds.h = h;
m_timelineDropLayerDecoStyle->paint(g, dropBounds, NULL, Style::State());
styles.timelineDropLayerDeco()->paint(g, dropBounds, NULL, Style::State());
break;
}
}
@ -1409,6 +1360,8 @@ void Timeline::drawRangeOutline(ui::Graphics* g)
void Timeline::drawPaddings(ui::Graphics* g)
{
SkinTheme::Styles& styles = skinTheme()->styles;
gfx::Rect client = getClientBounds();
gfx::Rect bottomLayer;
gfx::Rect lastFrame;
@ -1426,18 +1379,18 @@ void Timeline::drawPaddings(ui::Graphics* g)
gfx::Rect(lastFrame.x+lastFrame.w, client.y,
client.w - (lastFrame.x+lastFrame.w),
bottomLayer.y+bottomLayer.h),
NULL, m_timelinePaddingTrStyle);
NULL, styles.timelinePaddingTr());
drawPart(g,
gfx::Rect(client.x, bottomLayer.y+bottomLayer.h,
lastFrame.x+lastFrame.w - client.x, client.h - (bottomLayer.y+bottomLayer.h)),
NULL, m_timelinePaddingBlStyle);
NULL, styles.timelinePaddingBl());
drawPart(g,
gfx::Rect(lastFrame.x+lastFrame.w, bottomLayer.y+bottomLayer.h,
client.w - (lastFrame.x+lastFrame.w),
client.h - (bottomLayer.y+bottomLayer.h)),
NULL, m_timelinePaddingBrStyle);
NULL, styles.timelinePaddingBr());
}
gfx::Rect Timeline::getLayerHeadersBounds() const
@ -2210,4 +2163,9 @@ DocumentPreferences& Timeline::docPref() const
return App::instance()->preferences().document(m_document);
}
skin::SkinTheme* Timeline::skinTheme() const
{
return static_cast<SkinTheme*>(getTheme());
}
} // namespace app

View File

@ -12,7 +12,6 @@
#include "app/document_range.h"
#include "app/pref/preferences.h"
#include "app/ui/editor/editor_observer.h"
#include "app/ui/skin/style.h"
#include "base/connection.h"
#include "doc/document_observer.h"
#include "doc/documents_observer.h"
@ -36,6 +35,12 @@ namespace ui {
}
namespace app {
namespace skin {
class Style;
class SkinTheme;
}
using namespace doc;
class Command;
@ -191,36 +196,8 @@ namespace app {
bool validFrame(frame_t frame) const { return frame >= firstFrame() && frame <= lastFrame(); }
DocumentPreferences& docPref() const;
skin::SkinTheme* skinTheme() const;
skin::Style* m_timelineStyle;
skin::Style* m_timelineBoxStyle;
skin::Style* m_timelineOpenEyeStyle;
skin::Style* m_timelineClosedEyeStyle;
skin::Style* m_timelineOpenPadlockStyle;
skin::Style* m_timelineClosedPadlockStyle;
skin::Style* m_timelineContinuousStyle;
skin::Style* m_timelineDiscontinuousStyle;
skin::Style* m_timelineLayerStyle;
skin::Style* m_timelineEmptyFrameStyle;
skin::Style* m_timelineKeyframeStyle;
skin::Style* m_timelineFromLeftStyle;
skin::Style* m_timelineFromRightStyle;
skin::Style* m_timelineFromBothStyle;
skin::Style* m_timelineLeftLinkStyle;
skin::Style* m_timelineRightLinkStyle;
skin::Style* m_timelineBothLinksStyle;
skin::Style* m_timelineGearStyle;
skin::Style* m_timelineOnionskinStyle;
skin::Style* m_timelineOnionskinRangeStyle;
skin::Style* m_timelinePaddingStyle;
skin::Style* m_timelinePaddingTrStyle;
skin::Style* m_timelinePaddingBlStyle;
skin::Style* m_timelinePaddingBrStyle;
skin::Style* m_timelineSelectedCelStyle;
skin::Style* m_timelineRangeOutlineStyle;
skin::Style* m_timelineDropLayerDecoStyle;
skin::Style* m_timelineDropFrameDecoStyle;
skin::Style* m_timelineLoopRangeStyle;
Context* m_context;
Editor* m_editor;
Document* m_document;

View File

@ -306,14 +306,14 @@ void ToolBar::onPaint(ui::PaintEvent& ev)
gfx::Rect bounds = getClientBounds();
Graphics* g = ev.getGraphics();
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
gfx::Color normalFace = theme->getColor(ThemeColor::ButtonNormalFace);
gfx::Color hotFace = theme->getColor(ThemeColor::ButtonHotFace);
gfx::Color normalFace = theme->colors.buttonNormalFace();
gfx::Color hotFace = theme->colors.buttonHotFace();
ToolBox* toolbox = App::instance()->getToolBox();
ToolGroupList::iterator it = toolbox->begin_group();
int groups = toolbox->getGroupsCount();
Rect toolrc;
g->fillRect(theme->getColor(ThemeColor::TabSelectedFace), bounds);
g->fillRect(theme->colors.tabActiveFace(), bounds);
for (int c=0; c<groups; ++c, ++it) {
ToolGroup* tool_group = *it;
@ -733,11 +733,11 @@ void ToolBar::ToolStrip::onPaint(PaintEvent& ev)
if (UIContext::instance()->settings()->getCurrentTool() == tool ||
m_hotTool == tool) {
nw = PART_TOOLBUTTON_HOT_NW;
face = theme->getColor(ThemeColor::ButtonHotFace);
face = theme->colors.buttonHotFace();
}
else {
nw = PART_TOOLBUTTON_LAST_NW;
face = theme->getColor(ThemeColor::ButtonNormalFace);
face = theme->colors.buttonNormalFace();
}
toolrc = getToolBounds(index++);

View File

@ -13,11 +13,10 @@
#include "app/app.h"
#include "app/ui/main_window.h"
#include "app/ui/tabs.h"
#include "app/ui/workspace_part.h"
#include "app/ui/workspace_view.h"
#include "app/ui/skin/skin_theme.h"
#include "ui/splitter.h"
#include "app/ui/tabs.h"
#include "app/ui/workspace_view.h"
#include "base/remove_from_container.h"
#include <algorithm>
#include <queue>
@ -28,13 +27,11 @@ using namespace app::skin;
using namespace ui;
Workspace::Workspace()
: Box(JI_VERTICAL)
, m_activePart(new WorkspacePart)
: Widget(kGenericWidget)
, m_activeView(nullptr)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
setBgColor(theme->getColor(ThemeColor::Workspace));
addChild(m_activePart);
setBgColor(theme->colors.workspace());
}
Workspace::~Workspace()
@ -47,198 +44,52 @@ void Workspace::addView(WorkspaceView* view)
{
m_views.push_back(view);
m_activePart->addView(view);
App::instance()->getMainWindow()->getTabsBar()->addTab(dynamic_cast<TabView*>(view));
ActiveViewChanged(); // Fire ActiveViewChanged event
setActiveView(view);
}
void Workspace::removeView(WorkspaceView* view)
{
WorkspaceViews::iterator it = std::find(m_views.begin(), m_views.end(), view);
ASSERT(it != m_views.end());
m_views.erase(it);
base::remove_from_container(m_views, view);
WorkspacePart* part = getPartByView(view);
ASSERT(part != NULL);
Widget* content = view->getContentWidget();
if (content->getParent())
content->getParent()->removeChild(content);
part->removeView(view);
if (part->getViewCount() == 0 &&
part->getParent() != this) {
bool activePartRemoved = (m_activePart == part);
WorkspacePart* otherPart = destroyPart(part);
// Remove related tab
Tabs* tabs = App::instance()->getMainWindow()->getTabsBar();
tabs->removeTab(dynamic_cast<TabView*>(view));
if (activePartRemoved)
m_activePart = otherPart;
}
TabView* tabView = tabs->getSelectedTab();
setActiveView(dynamic_cast<WorkspaceView*>(tabView));
}
App::instance()->getMainWindow()->getTabsBar()->removeTab(dynamic_cast<TabView*>(view));
ActiveViewChanged(); // Fire ActiveViewChanged event
bool Workspace::closeView(WorkspaceView* view)
{
return view->onCloseView(this);
}
WorkspaceView* Workspace::activeView()
{
ASSERT(m_activePart != NULL);
return m_activePart->activeView();
return m_activeView;
}
void Workspace::setActiveView(WorkspaceView* view)
{
ASSERT(view != NULL);
m_activeView = view;
WorkspacePart* viewPart =
static_cast<WorkspacePart*>(view->getContentWidget()->getParent());
viewPart->setActiveView(view);
m_activePart = viewPart;
ActiveViewChanged(); // Fire ActiveViewChanged event
}
void Workspace::splitView(WorkspaceView* view, int orientation)
{
// Try to clone the workspace view.
WorkspaceView* newView = view->cloneWorkspaceView();
if (newView == NULL)
return;
// Get the part where the view-to-clone is located because we need
// to split this part.
WorkspacePart* viewPart =
static_cast<WorkspacePart*>(view->getContentWidget()->getParent());
// Create a new splitter to add new WorkspacePart on it: the given
// "viewPart" and a new part named "newPart".
Splitter* splitter = new Splitter(Splitter::ByPercentage, orientation);
splitter->setExpansive(true);
// Create the new part to contain the cloned view (see below, "newView").
WorkspacePart* newPart = new WorkspacePart();
// Replace the "viewPart" with the "splitter".
Widget* parent = viewPart->getParent();
parent->replaceChild(viewPart, splitter);
splitter->addChild(viewPart);
splitter->addChild(newPart);
// The new part is the active one.
m_activePart = newPart;
// Add the cloned view to the active part (newPart)
// using Workspace::addView().
addView(newView);
setActiveView(newView);
removeAllChildren();
if (view)
addChild(view->getContentWidget());
layout();
newView->onClonedFrom(view);
ActiveViewChanged(); // Fire ActiveViewChanged event
}
WorkspacePart* Workspace::destroyPart(WorkspacePart* part)
void Workspace::onPaint(PaintEvent& ev)
{
ASSERT(part != NULL);
ASSERT(part->getViewCount() == 0);
Widget* splitter = part->getParent();
ASSERT(splitter != this);
ASSERT(splitter->getChildren().size() == 2);
splitter->removeChild(part);
delete part;
ASSERT(splitter->getChildren().size() == 1);
Widget* otherWidget = splitter->getFirstChild();
WorkspacePart* otherPart = dynamic_cast<WorkspacePart*>(otherWidget);
if (otherPart == NULL) {
Widget* widget = otherWidget;
for (;;) {
otherPart = widget->findFirstChildByType<WorkspacePart>();
if (otherPart != NULL)
break;
widget = widget->getFirstChild();
}
}
ASSERT(otherPart != NULL);
splitter->removeChild(otherWidget);
splitter->getParent()->replaceChild(splitter, otherWidget);
delete splitter;
layout();
return otherPart;
}
void Workspace::makeUnique(WorkspaceView* view)
{
WorkspaceParts parts;
enumAllParts(parts);
for (WorkspaceParts::iterator it=parts.begin(), end=parts.end(); it != end; ++it) {
WorkspacePart* part = *it;
if (part->getParent() != this) {
while (part->activeView())
part->removeView(part->activeView());
}
}
for (WorkspaceParts::iterator it=parts.begin(), end=parts.end(); it != end; ++it) {
WorkspacePart* part = *it;
if (part->getParent() != this)
destroyPart(part);
}
WorkspacePart* uniquePart = dynamic_cast<WorkspacePart*>(getFirstChild());
ASSERT(uniquePart != NULL);
m_activePart = uniquePart;
for (WorkspaceViews::iterator it=m_views.begin(), end=m_views.end(); it != end; ++it) {
WorkspaceView* v = *it;
if (!v->getContentWidget()->getParent())
uniquePart->addView(v);
}
setActiveView(view);
}
WorkspacePart* Workspace::getPartByView(WorkspaceView* view)
{
WorkspaceParts parts;
enumAllParts(parts);
for (WorkspaceParts::iterator it=parts.begin(), end=parts.end(); it != end; ++it) {
WorkspacePart* part = *it;
if (part->hasView(view))
return part;
}
return NULL;
}
void Workspace::enumAllParts(WorkspaceParts& parts)
{
std::queue<Widget*> remaining;
remaining.push(getFirstChild());
while (!remaining.empty()) {
Widget* widget = remaining.front();
remaining.pop();
ASSERT(widget != NULL);
WorkspacePart* part = dynamic_cast<WorkspacePart*>(widget);
if (part) {
parts.push_back(part);
}
else {
UI_FOREACH_WIDGET(widget->getChildren(), it) {
remaining.push(*it);
}
}
}
ev.getGraphics()->fillRect(getBgColor(), getClientBounds());
}
} // namespace app

View File

@ -11,13 +11,14 @@
#include "app/ui/workspace_views.h"
#include "base/signal.h"
#include "ui/box.h"
#include "ui/widget.h"
#include <map>
#include <vector>
namespace app {
class WorkspacePart;
class Workspace : public ui::Box {
class Workspace : public ui::Widget {
public:
typedef WorkspaceViews::iterator iterator;
@ -30,24 +31,21 @@ namespace app {
void addView(WorkspaceView* view);
void removeView(WorkspaceView* view);
// Closes the given view. Returns false if the user cancels the
// operation.
bool closeView(WorkspaceView* view);
WorkspaceView* activeView();
void setActiveView(WorkspaceView* view);
void splitView(WorkspaceView* view, int orientation);
void makeUnique(WorkspaceView* view);
Signal0<void> ActiveViewChanged;
protected:
void onPaint(ui::PaintEvent& ev) override;
private:
typedef std::vector<WorkspacePart*> WorkspaceParts;
WorkspacePart* destroyPart(WorkspacePart* part);
WorkspacePart* getPartByView(WorkspaceView* view);
void enumAllParts(WorkspaceParts& parts);
// All views of all parts.
WorkspaceViews m_views;
WorkspacePart* m_activePart;
WorkspaceView* m_activeView;
};
} // namespace app

View File

@ -1,87 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/workspace_part.h"
#include "app/ui/workspace_view.h"
#include "app/ui/skin/skin_theme.h"
#include <algorithm>
namespace app {
using namespace app::skin;
using namespace ui;
WorkspacePart::WorkspacePart()
: Box(JI_VERTICAL)
, m_activeView(NULL)
{
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
setBgColor(theme->getColor(ThemeColor::Workspace));
setExpansive(true);
}
WorkspacePart::~WorkspacePart()
{
}
void WorkspacePart::addView(WorkspaceView* view)
{
m_views.push_back(view);
addChild(view->getContentWidget());
setActiveView(view);
}
void WorkspacePart::removeView(WorkspaceView* view)
{
WorkspaceViews::iterator it = std::find(m_views.begin(), m_views.end(), view);
ASSERT(it != m_views.end());
it = m_views.erase(it);
removeChild(view->getContentWidget());
setActiveView((it != m_views.end() ?
*it : (!m_views.empty() ? m_views.front(): NULL)));
}
void WorkspacePart::setActiveView(WorkspaceView* view)
{
m_activeView = view;
Widget* newContent = (view ? view->getContentWidget(): NULL);
WidgetsList children = getChildren();
UI_FOREACH_WIDGET(children, it) {
if ((*it) != newContent)
(*it)->setVisible(false);
}
if (newContent) {
newContent->setExpansive(true);
newContent->setVisible(true);
newContent->requestFocus();
}
if (m_activeView)
m_activeView->onWorkspaceViewSelected();
layout();
}
bool WorkspacePart::hasView(WorkspaceView* view)
{
return (std::find(m_views.begin(), m_views.end(), view) != m_views.end());
}
} // namespace app

View File

@ -1,40 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_WORKSPACE_PART_H_INCLUDED
#define APP_UI_WORKSPACE_PART_H_INCLUDED
#pragma once
#include "app/ui/workspace_views.h"
#include "ui/box.h"
#include <vector>
namespace app {
class WorkspacePart : public ui::Box {
public:
WorkspacePart();
~WorkspacePart();
size_t getViewCount() { return m_views.size(); }
void addView(WorkspaceView* view);
void removeView(WorkspaceView* view);
WorkspaceView* activeView() { return m_activeView; }
void setActiveView(WorkspaceView* view);
bool hasView(WorkspaceView* view);
private:
WorkspaceView* m_activeView;
WorkspaceViews m_views;
};
} // namespace app
#endif

View File

@ -14,6 +14,7 @@ namespace ui {
}
namespace app {
class Workspace;
class WorkspaceView {
public:
@ -27,6 +28,12 @@ namespace app {
// the workspace. It can be used to copy/clone scroll position
// from the original view.
virtual void onClonedFrom(WorkspaceView* from) = 0;
// Returns true if the view was closed successfully or false if
// the user cancels the operation.
virtual bool onCloseView(Workspace* workspace) = 0;
virtual void onTabPopup(Workspace* workspace) = 0;
};
} // namespace app

View File

@ -127,7 +127,7 @@ DocumentView* UIContext::getFirstDocumentView(Document* document) const
{
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
for (auto view : *workspace) {
for (WorkspaceView* view : *workspace) {
if (DocumentView* docView = dynamic_cast<DocumentView*>(view)) {
if (docView->getDocument() == document) {
return docView;
@ -177,8 +177,7 @@ void UIContext::onRemoveDocument(doc::Document* doc)
DocumentViews docViews;
// Collect all views related to the document.
for (Workspace::iterator it=workspace->begin(); it != workspace->end(); ++it) {
WorkspaceView* view = *it;
for (WorkspaceView* view : *workspace) {
if (DocumentView* docView = dynamic_cast<DocumentView*>(view)) {
if (docView->getDocument() == doc) {
docViews.push_back(docView);
@ -186,8 +185,7 @@ void UIContext::onRemoveDocument(doc::Document* doc)
}
}
for (DocumentViews::iterator it=docViews.begin(); it != docViews.end(); ++it) {
DocumentView* docView = *it;
for (DocumentView* docView : docViews) {
workspace->removeView(docView);
delete docView;
}

View File

@ -16,6 +16,7 @@
#include "app/resource_finder.h"
#include "app/ui/button_set.h"
#include "app/ui/color_button.h"
#include "app/ui/skin/skin_style_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/widget_not_found.h"
#include "app/xml_document.h"
@ -23,6 +24,7 @@
#include "base/bind.h"
#include "base/fs.h"
#include "base/memory.h"
#include "she/system.h"
#include "ui/ui.h"
#include "tinyxml.h"
@ -429,6 +431,27 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
}
}
}
else if (elem_name == "image") {
if (!widget) {
const char* file = elem->Attribute("file");
// Load image
std::string icon(file);
ResourceFinder rf;
rf.includeDataDir(file);
if (!rf.findFirst())
throw base::Exception("File %s not found", file);
try {
she::Surface* sur = she::instance()->loadRgbaSurface(rf.filename().c_str());
widget = new ImageView(sur, 0);
}
catch (...) {
throw base::Exception("Error loading %s file", file);
}
}
}
// Was the widget created?
if (widget)
@ -454,6 +477,8 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
const char* minheight = elem->Attribute("minheight");
const char* maxwidth = elem->Attribute("maxwidth");
const char* maxheight = elem->Attribute("maxheight");
const char* border = elem->Attribute("border");
const char* styleid = elem->Attribute("style");
const char* childspacing = elem->Attribute("childspacing");
if (width) {
@ -498,8 +523,11 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
if (noborders)
widget->noBorderNoChildSpacing();
if (border)
widget->setBorder(gfx::Border(strtol(border, NULL, 10)*guiscale()));
if (childspacing)
widget->child_spacing = strtol(childspacing, NULL, 10);
widget->child_spacing = strtol(childspacing, NULL, 10)*guiscale();
gfx::Size reqSize = widget->getPreferredSize();
@ -515,6 +543,14 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
widget->setMaxSize(gfx::Size(w, h));
}
if (styleid) {
SkinTheme* theme = static_cast<SkinTheme*>(root->getTheme());
skin::Style* style = theme->getStyle(styleid);
ASSERT(style);
SkinStylePropertyPtr prop(new SkinStyleProperty(style));
widget->setProperty(prop);
}
if (!root)
root = widget;

View File

@ -1,5 +1,5 @@
# Aseprite Base Library
# Copyright (c) 2001-2014 David Capello
# Copyright (c) 2001-2015 David Capello
include(CheckCSourceCompiles)
include(CheckCXXSourceCompiles)
@ -65,6 +65,7 @@ set(BASE_SOURCES
system_console.cpp
temp_dir.cpp
thread.cpp
time.cpp
trim_string.cpp
version.cpp)

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -28,6 +28,18 @@ template<> std::string convert_to(const int& from)
return buf;
}
template<> double convert_to(const std::string& from)
{
return std::strtod(from.c_str(), NULL);
}
template<> std::string convert_to(const double& from)
{
char buf[32];
std::sprintf(buf, "%g", from);
return buf;
}
template<> Sha1 convert_to(const std::string& from)
{
std::vector<uint8_t> digest(Sha1::HashSize);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -24,6 +24,9 @@ namespace base {
template<> int convert_to(const std::string& from);
template<> std::string convert_to(const int& from);
template<> double convert_to(const std::string& from);
template<> std::string convert_to(const double& from);
template<> Sha1 convert_to(const std::string& from);
template<> std::string convert_to(const Sha1& from);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -11,6 +11,7 @@
#include "base/exception.h"
#include <cstdio>
#include <cstring>
#include <cstdarg>
namespace base {
@ -24,7 +25,7 @@ Exception::Exception() throw()
Exception::Exception(const char* format, ...) throw()
{
try {
if (!strchr(format, '%')) {
if (!std::strchr(format, '%')) {
m_msg = format;
}
else {
@ -32,7 +33,7 @@ Exception::Exception(const char* format, ...) throw()
va_start(ap, format);
char buf[1024]; // TODO warning buffer overflow
vsprintf(buf, format, ap);
std::vsprintf(buf, format, ap);
m_msg = buf;
va_end(ap);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -12,6 +12,8 @@
namespace base {
class Time;
bool is_file(const std::string& path);
bool is_directory(const std::string& path);
@ -23,6 +25,8 @@ namespace base {
bool has_readonly_attr(const std::string& path);
void remove_readonly_attr(const std::string& path);
Time get_modification_time(const std::string& path);
void make_directory(const std::string& path);
void make_all_directories(const std::string& path);
void remove_directory(const std::string& path);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -10,12 +10,14 @@
#include <stdlib.h>
#include <stdexcept>
#include <vector>
#include <ctime>
#if __APPLE__
#include <mach-o/dyld.h>
#endif
#include "base/path.h"
#include "base/time.h"
#define MAXPATHLEN 1024
@ -82,6 +84,19 @@ void remove_readonly_attr(const std::string& path)
}
}
Time get_modification_time(const std::string& path)
{
struct stat sts;
int result = stat(path.c_str(), &sts);
if (result != 0)
return Time();
std::tm* t = std::localtime(&sts.st_mtime);
return Time(
t->tm_year+1900, t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
}
void remove_directory(const std::string& path)
{
int result = rmdir(path.c_str());

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -12,6 +12,7 @@
#include "base/path.h"
#include "base/string.h"
#include "base/win32_exception.h"
#include "base/time.h"
namespace base {
@ -68,6 +69,24 @@ void remove_readonly_attr(const std::string& path)
::SetFileAttributes(fn.c_str(), attr & ~FILE_ATTRIBUTE_READONLY);
}
Time get_modification_time(const std::string& path)
{
WIN32_FILE_ATTRIBUTE_DATA data;
ZeroMemory(&data, sizeof(data));
std::wstring fn = from_utf8(path);
if (!GetFileAttributesEx(fn.c_str(), GetFileExInfoStandard, (LPVOID)&data))
return Time();
SYSTEMTIME utc, local;
FileTimeToSystemTime(&data.ftLastWriteTime, &utc);
SystemTimeToTzSpecificLocalTime(NULL, &utc, &local);
return Time(
local.wYear, local.wMonth, local.wDay,
local.wHour, local.wMinute, local.wSecond);
}
void make_directory(const std::string& path)
{
BOOL result = ::CreateDirectory(from_utf8(path).c_str(), NULL);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -12,7 +12,7 @@
namespace base {
std::string get_pretty_memory_size(size_t memsize);
std::string get_pretty_memory_size(std::size_t memsize);
} // namespace base

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -8,9 +8,11 @@
#define BASE_MEMORY_H_INCLUDED
#pragma once
void* base_malloc (size_t bytes);
void* base_malloc0(size_t bytes);
void* base_realloc(void* mem, size_t bytes);
#include <cstddef>
void* base_malloc (std::size_t bytes);
void* base_malloc0(std::size_t bytes);
void* base_realloc(void* mem, std::size_t bytes);
void base_free (void* mem);
char* base_strdup (const char* string);

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -22,7 +22,7 @@ public:
typedef typename list_type::const_iterator const_iterator;
bool empty() const { return m_observers.empty(); }
size_t size() const { return m_observers.size(); }
std::size_t size() const { return m_observers.size(); }
// Adds the observer in the collection. The observer is owned by the
// collection and will be destroyed calling the T::dispose() member

View File

@ -187,11 +187,11 @@ std::string ProgramOptions::value_of(const Option& option) const
std::ostream& operator<<(std::ostream& os, const base::ProgramOptions& po)
{
size_t maxOptionWidth = 0;
std::size_t maxOptionWidth = 0;
for (base::ProgramOptions::OptionList::const_iterator
it=po.options().begin(), end=po.options().end(); it != end; ++it) {
const base::ProgramOptions::Option* option = *it;
size_t optionWidth =
std::size_t optionWidth =
6+option->name().size()+1+
(option->doesRequireValue() ? option->getValueName().size()+1: 0);
@ -202,7 +202,7 @@ std::ostream& operator<<(std::ostream& os, const base::ProgramOptions& po)
for (base::ProgramOptions::OptionList::const_iterator
it=po.options().begin(), end=po.options().end(); it != end; ++it) {
const base::ProgramOptions::Option* option = *it;
size_t optionWidth = 6+option->name().size()+1+
std::size_t optionWidth = 6+option->name().size()+1+
(option->doesRequireValue() ? option->getValueName().size()+1: 0);
if (option->mnemonic() != 0)

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -20,14 +20,14 @@ public:
typedef typename Items::iterator iterator;
typedef typename Items::const_iterator const_iterator;
RecentItems(size_t limit) : m_limit(limit) { }
RecentItems(std::size_t limit) : m_limit(limit) { }
const_iterator begin() { return m_items.begin(); }
const_iterator end() { return m_items.end(); }
bool empty() const { return m_items.empty(); }
size_t size() const { return m_items.size(); }
size_t limit() const { return m_limit; }
std::size_t size() const { return m_items.size(); }
std::size_t limit() const { return m_limit; }
void addItem(const T& item) {
iterator it = std::find(m_items.begin(), m_items.end(), item);
@ -57,7 +57,7 @@ public:
private:
Items m_items;
size_t m_limit;
std::size_t m_limit;
};
} // namespace base

View File

@ -20,7 +20,7 @@ void replace_string(
if (replace_this.empty()) // Do nothing case
return;
size_t i = 0;
std::size_t i = 0;
while (true) {
i = subject.find(replace_this, i);
if (i == std::string::npos)
@ -29,5 +29,5 @@ void replace_string(
i += with_that.size();
}
}
} // namespace base

View File

@ -42,7 +42,7 @@ Sha1 Sha1::calculateFromFile(const std::string& fileName)
unsigned char buf[1024];
while (file.good()) {
file.read((char*)buf, 1024);
size_t len = (size_t)file.gcount();
std::size_t len = (std::size_t)file.gcount();
if (len > 0)
SHA1Input(&sha, buf, len);
}

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -38,10 +38,10 @@ void base::split_string(const std::string& string,
std::vector<std::string>& parts,
const std::string& separators)
{
size_t elements = 1 + std::count_if(string.begin(), string.end(), is_separator(&separators));
std::size_t elements = 1 + std::count_if(string.begin(), string.end(), is_separator(&separators));
parts.reserve(elements);
size_t beg = 0, end;
std::size_t beg = 0, end;
while (true) {
end = string.find_first_of(separators, beg);
if (end != std::string::npos) {

View File

@ -83,7 +83,7 @@ std::wstring from_utf8(const std::string& src)
#else
// Based on Allegro Unicode code (allegro/src/unicode.c)
static size_t insert_utf8_char(std::string* result, wchar_t chr)
static std::size_t insert_utf8_char(std::string* result, wchar_t chr)
{
int size, bits, b, i;
@ -129,7 +129,7 @@ std::string to_utf8(const std::wstring& src)
// Get required size to reserve a string so string::push_back()
// doesn't need to reallocate its data.
size_t required_size = 0;
std::size_t required_size = 0;
for (it = begin; it != end; ++it)
required_size += insert_utf8_char(NULL, *it);
if (!required_size)

40
src/base/time.cpp Normal file
View File

@ -0,0 +1,40 @@
// Aseprite Base Library
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "base/time.h"
#if _WIN32
#include <windows.h>
#else
#include <ctime>
#endif
namespace base {
Time current_time()
{
#if _WIN32
SYSTEMTIME st;
GetLocalTime(&st);
return Time(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
#else
std::time_t now = std::time(nullptr);
std::tm* t = std::localtime(&now);
return Time(
t->tm_year+1900, t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
#endif
}
} // namespace base

Some files were not shown because too many files have changed in this diff Show More