diff --git a/CHANGELOG.md b/CHANGELOG.md index 34eff35f..56cbae12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - Add ability to set the opacity of the scripting overlay. - Add ability to get/set map header properties and read tile pixel data via the API. - Add button to copy the full metatile label to the clipboard in the Tileset Editor. +- Add option to not open the most recent project on launch. +- Add color picker to palette editor for taking colors from the screen. ### Changed - If an object event is inanimate, it will always render using its first frame. @@ -25,6 +27,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - Metatiles are always rendered accurately with 3 layers, and the unused layer is not assumed to be transparent. - `object_event_graphics_info.h` can now be parsed correctly if it uses structs with attributes. - The selection is no longer reset when pasting events. The newly pasted events are selected instead. +- Palette editor ui is updated a bit to allow hex and rgb value input. ### Fixed - Fix cursor tile outline not updating at the end of a dragged selection. @@ -33,6 +36,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - Fix selected space not updating while painting in Collision view. - Fix the map music dropdown being empty when importing a map from Advance Map. - Fix object events added by pasting ignoring the map event limit. +- Fixed a bug where saving the tileset editor would reselect the main editor's first selected metatile. ## [4.5.0] - 2021-12-26 ### Added diff --git a/docsrc/index.rst b/docsrc/index.rst index 12eaa30f..8e0c641d 100644 --- a/docsrc/index.rst +++ b/docsrc/index.rst @@ -18,6 +18,7 @@ Porymap Documentation manual/editing-wild-encounters manual/creating-new-maps manual/region-map-editor + manual/tileset-editor manual/scripting-capabilities manual/project-files manual/shortcuts diff --git a/docsrc/manual/images/tileset-editor/pe-open-window.png b/docsrc/manual/images/tileset-editor/pe-open-window.png new file mode 100644 index 00000000..6e0c80cd Binary files /dev/null and b/docsrc/manual/images/tileset-editor/pe-open-window.png differ diff --git a/docsrc/manual/images/tileset-editor/tse-display-tool.png b/docsrc/manual/images/tileset-editor/tse-display-tool.png new file mode 100644 index 00000000..2faa4812 Binary files /dev/null and b/docsrc/manual/images/tileset-editor/tse-display-tool.png differ diff --git a/docsrc/manual/images/tileset-editor/tse-metatile-properties-alt.png b/docsrc/manual/images/tileset-editor/tse-metatile-properties-alt.png new file mode 100644 index 00000000..72d4f530 Binary files /dev/null and b/docsrc/manual/images/tileset-editor/tse-metatile-properties-alt.png differ diff --git a/docsrc/manual/images/tileset-editor/tse-metatile-properties.png b/docsrc/manual/images/tileset-editor/tse-metatile-properties.png new file mode 100644 index 00000000..f0a38267 Binary files /dev/null and b/docsrc/manual/images/tileset-editor/tse-metatile-properties.png differ diff --git a/docsrc/manual/images/tileset-editor/tse-open-window.png b/docsrc/manual/images/tileset-editor/tse-open-window.png new file mode 100644 index 00000000..ecc4ce59 Binary files /dev/null and b/docsrc/manual/images/tileset-editor/tse-open-window.png differ diff --git a/docsrc/manual/navigation.rst b/docsrc/manual/navigation.rst index 46b6547c..b885cca9 100644 --- a/docsrc/manual/navigation.rst +++ b/docsrc/manual/navigation.rst @@ -73,7 +73,8 @@ Wild Pokémon Tab Tileset Editor -------------- -The Tileset Editor can be opened with *File -> Tileset Editor* (``Ctrl+T``). When the Tileset Editor is opened, it is opened in the context of the currently-opened map. Every map has a primary and secondary tileset, so you will work with a combination of the two whenever you use the Tileset Editor. The left-side pane shows the primary and secondary tilesets' metatiles. The right-side panes allow you to modify the currently-selected metatile. +The Tileset Editor can be opened with *File -> Tileset Editor* (``Ctrl+T``). +Check out :ref:`The Tileset Editor ` section for more details. .. figure:: images/navigation/tileset-editor.png :alt: Tileset Editor @@ -83,11 +84,13 @@ The Tileset Editor can be opened with *File -> Tileset Editor* (``Ctrl+T``). Wh Region Map Editor ----------------- -The Region Map Editor can be opened with *File -> Region Map Editor* (``Ctrl+M``). This window will allow you to modify the look and layout of maps on the game's region map. You can also modify the city map images using the bottom two panes. Currently the Region Map Editor is only available for pokeemerald and pokeruby projects. +The Region Map Editor can be opened with *File -> Region Map Editor* (``Ctrl+M``). +This window will allow you to modify the look and layout of maps on the game's region map. +Check out :ref:`The Region Map Editor ` section for more details. .. figure:: images/navigation/region-map-editor.png :alt: Region Map Editor Region Map Editor -We covered all of the basic views and windows of Porymap above. Next, let's learn how to use Porymap's features to the fullest when editing map tiles. +We covered all of the basic views and windows of porymap above. Next, let's learn how to use Porymap's features to the fullest when editing map tiles. diff --git a/docsrc/manual/region-map-editor.rst b/docsrc/manual/region-map-editor.rst index e6629b96..fbddfce7 100644 --- a/docsrc/manual/region-map-editor.rst +++ b/docsrc/manual/region-map-editor.rst @@ -1,3 +1,5 @@ +.. _rme-ref: + ********************* The Region Map Editor ********************* diff --git a/docsrc/manual/settings-and-options.rst b/docsrc/manual/settings-and-options.rst index 5aec32fc..2c231ea2 100644 --- a/docsrc/manual/settings-and-options.rst +++ b/docsrc/manual/settings-and-options.rst @@ -17,6 +17,7 @@ determined by this file. :widths: 10, 3, 5, 5, 20 ``recent_project``, , global, yes, The project that will be opened on launch + ``reopen_on_launch``, 1, global, yes, Whether the most recent project should be opened on launch ``recent_map``, , global, yes, The map that will be opened on launch ``pretty_cursors``, 1, global, yes, Whether to use custom crosshair cursors ``map_sort_order``, group, global, yes, The order map list is sorted in diff --git a/docsrc/manual/tileset-editor.rst b/docsrc/manual/tileset-editor.rst new file mode 100644 index 00000000..df9cfb95 --- /dev/null +++ b/docsrc/manual/tileset-editor.rst @@ -0,0 +1,163 @@ +.. _tse-ref: + +********************* +The Tileset Editor +********************* + +Here, you can edit individual tilesets. +When the Tileset Editor is opened, it is opened in the context of the +currently-opened map. Every map has a primary and secondary tileset, so you +will work with a combination of the two whenever you use the Tileset Editor. +The left-side pane shows the primary and secondary tilesets' metatiles. +The right-side panes allow you to modify the currently-selected metatile. + +.. figure:: images/tileset-editor/tse-open-window.png + :align: center + :width: 75% + :alt: TSE Window + + Tileset Editor Window + + + +Metatile Properties +=================== + +.. figure:: images/tileset-editor/tse-metatile-properties.png + :align: center + :width: 30% + :alt: MP Frame + + Metatile Properties Panel + +Layer Type +---------- + +Defines the background layers the metatiles will use for drawing. +The options are: + +**Normal** --- Metatile uses middle and top bg layers + +**Covered** --- Metatile uses bottom and middle bg layers + +**Split** --- Metatile uses bottom and top bg layers + + +Metatile Behavior +----------------- + +Defines the metatile behavior associated with this metatile. This can be used +for a variety of different reasons. For example, warps, ice, and tall grass effects +are all determined by a metatile's behavior. + +This dropdown is populated with constants found in ``include/constants/metatile_behaviors.h``. + + +Encounter Type +-------------- + + *pokefirered exclusive* + +Used to determine which category of wild encounter to attempt. + + +Terrain Type +------------ + + *pokefirered exclusive* + +Used to determine certain attributes of metatiles. Can be useful in certain scenarios. +For example, to determine if the player is facing water or standing in grass. + + +Metatile Label +-------------- + + *optional* + +A name can be given to metatiles so that they may be referenced in source code. +These are defined in ``include/constants/metatile_labels.h`` and can be used in +together with the ``METATILE_ID`` macro. + +For example, the metatile pictured above can be accessed like +``METATILE_ID(General, Plain_Grass)``. + + + + +Tools Menu +========== + +The tileset editor provides users with several useful tools for making edits +easier and more convenient. + + +Import Tiles Image... +--------------------- + +Tool to automatically import a new tile image for a tileset. +The tile image is an indexed png of 8x8 pixel tiles, which are used to form +metatiles in the tileset editor. + + +Import Metatiles from Advance Map 1.92... +----------------------------------------- + +Helpful for users converting projects from binary hacks. +Metatile data exported from Advance Map 1.92 in a ``.bvd``` file can be imported +into porymap's tileset editor. +This saves a lot of time since metatiles will not have to be defined from scratch. + + +Change Number of Metatiles +-------------------------- + +The number of metatiles in both the current primary and current secondary tileset +can be adjusted within the limits. + +.. note:: + You may need to change the Makefile rules for the number of tiles allowed + for the tileset in the file ``graphics_file_rules.mk``. You can simply + remove the ``-num_tiles=`` argument altogether. + + +Other Tools +----------- + +.. figure:: images/tileset-editor/tse-display-tool.png + :align: center + :width: 60% + :alt: TSE Unused + + Displaying Unused Tiles + +There are also tools to count the number of metatile and tile usages across the +entire project, which can be useful, for example, in determining whether a +metatile can be deleted. The output of these operations is pictured above. + + +Palette Editor +============== + +The palette editor is where the ``.pal`` files are modified for each tileset. + +.. figure:: images/tileset-editor/pe-open-window.png + :align: center + :width: 75% + :alt: PE + + Palette Editor + +The current palette is indicated by the spinner at the top left. To switch +between palettes, just change the spinner value. +At the top right is a setting for the bit depth at which colors are displayed. +The colors in a palette file are displayed as 24 bit numbers, but the GBA +hardware only allows 15 bit colors, so displaying in 15 bits can be more realistic. + +Each individual color can be adjusted with either the sliders or the spinners, +in addition to the hex value box. Each color also has an eyedropper toolbutton +which allows users to pick any color from the screen and add it to the palette. + +Entire palettes can also be imported from a variety of formats, +including JASC, Adobe Color Table, Tile Layer Pro, and Advance PE. +Each imported palette must contain 16 colors. diff --git a/forms/colorpicker.ui b/forms/colorpicker.ui new file mode 100644 index 00000000..a8cafe93 --- /dev/null +++ b/forms/colorpicker.ui @@ -0,0 +1,219 @@ + + + ColorPicker + + + + 0 + 0 + 383 + 243 + + + + Color Picker + + + + + + QFrame::Box + + + QFrame::Plain + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 120 + 120 + + + + + 120 + 120 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 50 + 50 + + + + + 50 + 50 + + + + + 50 + 50 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Courier + + + + RGB (000, 000, 000) + + + + + + + + Courier + + + + #FFFFFF + + + + + + + + + + + + + + Courier + + + + press [SPACE] to capture color + + + Qt::AlignCenter + + + + + + + + diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index d9d39058..fb9130fb 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2661,6 +2661,7 @@ + @@ -2733,6 +2734,14 @@ Use Poryscript + + + true + + + Open Recent Project On Launch + + New Map... diff --git a/forms/paletteeditor.ui b/forms/paletteeditor.ui index b87b4398..35864675 100644 --- a/forms/paletteeditor.ui +++ b/forms/paletteeditor.ui @@ -6,1309 +6,38 @@ 0 0 - 817 - 739 + 907 + 886 - - Qt::ClickFocus - Palette Editor - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Palette - - - - - - - Qt::StrongFocus - - - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - + + + + - - - - Color 4 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 5 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 7 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 6 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 10 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 8 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 9 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 11 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 12 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 14 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 13 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - - - - - Color 15 - - - - - - - 32 - 32 - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal - - - - - - - - - - - - - + + 0 + + + 0 + + + 0 + + + 0 + - + Color 0 - - - - Red - - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - 31 - - - Qt::Horizontal - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - + 32 @@ -1329,24 +58,299 @@ - - - - + + + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + - + Color 1 - + - + 32 @@ -1367,84 +371,299 @@ - - - - Red + + + + QFrame::NoFrame - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - 31 - - - Qt::Horizontal - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal + + QFrame::Raised + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + - - - + + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + - + Color 2 - + - + 32 @@ -1465,84 +684,299 @@ - - - - Red + + + + QFrame::NoFrame - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal + + QFrame::Raised + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + - - - + + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + - + Color 3 - + - + 32 @@ -1563,76 +997,4110 @@ - - - - Red + + + + QFrame::NoFrame - - - - - - 31 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks - - - - - - - Green - - - - - - - Blue - - - - - - - 31 - - - Qt::Horizontal - - - - - - - 31 - - - Qt::Horizontal + + QFrame::Raised + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + - - - + + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + Color 4 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 5 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 6 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 7 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 8 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 9 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 10 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 11 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 12 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 13 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 14 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + Color 15 + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + 31 + + + 4 + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + 255 + + + 8 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + ... + + + + :/icons/pipette.ico:/icons/pipette.ico + + + + + + + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + Palette + + + + + + + Qt::StrongFocus + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Bit Depth: + + + + + + + 15 + + + + + + + 24 + + + true + + + @@ -1643,8 +5111,8 @@ 0 0 - 817 - 21 + 907 + 22 @@ -1692,6 +5160,8 @@ - + + + diff --git a/include/config.h b/include/config.h index c5c0e66b..165bab60 100644 --- a/include/config.h +++ b/include/config.h @@ -28,6 +28,7 @@ protected: virtual QMap getKeyValueMap() = 0; virtual void onNewConfigFileCreated() = 0; virtual void setUnreadKeys() = 0; + void setConfigBool(QString key, bool * field, QString value); }; class PorymapConfig: public KeyValueConfigBase @@ -38,6 +39,7 @@ public: } virtual void reset() override { this->recentProject = ""; + this->reopenOnLaunch = true; this->mapSortOrder = MapSortOrder::Group; this->prettyCursors = true; this->collisionOpacity = 50; @@ -53,6 +55,7 @@ public: this->textEditorGotoLine = ""; } void setRecentProject(QString project); + void setReopenOnLaunch(bool enabled); void setMapSortOrder(MapSortOrder order); void setPrettyCursors(bool enabled); void setMainGeometry(QByteArray, QByteArray, QByteArray, QByteArray); @@ -71,6 +74,7 @@ public: void setTextEditorOpenFolder(const QString &command); void setTextEditorGotoLine(const QString &command); QString getRecentProject(); + bool getReopenOnLaunch(); MapSortOrder getMapSortOrder(); bool getPrettyCursors(); QMap getMainGeometry(); @@ -96,6 +100,7 @@ protected: virtual void setUnreadKeys() override {}; private: QString recentProject; + bool reopenOnLaunch; QString stringFromByteArray(QByteArray); QByteArray bytesFromString(QString); MapSortOrder mapSortOrder; diff --git a/include/core/history.h b/include/core/history.h index 75883d2d..0c26780c 100644 --- a/include/core/history.h +++ b/include/core/history.h @@ -8,6 +8,13 @@ template class History { public: History() { } + + ~History() { + while (!history.isEmpty()) { + delete history.takeLast(); + } + } + T back() { if (head > 0) { return history.at(--head); diff --git a/include/mainwindow.h b/include/mainwindow.h index e330a20d..1174060b 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -250,6 +250,7 @@ private slots: void on_actionUse_Encounter_Json_triggered(bool checked); void on_actionMonitor_Project_Files_triggered(bool checked); void on_actionUse_Poryscript_triggered(bool checked); + void on_actionOpen_Recent_Project_On_Launch_triggered(bool checked); void on_actionEdit_Shortcuts_triggered(); void on_mainTabBar_tabBarClicked(int index); diff --git a/include/ui/colorpicker.h b/include/ui/colorpicker.h new file mode 100644 index 00000000..fa431341 --- /dev/null +++ b/include/ui/colorpicker.h @@ -0,0 +1,33 @@ +#ifndef COLORPICKER_H +#define COLORPICKER_H + +#include +#include + +namespace Ui { +class ColorPicker; +} + +class ColorPicker : public QDialog +{ + Q_OBJECT + +public: + explicit ColorPicker(QWidget *parent = nullptr); + ~ColorPicker(); + + QColor getColor() { return this->color; } + +private: + Ui::ColorPicker *ui; + QGraphicsScene *scene = nullptr; + QTimer *timer = nullptr; + + QPoint lastCursorPos = QPoint(0, 0); + + QColor color = Qt::white; + + void hover(int mouseX, int mouseY); +}; + +#endif // COLORPICKER_H diff --git a/include/ui/paletteeditor.h b/include/ui/paletteeditor.h index 2dbd6d29..9b846d60 100644 --- a/include/ui/paletteeditor.h +++ b/include/ui/paletteeditor.h @@ -2,6 +2,7 @@ #define PALETTEEDITOR_H #include +#include #include #include #include @@ -31,23 +32,43 @@ public: private: Ui::PaletteEditor *ui; Project *project = nullptr; + QList> sliders; + QList> spinners; QList frames; - QList rgbLabels; + QList pickButtons; + QList hexEdits; + Tileset *primaryTileset; Tileset *secondaryTileset; + QList> palettesHistory; - void disableSliderSignals(); - void enableSliderSignals(); - void initColorSliders(); - void refreshColorSliders(); - void refreshColors(); - void refreshColor(int); - void setColor(int); + + void refreshColorUis(); + void updateColorUi(int index, QRgb color); void commitEditHistory(int paletteid); void restoreWindowState(); + void setSignalsEnabled(bool enabled); void setColorsFromHistory(PaletteHistoryItem*, int); void closeEvent(QCloseEvent*); + void pickColor(int i); + + void setRgb(int index, QRgb rgb); + void setRgbFromSliders(int colorIndex); + void setRgbFromHexEdit(int colorIndex); + void setRgbFromSpinners(int colorIndex); + + void setBitDepth(int bits); + int bitDepth = 24; + + class HexCodeValidator : public QValidator { + virtual QValidator::State validate(QString &input, int &) const override { + input = input.toUpper(); + return QValidator::Acceptable; + } + }; + + HexCodeValidator *hexValidator = nullptr; signals: void closed(); diff --git a/porymap.pro b/porymap.pro index 1b78ebcc..21417d3e 100644 --- a/porymap.pro +++ b/porymap.pro @@ -82,6 +82,7 @@ SOURCES += src/core/block.cpp \ src/ui/multikeyedit.cpp \ src/ui/preferenceeditor.cpp \ src/ui/regionmappropertiesdialog.cpp \ + src/ui/colorpicker.cpp \ src/config.cpp \ src/editor.cpp \ src/main.cpp \ @@ -164,6 +165,7 @@ HEADERS += include/core/block.h \ include/ui/multikeyedit.h \ include/ui/preferenceeditor.h \ include/ui/regionmappropertiesdialog.h \ + include/ui/colorpicker.h \ include/config.h \ include/editor.h \ include/mainwindow.h \ @@ -183,7 +185,8 @@ FORMS += forms/mainwindow.ui \ forms/mapimageexporter.ui \ forms/shortcutseditor.ui \ forms/preferenceeditor.ui \ - forms/regionmappropertiesdialog.ui + forms/regionmappropertiesdialog.ui \ + forms/colorpicker.ui RESOURCES += \ resources/images.qrc \ diff --git a/src/config.cpp b/src/config.cpp index 32cf00e7..0ed1e081 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -79,6 +79,14 @@ void KeyValueConfigBase::save() { } } +void KeyValueConfigBase::setConfigBool(QString key, bool * field, QString value) { + bool ok; + *field = value.toInt(&ok); + if (!ok) { + logWarn(QString("Invalid config value for %1: '%2'. Must be 0 or 1.").arg(key).arg(value)); + } +} + const QMap mapSortOrderMap = { {MapSortOrder::Group, "group"}, {MapSortOrder::Layout, "layout"}, @@ -108,12 +116,10 @@ QString PorymapConfig::getConfigFilepath() { void PorymapConfig::parseConfigKeyValue(QString key, QString value) { if (key == "recent_project") { this->recentProject = value; + } else if (key == "reopen_on_launch") { + setConfigBool(key, &this->reopenOnLaunch, value); } else if (key == "pretty_cursors") { - bool ok; - this->prettyCursors = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for pretty_cursors: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->prettyCursors, value); } else if (key == "map_sort_order") { QString sortOrder = value.toLower(); if (mapSortOrderReverseMap.contains(sortOrder)) { @@ -157,35 +163,15 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) { this->metatilesZoom = 30; } } else if (key == "show_player_view") { - bool ok; - this->showPlayerView = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for show_player_view: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->showPlayerView, value); } else if (key == "show_cursor_tile") { - bool ok; - this->showCursorTile = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for show_cursor_tile: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->showCursorTile, value); } else if (key == "show_border") { - bool ok; - this->showBorder = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for show_border: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->showBorder, value); } else if (key == "show_grid") { - bool ok; - this->showGrid = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for show_grid: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->showGrid, value); } else if (key == "monitor_files") { - bool ok; - this->monitorFiles = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for monitor_files: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->monitorFiles, value); } else if (key == "region_map_dimensions") { bool ok1, ok2; QStringList dims = value.split("x"); @@ -211,6 +197,7 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) { QMap PorymapConfig::getKeyValueMap() { QMap map; map.insert("recent_project", this->recentProject); + map.insert("reopen_on_launch", this->reopenOnLaunch ? "1" : "0"); map.insert("pretty_cursors", this->prettyCursors ? "1" : "0"); map.insert("map_sort_order", mapSortOrderMap.value(this->mapSortOrder)); map.insert("main_window_geometry", stringFromByteArray(this->mainWindowGeometry)); @@ -260,6 +247,11 @@ void PorymapConfig::setRecentProject(QString project) { this->save(); } +void PorymapConfig::setReopenOnLaunch(bool enabled) { + this->reopenOnLaunch = enabled; + this->save(); +} + void PorymapConfig::setMapSortOrder(MapSortOrder order) { this->mapSortOrder = order; this->save(); @@ -354,6 +346,10 @@ QString PorymapConfig::getRecentProject() { return this->recentProject; } +bool PorymapConfig::getReopenOnLaunch() { + return this->reopenOnLaunch; +} + MapSortOrder PorymapConfig::getMapSortOrder() { return this->mapSortOrder; } @@ -475,77 +471,29 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { } else if (key == "recent_map") { this->recentMap = value; } else if (key == "use_encounter_json") { - bool ok; - this->useEncounterJson = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for use_encounter_json: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->useEncounterJson, value); } else if (key == "use_poryscript") { - bool ok; - this->usePoryScript = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for use_poryscript: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->usePoryScript, value); } else if (key == "use_custom_border_size") { - bool ok; - this->useCustomBorderSize = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for use_custom_border_size: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->useCustomBorderSize, value); } else if (key == "enable_event_weather_trigger") { - bool ok; - this->enableEventWeatherTrigger = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_event_weather_trigger: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableEventWeatherTrigger, value); } else if (key == "enable_event_secret_base") { - bool ok; - this->enableEventSecretBase = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_event_secret_base: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableEventSecretBase, value); } else if (key == "enable_hidden_item_quantity") { - bool ok; - this->enableHiddenItemQuantity = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_hidden_item_quantity: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableHiddenItemQuantity, value); } else if (key == "enable_hidden_item_requires_itemfinder") { - bool ok; - this->enableHiddenItemRequiresItemfinder = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_hidden_item_requires_itemfinder: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableHiddenItemRequiresItemfinder, value); } else if (key == "enable_heal_location_respawn_data") { - bool ok; - this->enableHealLocationRespawnData = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_heal_location_respawn_data: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableHealLocationRespawnData, value); } else if (key == "enable_event_clone_object") { - bool ok; - this->enableEventCloneObject = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_event_clone_object: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableEventCloneObject, value); } else if (key == "enable_floor_number") { - bool ok; - this->enableFloorNumber = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_floor_number: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableFloorNumber, value); } else if (key == "create_map_text_file") { - bool ok; - this->createMapTextFile = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for create_map_text_file: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->createMapTextFile, value); } else if (key == "enable_triple_layer_metatiles") { - bool ok; - this->enableTripleLayerMetatiles = value.toInt(&ok); - if (!ok) { - logWarn(QString("Invalid config value for enable_triple_layer_metatiles: '%1'. Must be 0 or 1.").arg(value)); - } + setConfigBool(key, &this->enableTripleLayerMetatiles, value); } else if (key == "custom_scripts") { this->customScripts.clear(); QList paths = value.split(","); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3aea04ec..79580bfd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -461,6 +461,7 @@ void MainWindow::loadUserSettings() { ui->horizontalSlider_MetatileZoom->setValue(porymapConfig.getMetatilesZoom()); ui->horizontalSlider_MetatileZoom->blockSignals(false); ui->actionMonitor_Project_Files->setChecked(porymapConfig.getMonitorFiles()); + ui->actionOpen_Recent_Project_On_Launch->setChecked(porymapConfig.getReopenOnLaunch()); setTheme(porymapConfig.getTheme()); } @@ -485,6 +486,9 @@ void MainWindow::setTheme(QString theme) { } bool MainWindow::openRecentProject() { + if (!porymapConfig.getReopenOnLaunch()) + return false; + QString default_dir = porymapConfig.getRecentProject(); if (!default_dir.isNull() && default_dir.length() > 0) { logInfo(QString("Opening recent project: '%1'").arg(default_dir)); @@ -1774,6 +1778,11 @@ void MainWindow::on_actionUse_Poryscript_triggered(bool checked) projectConfig.setUsePoryScript(checked); } +void MainWindow::on_actionOpen_Recent_Project_On_Launch_triggered(bool checked) +{ + porymapConfig.setReopenOnLaunch(checked); +} + void MainWindow::on_actionEdit_Shortcuts_triggered() { if (!shortcutsEditor) diff --git a/src/ui/colorpicker.cpp b/src/ui/colorpicker.cpp new file mode 100644 index 00000000..ee2baff3 --- /dev/null +++ b/src/ui/colorpicker.cpp @@ -0,0 +1,81 @@ +#include "colorpicker.h" +#include "ui_colorpicker.h" + +#include + +const int zoom_box_dimensions = 15; + +ColorPicker::ColorPicker(QWidget *parent) : + QDialog(parent), + ui(new Ui::ColorPicker) +{ + ui->setupUi(this); + + this->scene = new QGraphicsScene; + + // listen for spacebar press to take color + QShortcut *takeColor = new QShortcut(Qt::Key_Space, this); + QObject::connect(takeColor, &QShortcut::activated, [this](){ + timer->stop(); + this->accept(); + }); + + // need to set up a timer because there is no good way to get global mouse movement + // outside of the application in a cross-platform way + timer = new QTimer(this); + connect(timer, &QTimer::timeout, [this]() { + QPoint cursorPos = QCursor::pos(); + if (lastCursorPos != cursorPos) { + lastCursorPos = cursorPos; + this->hover(cursorPos.x(), cursorPos.y()); + } + }); + timer->start(10); +} + +ColorPicker::~ColorPicker() +{ + delete scene; + delete timer; + delete ui; +} + +void ColorPicker::hover(int mouseX, int mouseY) { + QScreen *screen = QGuiApplication::primaryScreen(); + if (const QWindow *window = windowHandle()) + screen = window->screen(); + if (!screen) + return; + + // 15 X 15 box with 8x magnification = 120px square) + QRect zoomRect(mouseX - zoom_box_dimensions / 2, mouseY - zoom_box_dimensions / 2, zoom_box_dimensions, zoom_box_dimensions); + QPixmap grab = screen->grabWindow(0, mouseX - zoom_box_dimensions / 2, mouseY - zoom_box_dimensions / 2, zoom_box_dimensions, zoom_box_dimensions); + int pixelRatio = grab.devicePixelRatio(); + + // TODO: investigate for high dpi displays why text is too high res + grab.setDevicePixelRatio(1); + QPixmap magnified = grab.scaled(zoom_box_dimensions * 8, zoom_box_dimensions * 8, Qt::KeepAspectRatio); + + QPainter painter(&magnified); + painter.setRenderHint(QPainter::Antialiasing, false); + QRectF rect(zoom_box_dimensions / 2 * 8 - 1, zoom_box_dimensions / 2 * 8 - 1, zoom_box_dimensions / 2 + 2, zoom_box_dimensions / 2 + 2); + painter.drawRect(rect); + painter.end(); + + // TODO: bounds checking? + + this->color = grab.toImage().pixelColor(zoom_box_dimensions / 2 * pixelRatio, zoom_box_dimensions / 2 * pixelRatio); + int r = this->color.red(); + int g = this->color.green(); + int b = this->color.blue(); + + // update the displayed color value + QString rgb = QString("rgb(%1, %2, %3)").arg(r).arg(g).arg(b); + QString stylesheet = QString("background-color: %1;").arg(rgb); + this->ui->frame_centralColor->setStyleSheet(stylesheet); + + this->ui->label_RGB->setText(rgb); + this->ui->label_HEX->setText(color.name()); + + this->ui->viewport->setPixmap(magnified); +} diff --git a/src/ui/paletteeditor.cpp b/src/ui/paletteeditor.cpp index d03615fa..3907a591 100644 --- a/src/ui/paletteeditor.cpp +++ b/src/ui/paletteeditor.cpp @@ -1,11 +1,20 @@ #include "paletteeditor.h" #include "ui_paletteeditor.h" +#include "colorpicker.h" #include "paletteutil.h" #include "config.h" #include "log.h" + +#include #include #include +static inline int rgb5(int rgb) { return round(static_cast(rgb * 31) / 255.0); } +static inline int rgb8(int rgb) { return round(rgb * 255. / 31.); } +static inline int gbaRed(int rgb) { return rgb & 0x1f; } +static inline int gbaGreen(int rgb) { return (rgb >> 5) & 0x1f; } +static inline int gbaBlue(int rgb) { return (rgb >> 10) & 0x1f; } + PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId, QWidget *parent) : QMainWindow(parent), ui(new Ui::PaletteEditor) @@ -16,101 +25,74 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset this->ui->setupUi(this); this->ui->spinBox_PaletteId->setMinimum(0); this->ui->spinBox_PaletteId->setMaximum(Project::getNumPalettesTotal() - 1); + this->sliders.clear(); for (int i = 0; i < 16; i++) { - this->sliders.append(QList()); + QList rgbSliders; + rgbSliders.append(this->ui->container->findChild("slider_red_" + QString::number(i))); + rgbSliders.append(this->ui->container->findChild("slider_green_" + QString::number(i))); + rgbSliders.append(this->ui->container->findChild("slider_blue_" + QString::number(i))); + this->sliders.append(rgbSliders); + + connect(this->sliders[i][0], &QSlider::valueChanged, [=](int) { setRgbFromSliders(i); }); + connect(this->sliders[i][1], &QSlider::valueChanged, [=](int) { setRgbFromSliders(i); }); + connect(this->sliders[i][2], &QSlider::valueChanged, [=](int) { setRgbFromSliders(i); }); + } + + this->spinners.clear(); + for (int i = 0; i < 16; i++) { + QList rgbSpinners; + rgbSpinners.append(this->ui->container->findChild("spin_red_" + QString::number(i))); + rgbSpinners.append(this->ui->container->findChild("spin_green_" + QString::number(i))); + rgbSpinners.append(this->ui->container->findChild("spin_blue_" + QString::number(i))); + this->spinners.append(rgbSpinners); + + connect(this->spinners[i][0], QOverload::of(&QSpinBox::valueChanged), [=](int) { setRgbFromSpinners(i); }); + connect(this->spinners[i][1], QOverload::of(&QSpinBox::valueChanged), [=](int) { setRgbFromSpinners(i); }); + connect(this->spinners[i][2], QOverload::of(&QSpinBox::valueChanged), [=](int) { setRgbFromSpinners(i); }); } - this->sliders[0].append(this->ui->horizontalSlider); - this->sliders[0].append(this->ui->horizontalSlider_2); - this->sliders[0].append(this->ui->horizontalSlider_3); - this->sliders[1].append(this->ui->horizontalSlider_4); - this->sliders[1].append(this->ui->horizontalSlider_5); - this->sliders[1].append(this->ui->horizontalSlider_6); - this->sliders[2].append(this->ui->horizontalSlider_7); - this->sliders[2].append(this->ui->horizontalSlider_8); - this->sliders[2].append(this->ui->horizontalSlider_9); - this->sliders[3].append(this->ui->horizontalSlider_10); - this->sliders[3].append(this->ui->horizontalSlider_11); - this->sliders[3].append(this->ui->horizontalSlider_12); - this->sliders[4].append(this->ui->horizontalSlider_13); - this->sliders[4].append(this->ui->horizontalSlider_14); - this->sliders[4].append(this->ui->horizontalSlider_15); - this->sliders[5].append(this->ui->horizontalSlider_16); - this->sliders[5].append(this->ui->horizontalSlider_17); - this->sliders[5].append(this->ui->horizontalSlider_18); - this->sliders[6].append(this->ui->horizontalSlider_19); - this->sliders[6].append(this->ui->horizontalSlider_20); - this->sliders[6].append(this->ui->horizontalSlider_21); - this->sliders[7].append(this->ui->horizontalSlider_22); - this->sliders[7].append(this->ui->horizontalSlider_23); - this->sliders[7].append(this->ui->horizontalSlider_24); - this->sliders[8].append(this->ui->horizontalSlider_25); - this->sliders[8].append(this->ui->horizontalSlider_26); - this->sliders[8].append(this->ui->horizontalSlider_27); - this->sliders[9].append(this->ui->horizontalSlider_28); - this->sliders[9].append(this->ui->horizontalSlider_29); - this->sliders[9].append(this->ui->horizontalSlider_30); - this->sliders[10].append(this->ui->horizontalSlider_31); - this->sliders[10].append(this->ui->horizontalSlider_32); - this->sliders[10].append(this->ui->horizontalSlider_33); - this->sliders[11].append(this->ui->horizontalSlider_34); - this->sliders[11].append(this->ui->horizontalSlider_35); - this->sliders[11].append(this->ui->horizontalSlider_36); - this->sliders[12].append(this->ui->horizontalSlider_37); - this->sliders[12].append(this->ui->horizontalSlider_38); - this->sliders[12].append(this->ui->horizontalSlider_39); - this->sliders[13].append(this->ui->horizontalSlider_40); - this->sliders[13].append(this->ui->horizontalSlider_41); - this->sliders[13].append(this->ui->horizontalSlider_42); - this->sliders[14].append(this->ui->horizontalSlider_43); - this->sliders[14].append(this->ui->horizontalSlider_44); - this->sliders[14].append(this->ui->horizontalSlider_45); - this->sliders[15].append(this->ui->horizontalSlider_46); - this->sliders[15].append(this->ui->horizontalSlider_47); - this->sliders[15].append(this->ui->horizontalSlider_48); this->frames.clear(); - this->frames.append(this->ui->frame); - this->frames.append(this->ui->frame_2); - this->frames.append(this->ui->frame_3); - this->frames.append(this->ui->frame_4); - this->frames.append(this->ui->frame_5); - this->frames.append(this->ui->frame_6); - this->frames.append(this->ui->frame_7); - this->frames.append(this->ui->frame_8); - this->frames.append(this->ui->frame_9); - this->frames.append(this->ui->frame_10); - this->frames.append(this->ui->frame_11); - this->frames.append(this->ui->frame_12); - this->frames.append(this->ui->frame_13); - this->frames.append(this->ui->frame_14); - this->frames.append(this->ui->frame_15); - this->frames.append(this->ui->frame_16); + for (int i = 0; i < 16; i++) { + this->frames.append(this->ui->container->findChild("colorFrame_" + QString::number(i))); + this->frames[i]->setFrameStyle(QFrame::NoFrame); + } - this->rgbLabels.clear(); - this->rgbLabels.append(this->ui->label_rgb0); - this->rgbLabels.append(this->ui->label_rgb1); - this->rgbLabels.append(this->ui->label_rgb2); - this->rgbLabels.append(this->ui->label_rgb3); - this->rgbLabels.append(this->ui->label_rgb4); - this->rgbLabels.append(this->ui->label_rgb5); - this->rgbLabels.append(this->ui->label_rgb6); - this->rgbLabels.append(this->ui->label_rgb7); - this->rgbLabels.append(this->ui->label_rgb8); - this->rgbLabels.append(this->ui->label_rgb9); - this->rgbLabels.append(this->ui->label_rgb10); - this->rgbLabels.append(this->ui->label_rgb11); - this->rgbLabels.append(this->ui->label_rgb12); - this->rgbLabels.append(this->ui->label_rgb13); - this->rgbLabels.append(this->ui->label_rgb14); - this->rgbLabels.append(this->ui->label_rgb15); + this->pickButtons.clear(); + for (int i = 0; i < 16; i++) { + this->pickButtons.append(this->ui->container->findChild("pick_" + QString::number(i))); + } + + this->hexValidator = new HexCodeValidator; + this->hexEdits.clear(); + for (int i = 0; i < 16; i++) { + this->hexEdits.append(this->ui->container->findChild("hex_" + QString::number(i))); + this->hexEdits[i]->setValidator(hexValidator); + } + + // Connect to function that will update color when hex edit is changed + for (int i = 0; i < this->hexEdits.length(); i++) { + connect(this->hexEdits[i], &QLineEdit::textEdited, [this, i](QString text){ + if ((this->bitDepth == 24 && text.length() == 6) || (this->bitDepth == 15 && text.length() == 4)) setRgbFromHexEdit(i); + }); + } // Setup edit-undo history for each of the palettes. for (int i = 0; i < Project::getNumPalettesTotal(); i++) { this->palettesHistory.append(History()); } - this->initColorSliders(); + // Connect the color picker's selection to the correct color index + for (int i = 0; i < 16; i++) { + connect(this->pickButtons[i], &QToolButton::clicked, [this, i](){ this->pickColor(i); }); + } + + setBitDepth(24); + + // Connect bit depth buttons + connect(this->ui->bit_depth_15, &QRadioButton::toggled, [this](bool checked){ if (checked) this->setBitDepth(15); }); + connect(this->ui->bit_depth_24, &QRadioButton::toggled, [this](bool checked){ if (checked) this->setBitDepth(24); }); + this->setPaletteId(paletteId); this->commitEditHistory(this->ui->spinBox_PaletteId->value()); this->restoreWindowState(); @@ -119,34 +101,194 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset PaletteEditor::~PaletteEditor() { delete ui; + delete this->hexValidator; } -void PaletteEditor::disableSliderSignals() { +void PaletteEditor::updateColorUi(int colorIndex, QRgb rgb) { + setSignalsEnabled(false); + + int red = qRed(rgb); + int green = qGreen(rgb); + int blue = qBlue(rgb); + + if (this->bitDepth == 15) { + // sliders + this->sliders[colorIndex][0]->setValue(rgb5(red)); + this->sliders[colorIndex][1]->setValue(rgb5(green)); + this->sliders[colorIndex][2]->setValue(rgb5(blue)); + + // hex + int hex15 = (rgb5(blue) << 10) | (rgb5(green) << 5) | rgb5(red); + QString hexcode = QString("%1").arg(hex15, 4, 16, QLatin1Char('0')).toUpper(); + this->hexEdits[colorIndex]->setText(hexcode); + + // spinners + this->spinners[colorIndex][0]->setValue(rgb5(red)); + this->spinners[colorIndex][1]->setValue(rgb5(green)); + this->spinners[colorIndex][2]->setValue(rgb5(blue)); + } else { + // sliders + this->sliders[colorIndex][0]->setValue(red); + this->sliders[colorIndex][1]->setValue(green); + this->sliders[colorIndex][2]->setValue(blue); + + // hex + QColor color(red, green, blue); + QString hexcode = color.name().remove(0, 1).toUpper(); + this->hexEdits[colorIndex]->setText(hexcode); + + // spinners + this->spinners[colorIndex][0]->setValue(red); + this->spinners[colorIndex][1]->setValue(green); + this->spinners[colorIndex][2]->setValue(blue); + } + + // frame + QString stylesheet = QString("background-color: rgb(%1, %2, %3);").arg(red).arg(green).arg(blue); + this->frames[colorIndex]->setStyleSheet(stylesheet); + + setSignalsEnabled(true); +} + +void PaletteEditor::setSignalsEnabled(bool enabled) { + // spinners, sliders, hexbox for (int i = 0; i < this->sliders.length(); i++) { - this->sliders.at(i).at(0)->blockSignals(true); - this->sliders.at(i).at(1)->blockSignals(true); - this->sliders.at(i).at(2)->blockSignals(true); + this->sliders.at(i).at(0)->blockSignals(!enabled); + this->sliders.at(i).at(1)->blockSignals(!enabled); + this->sliders.at(i).at(2)->blockSignals(!enabled); + } + + for (int i = 0; i < this->spinners.length(); i++) { + this->spinners.at(i).at(0)->blockSignals(!enabled); + this->spinners.at(i).at(1)->blockSignals(!enabled); + this->spinners.at(i).at(2)->blockSignals(!enabled); + } + + for (int i = 0; i < this->hexEdits.length(); i++) { + this->hexEdits.at(i)->blockSignals(!enabled); } } -void PaletteEditor::enableSliderSignals() { - for (int i = 0; i < this->sliders.length(); i++) { - this->sliders.at(i).at(0)->blockSignals(false); - this->sliders.at(i).at(1)->blockSignals(false); - this->sliders.at(i).at(2)->blockSignals(false); +void PaletteEditor::setBitDepth(int bits) { + setSignalsEnabled(false); + switch (bits) { + case 15: + for (int i = 0; i < 16; i++) { + // sliders ranged [0, 31] with 1 single step and 4 page step + this->sliders[i][0]->setSingleStep(1); + this->sliders[i][1]->setSingleStep(1); + this->sliders[i][2]->setSingleStep(1); + this->sliders[i][0]->setPageStep(4); + this->sliders[i][1]->setPageStep(4); + this->sliders[i][2]->setPageStep(4); + this->sliders[i][0]->setMaximum(31); + this->sliders[i][1]->setMaximum(31); + this->sliders[i][2]->setMaximum(31); + + // spinners limited [0, 31] with 1 step + this->spinners[i][0]->setSingleStep(1); + this->spinners[i][1]->setSingleStep(1); + this->spinners[i][2]->setSingleStep(1); + this->spinners[i][0]->setMaximum(31); + this->spinners[i][1]->setMaximum(31); + this->spinners[i][2]->setMaximum(31); + + // hex box now 4 digits + this->hexEdits[i]->setInputMask("HHHH"); + this->hexEdits[i]->setMaxLength(4); + } + break; + case 24: + default: + for (int i = 0; i < 16; i++) { + // sliders ranged [0, 31] with 1 single step and 4 page step + this->sliders[i][0]->setSingleStep(8); + this->sliders[i][1]->setSingleStep(8); + this->sliders[i][2]->setSingleStep(8); + this->sliders[i][0]->setPageStep(24); + this->sliders[i][1]->setPageStep(24); + this->sliders[i][2]->setPageStep(24); + this->sliders[i][0]->setMaximum(255); + this->sliders[i][1]->setMaximum(255); + this->sliders[i][2]->setMaximum(255); + + // spinners limited [0, 31] with 1 step + this->spinners[i][0]->setSingleStep(8); + this->spinners[i][1]->setSingleStep(8); + this->spinners[i][2]->setSingleStep(8); + this->spinners[i][0]->setMaximum(255); + this->spinners[i][1]->setMaximum(255); + this->spinners[i][2]->setMaximum(255); + + // hex box now 4 digits + this->hexEdits[i]->setInputMask("HHHHHH"); + this->hexEdits[i]->setMaxLength(6); + } + break; + } + this->bitDepth = bits; + refreshColorUis(); + setSignalsEnabled(true); +} + +void PaletteEditor::setRgb(int colorIndex, QRgb rgb) { + int paletteNum = this->ui->spinBox_PaletteId->value(); + + Tileset *tileset = paletteNum < Project::getNumPalettesPrimary() + ? this->primaryTileset + : this->secondaryTileset; + tileset->palettes[paletteNum][colorIndex] = rgb; + tileset->palettePreviews[paletteNum][colorIndex] = rgb; + + this->updateColorUi(colorIndex, rgb); + + this->commitEditHistory(paletteNum); + emit this->changedPaletteColor(); +} + +void PaletteEditor::setRgbFromSliders(int colorIndex) { + if (this->bitDepth == 15) { + setRgb(colorIndex, qRgb(rgb8(this->sliders[colorIndex][0]->value()), + rgb8(this->sliders[colorIndex][1]->value()), + rgb8(this->sliders[colorIndex][2]->value()))); + } else { + setRgb(colorIndex, qRgb(this->sliders[colorIndex][0]->value(), + this->sliders[colorIndex][1]->value(), + this->sliders[colorIndex][2]->value())); } } -void PaletteEditor::initColorSliders() { - for (int i = 0; i < 16; i++) { - connect(this->sliders[i][0], &QSlider::valueChanged, [=](int) { this->setColor(i); }); - connect(this->sliders[i][1], &QSlider::valueChanged, [=](int) { this->setColor(i); }); - connect(this->sliders[i][2], &QSlider::valueChanged, [=](int) { this->setColor(i); }); +void PaletteEditor::setRgbFromHexEdit(int colorIndex) { + QString text = this->hexEdits[colorIndex]->text(); + bool ok = false; + if (this->bitDepth == 15) { + int rgb15 = text.toInt(&ok, 16); + int rc = gbaRed(rgb15); + int gc = gbaGreen(rgb15); + int bc = gbaBlue(rgb15); + QRgb rgb = qRgb(rc, gc, bc); + if (!ok) rgb = 0xFFFFFFFF; + setRgb(colorIndex, rgb); + } else { + QRgb rgb = text.toInt(&ok, 16); + if (!ok) rgb = 0xFFFFFFFF; + setRgb(colorIndex, rgb); } } -void PaletteEditor::refreshColorSliders() { - disableSliderSignals(); +void PaletteEditor::setRgbFromSpinners(int colorIndex) { + if (this->bitDepth == 15) { + setRgb(colorIndex, qRgb(rgb8(this->spinners[colorIndex][0]->value()), + rgb8(this->spinners[colorIndex][1]->value()), + rgb8(this->spinners[colorIndex][2]->value()))); + } else { + setRgb(colorIndex, qRgb(this->spinners[colorIndex][0]->value(), + this->spinners[colorIndex][1]->value(), + this->spinners[colorIndex][2]->value())); + } +} + +void PaletteEditor::refreshColorUis() { int paletteNum = this->ui->spinBox_PaletteId->value(); for (int i = 0; i < 16; i++) { QRgb color; @@ -156,64 +298,34 @@ void PaletteEditor::refreshColorSliders() { color = this->secondaryTileset->palettes.at(paletteNum).at(i); } - this->sliders[i][0]->setValue(qRed(color) / 8); - this->sliders[i][1]->setValue(qGreen(color) / 8); - this->sliders[i][2]->setValue(qBlue(color) / 8); + this->updateColorUi(i, color); } - enableSliderSignals(); -} - -void PaletteEditor::refreshColors() { - for (int i = 0; i < 16; i++) { - this->refreshColor(i); - } -} - -void PaletteEditor::refreshColor(int colorIndex) { - int red = this->sliders[colorIndex][0]->value() * 8; - int green = this->sliders[colorIndex][1]->value() * 8; - int blue = this->sliders[colorIndex][2]->value() * 8; - QString stylesheet = QString("background-color: rgb(%1, %2, %3);") - .arg(red) - .arg(green) - .arg(blue); - this->frames[colorIndex]->setStyleSheet(stylesheet); - this->rgbLabels[colorIndex]->setText(QString("RGB(%1, %2, %3)").arg(red).arg(green).arg(blue)); } void PaletteEditor::setPaletteId(int paletteId) { this->ui->spinBox_PaletteId->blockSignals(true); this->ui->spinBox_PaletteId->setValue(paletteId); - this->refreshColorSliders(); - this->refreshColors(); + this->refreshColorUis(); this->ui->spinBox_PaletteId->blockSignals(false); } void PaletteEditor::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) { this->primaryTileset = primaryTileset; this->secondaryTileset = secondaryTileset; - this->refreshColorSliders(); - this->refreshColors(); + this->refreshColorUis(); } -void PaletteEditor::setColor(int colorIndex) { - int paletteNum = this->ui->spinBox_PaletteId->value(); - int red = this->sliders[colorIndex][0]->value() * 8; - int green = this->sliders[colorIndex][1]->value() * 8; - int blue = this->sliders[colorIndex][2]->value() * 8; - Tileset *tileset = paletteNum < Project::getNumPalettesPrimary() - ? this->primaryTileset - : this->secondaryTileset; - tileset->palettes[paletteNum][colorIndex] = qRgb(red, green, blue); - tileset->palettePreviews[paletteNum][colorIndex] = qRgb(red, green, blue); - this->refreshColor(colorIndex); - this->commitEditHistory(paletteNum); - emit this->changedPaletteColor(); +void PaletteEditor::pickColor(int index) { + ColorPicker picker(this); + if (picker.exec() == QDialog::Accepted) { + QColor c = picker.getColor(); + this->setRgb(index, c.rgb()); + } + return; } void PaletteEditor::on_spinBox_PaletteId_valueChanged(int paletteId) { - this->refreshColorSliders(); - this->refreshColors(); + this->refreshColorUis(); if (!this->palettesHistory[paletteId].current()) { this->commitEditHistory(paletteId); } @@ -223,7 +335,7 @@ void PaletteEditor::on_spinBox_PaletteId_valueChanged(int paletteId) { void PaletteEditor::commitEditHistory(int paletteId) { QList colors; for (int i = 0; i < 16; i++) { - colors.append(qRgb(this->sliders[i][0]->value() * 8, this->sliders[i][1]->value() * 8, this->sliders[i][2]->value() * 8)); + colors.append(qRgb(this->spinners[i][0]->value(), this->spinners[i][1]->value(), this->spinners[i][2]->value())); } PaletteHistoryItem *commit = new PaletteHistoryItem(colors); this->palettesHistory[paletteId].push(commit); @@ -263,8 +375,7 @@ void PaletteEditor::setColorsFromHistory(PaletteHistoryItem *history, int palett } } - this->refreshColorSliders(); - this->refreshColors(); + this->refreshColorUis(); emit this->changedPaletteColor(); } @@ -314,8 +425,7 @@ void PaletteEditor::on_actionImport_Palette_triggered() } } - this->refreshColorSliders(); - this->refreshColors(); + this->refreshColorUis(); this->commitEditHistory(paletteId); emit this->changedPaletteColor(); } diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index ad3dd38b..40e57ec3 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -556,10 +556,15 @@ void TilesetEditor::on_comboBox_terrainType_activated(int terrainType) void TilesetEditor::on_actionSave_Tileset_triggered() { + // need this temporary metatile ID to reset selection after saving + // when the tilesetsSaved signal is sent, it will be reset to the current map metatile + uint16_t reselectMetatileID = this->metatileSelector->getSelectedMetatileId(); + saveMetatileLabel(); this->project->saveTilesets(this->primaryTileset, this->secondaryTileset); emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name); + this->metatileSelector->select(reselectMetatileID); if (this->paletteEditor) { this->paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset); }